NPC Controlled Entities with more than 1 weapon and/or weapon switching logic?

Place to get help with not working mods / modding interface.
Post Reply
swizzlewizzle
Burner Inserter
Burner Inserter
Posts: 10
Joined: Thu May 14, 2020 7:58 am
Contact:

NPC Controlled Entities with more than 1 weapon and/or weapon switching logic?

Post by swizzlewizzle »

Is it possible?

From everything I have seen in the vanilla files and mods, enemies always have only a single set of attack parameters (ie. their weapon). However, for what i'm doing, I need entities to have access to more than one weapon, and ideally, to be able to do some basic proximity checks to see what they should use. I'm working on a roguelike so having every monster using only a single spell/attack would be pretty boring. ;)

(if some basic AI is impossible, then at least cycling randomly through their weapons/attack parameters somehow?)

Hope someone here knows how this might be done. :)

Pi-C
Smart Inserter
Smart Inserter
Posts: 1645
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: NPC Controlled Entities with more than 1 weapon and/or weapon switching logic?

Post by Pi-C »

swizzlewizzle wrote:
Thu May 14, 2020 8:02 am
(if some basic AI is impossible, then at least cycling randomly through their weapons/attack parameters somehow?)
I've never dealt with units yet, but I suppose it may be possible to allow for different weapons in the prototype definition and switch weapons in the script.

In Autodrive, you can install an Enemy sensor. If a vehicle with such a sensor has weapons and there are enemies in range, it will automatically target one. If the vehicle has several weapons, it will switch to the next one if the current runs out of ammo. This is how we do it:

Code: Select all

  local enemy = nil
  local gun = nil
  local driver = car.get_driver()
  local passenger = car.get_passenger()
  local trunk = car.get_inventory(defines.inventory.car_trunk)
  local ftank = car.get_fuel_inventory()
  local clip = car.get_inventory(defines.inventory.car_ammo)
  if car.prototype.guns then
    -- There may be several weapons (tanks/modded vehicles), but only the
    -- selected weapon is of interest here
    local index = 1
    for _, g in pairs(car.prototype.guns) do
      if index == car.selected_gun_index then
        gun = g
        break
      end
      index = index + 1
    end
  end

  if state.enemy_sensor and gun then
--~ vdebug("Have gun, sense enemy?")
    enemy = car.surface.find_nearest_enemy({
      force = car.force,
      position = car.position,
      max_distance = gun.attack_parameters.range + 3,
    })
  end

  -- reload
  if state.ammo_sensor and gun and trunk and clip then
    -- Try to reload all weapons
    for slot = 1, table_size(car.prototype.guns) do
      -- Reload if weapon has no ammo
      if not clip[slot].valid_for_read then
        for item, count in pairs(trunk.get_contents()) do
          local stack = { name = item, count = count }
          if clip.can_insert(stack) then
            notify(state, {"AUTODRIVE-messages.reload"})
            trunk.remove({ name = item, count = clip.insert(stack) or 1 })
            break
          end
        end
      end
    end
  end
  --------------------------------------------------------------------------------------------
  -- We tried to reload -- but does every (or any) weapon have ammo?
  -- Do nothing if currently selected weapon has ammo, otherwise switch to the first
  -- weapon (from left to right) available. This allows the player to manually switch
  -- weapons, so expensive ammo like cannon shells isn't wasted on small biters. 
  if gun and clip and not clip[car.selected_gun_index].valid_for_read then
    local has_ammo = false
    for slot = 1, table_size(car.prototype.guns) do
      -- This weapon has ammo, so make it active
      if clip[slot].valid_for_read then
        car.selected_gun_index = slot
        has_ammo = true
        break
      end
    end
    -- A car without ammo doesn't really have a gun!
    if not has_ammo then
      gun = nil
    end
  end

  local shooter = (driver and driver.valid) and driver or passenger
  if gun and enemy and enemy.valid and shooter and shooter.valid then
    shooter.shooting_state = {
      state = defines.shooting.shooting_enemies,
      position = enemy.position,
    }
  end
The logic is rather primitive, as you can see. It doesn't take into account the vulnerabilities of an enemy -- it's just picking the first weapon that can be used and attacking the first thing in range. But perhaps you can use some ideas from it. :-)
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!

SyncViews
Filter Inserter
Filter Inserter
Posts: 295
Joined: Thu Apr 21, 2016 3:17 pm
Contact:

Re: NPC Controlled Entities with more than 1 weapon and/or weapon switching logic?

Post by SyncViews »

You can do a fair bit with vehicles, but it relies heavily on Lua coding unfortunately, which massively limits scale (a small group of player stuff or a "boss", fine. as a common unit like normal biters/spitters? Forget it, you probably have a bunch of stuff to do per-unit per-tick.).

Units perform better as you can leave them to get on with stuff and interact with them in scripts less often, but I found units a lot more restrictive in terms of capability, see https://wiki.factorio.com/Prototype/Unit, e.g. you only get to add one `attack_parameters`.
An idea I had was to destroy and then create a new unit (of a different prototype) at the same position. I didn't try implementing it yet though, the question is if can spawn a unit precisely enough to avoid too much of a visual glitch, how much it glitches surrounding entities (e.g. turret, drone, etc. targeting), etc.

swizzlewizzle
Burner Inserter
Burner Inserter
Posts: 10
Joined: Thu May 14, 2020 7:58 am
Contact:

Re: NPC Controlled Entities with more than 1 weapon and/or weapon switching logic?

Post by swizzlewizzle »

Destroy/create has a lot of overhead so it doesn't sound defensible... can the attack_parameters be easily changed at runtime directly? If so, perhaps holding a table of all in-combat entities and rotating their attacks every few seconds would work.. won't have "smart" AI, but will at least allow them to mix up their attack profile... unless someone else has a better idea?

SyncViews
Filter Inserter
Filter Inserter
Posts: 295
Joined: Thu Apr 21, 2016 3:17 pm
Contact:

Re: NPC Controlled Entities with more than 1 weapon and/or weapon switching logic?

Post by SyncViews »

Prototypes are shared between all instances of an entity and are read-only unfortunately (I wouldn't mind ability to make arbitrary changes though, I was looking more at upgrading spawners/worms/etc. when I first looked at the create/destroy idea, since research can only effect very few stats).

swizzlewizzle
Burner Inserter
Burner Inserter
Posts: 10
Joined: Thu May 14, 2020 7:58 am
Contact:

Re: NPC Controlled Entities with more than 1 weapon and/or weapon switching logic?

Post by swizzlewizzle »

Yea it's looking like the only way to achieve a single spawned "entity" having more than one way to attack is to despawn and respawn it on the same spot, inside of a single tick, with itself (a prototype that is basically the same), except a different attack_parameters set...

Or the devs could add the ability to give a table of attack_parameters to a unit instead of just 1... add basic random-chance rotation of the attack parameters, or even some simple AI that could be set to define what attack type the unit should use.

Destroy/create here we go!

Post Reply

Return to “Modding help”