Using LuaSurface.find_nearest_enemy* with min_distance

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Pi-C
Smart Inserter
Smart Inserter
Posts: 1742
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Using LuaSurface.find_nearest_enemy* with min_distance

Post by Pi-C »

What?
Both LuaSurface.find_nearest_enemy and LuaSurface.find_nearest_enemy_entity_with_owner take max_distance as argument. I'd like to have the option to pass on min_distance as well.
Why?
Currently, these functions find just one enemy in the radius given by max_distance around a position. While this may find an enemy, it isn't guaranteed that this enemy can be attacked because there are weapons that have a min_range (e.g. flame thrower). These weapons will only start shooting if min_range <= distance_to_target <= max_range.

Of course, I could use LuaSurface.find_entities_filtered to find all entities that do not belong to a certain force and then check if they are at least min_distance away from the shooter position. However, this isn't practical for two reasons:
  • While find_nearest_enemy* is looking for entities that are considered military units or structures out of the box, we must construct filters for find_entities* that will catch all entities with a prototype that has the is_military_target flag.
  • Even with such filters in place, find_entities* will find all entities based on prototypes with is_military_target. We'd still need to make sure that they are of a different force than the shooter, and that target and shooter force really are enemies.
Alternative
The beauty of find_nearest_enemy* is that it already filters for enemies of the shooter. The problem is that it will find one enemy only, and searching again from the same position will find the same enemy again, or another that would also be less than min_distance away from the shooter's position.

If it isn't possible to add min_distance to find_nearest_enemy and find_nearest_enemy_entity_with_owner, it also would be useful to get versions of these that return all enemies/all enemy entities with owner within the circular area around position. With an array of guaranteed enemies available, it should be easy to find a target that's more than min_distance away.
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Honktown
Smart Inserter
Smart Inserter
Posts: 1045
Joined: Thu Oct 03, 2019 7:10 am
Contact:

Re: Using LuaSurface.find_nearest_enemy* with min_distance

Post by Honktown »

For the "find within circular radius" part, find_entities_filtered can take only a radius and position, and the enemies of the force can be gotten by using force.is_enemy() against game.forces, and is_military_target ... and more logic for minimum, supposing

An alternative is a turret. They do all this for you, and could raise a script effect TriggerItem when they hit something. Invisible void-powered energy turret would fire at anything nearby. If you hadn't heard of 'composite entities', you build them and remove them as closely as possible to when the original is built to get the extra behavior desired.
I have mods! I guess!
Link
Pi-C
Smart Inserter
Smart Inserter
Posts: 1742
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: Using LuaSurface.find_nearest_enemy* with min_distance

Post by Pi-C »

Honktown wrote: Sun Jul 02, 2023 5:13 pm For the "find within circular radius" part, find_entities_filtered can take only a radius and position, and the enemies of the force can be gotten by using force.is_enemy() against game.forces, and is_military_target ... and more logic for minimum, supposing
Thanks, but I knew this already. My point was, find_nearest_enemy is great because it already figures out what kind of entities are military targets, and whether they are of an enemy or friendly force, but has the drawback that it will find just one (the closest) enemy. In contrast, find_entities_filtered doesn't have automatic enemy recognition built in (so when loading a game, I have to rebuild a list of all entity prototypes that have the is_military_target flag that I can then use as search filter, but with mods, the list may get quite long; additionally, I have to filter out entities from the force as the shooter + friendly entities), but has the advantage that it will give you an array of all entities found in the search area. What I want is the best of both worlds: Using the current mechanism of find_nearest_enemy will usually be sufficient, but not if the used weapon has a min_range. (If the enemy it finds is closer to the shooter's position than allowed by min_range, a new search from the same position will be futile because if another enemy was closer to the shooter, it would be too close for min_range as well.) In this case, if I could fall back to a list of all enemies in the search area would allow me to iterate over the lest and check whether their distance is >min_range.
An alternative is a turret. They do all this for you, and could raise a script effect TriggerItem when they hit something. Invisible void-powered energy turret would fire at anything nearby. If you hadn't heard of 'composite entities', you build them and remove them as closely as possible to when the original is built to get the extra behavior desired.
I've used composite entities before, but I don't think this would be a good idea here. My use case is Autodrive, which is an attempt to let vehicles operate without a player inside. Vehicles equipped with an enemy sensor will look for the nearest enemy in regular intervals. If the vehicle has a loaded weapon, it will attack. If the weapon runs out of ammo and there is another one, the vehicle will switch weapons and continue fighting. If the vehicle prototype doesn't have any gun, or if no gun has any ammo left, vehicles equipped with an enemy sensor will try to escape.

Adding hidden turrets to vehicles may be OK if they are immobile. If the vehicles are moving, I'd have to check the turret's position on each tick and teleport it to the vehicle position if they are too far apart from each other. Also, the vehicles still have their own weapons. (I can't really mod them away because only the vehicles selected by the player are to auto-shoot -- if the vehicle is released from my mod's control, the vehicle resumes its normal behavior. So adding hidden turrets would also mean duplicating the vehicle prototypes to get a version with and another without weapons.) The whole thing looks like it will be an awful hog of resources, and fragile like hell. :-)

(As a workaround, I've just changed the code deciding whether vehicles should attack or escape so that they will be considered as having no gun if the closest enemy is nearer than min_range. This has the disadvantage that the vehicle will always escape if the nearest enemy isn't far enough away -- even if there was another enemy that it could shoot at.)
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
pleegwat
Filter Inserter
Filter Inserter
Posts: 278
Joined: Fri May 19, 2017 7:31 pm
Contact:

Re: Using LuaSurface.find_nearest_enemy* with min_distance

Post by pleegwat »

Pi-C wrote: Sun Jul 02, 2023 5:56 pm This has the disadvantage that the vehicle will always escape if the nearest enemy isn't far enough away -- even if there was another enemy that it could shoot at.)
But it will be running away from an enemy it currently cannot attack, which could otherwise be meleeing it. Might actually be desirable.
Honktown
Smart Inserter
Smart Inserter
Posts: 1045
Joined: Thu Oct 03, 2019 7:10 am
Contact:

Re: Using LuaSurface.find_nearest_enemy* with min_distance

Post by Honktown »

The vehicle having equipment grids with lasers would work for detecting nearby enemies... And ironically might make sense in context (equipping the vehicle with an auto-attack sensor). However many equipments it takes to attack only on min-range on some weapon, swapping out as needed.

*Can* vehicles even fire when they're not being player driven and it's not a spidertron? Shooting target is for turrets. I don't see any way to force-fire with it, so one must simulate the whole attack process if you're really trying to auto-attack.

Also, stopping the vehicle so it can attack would be something that makes sense, if turrets aren't completely off the table. Simple AI behave like that.
I have mods! I guess!
Link
Pi-C
Smart Inserter
Smart Inserter
Posts: 1742
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: Using LuaSurface.find_nearest_enemy* with min_distance

Post by Pi-C »

Honktown wrote: Mon Jul 03, 2023 12:03 am The vehicle having equipment grids with lasers would work for detecting nearby enemies... And ironically might make sense in context (equipping the vehicle with an auto-attack sensor). However many equipments it takes to attack only on min-range on some weapon, swapping out as needed.
Lasers? Need to think about it. Actually, all equipment created by Autodrive is just sensors. If a sensor for something is installed in the grid, it triggers checks in my script, but it isn't guaranteed that a vehicle can act on it. For example, if a vehicle has a repair sensor, this will trigger the code that checks for damage and initiates repairs, but the vehicle will only be repaired if it has repair-packs (vanilla or modded) in its trunk -- so the sensor is not a super repair-tool on its own. Similarly, the fuel sensor triggers the code that checks if the vehicle has run out of fuel and transfers suitable items from the trunk to the fuel inventory; but it won't generate fuel ex nihilo, if a vehicle has burnt up the last fuel and there is none left in its trunk, it can't go on even if it has a fuel sensor. Adding a sensor that really does stuff on its own would break with this paradigm -- not saying that's bad, but it's different. :-)
*Can* vehicles even fire when they're not being player driven and it's not a spidertron? Shooting target is for turrets. I don't see any way to force-fire with it, so one must simulate the whole attack process if you're really trying to auto-attack.
Players don't shoot, characters do! When a player enters a vehicle, the player will remain outside but player.character will be moved into the vehicle. So, if my mod finds that there are enemies within shooting range of a vehicle that has no character inside, it will create a dummy character and put it in the passenger seat. It then decides who will be shooter (passenger by default, or driver if there is no passenger) by setting vehicle.driver_is_gunner, and assigns a target by setting shooter.shooting_state.
Also, stopping the vehicle so it can attack would be something that makes sense, if turrets aren't completely off the table. Simple AI behave like that.
Using turrets would make things rather awkward. Players can still ride in an Autodrive-controlled vehicle, they can even drive it themselves (in this case, they'd still benefit from things provided by the installed sensors, e.g. automatic ammo/fuel reloading and auto-repairing with items from the trunk, automatic shooting, or the -- still crappy -- logistic network support for cars). That's where the vanilla display of the player's vehicle becomes a problem: It shows the weapon/ammo slots of the player's current vehicle. If I swap the vehicle for a version without weapons and use a turret, players will notice that their vehicle suddenly has no weapons but starts shooting; it's similar if I keep the vehicle but move its ammo from the vehicle weapon to the turret. If I leave the vehicle as it is and create turrets for shooting, I also must sync the ammo inventories after each shot, so players can see that ammo is getting used up or reloaded.

Besides, stopping for attack could be dangerous: If the vehicle attacks a spawner, it will be attacked by biters running towards it. I think shoot, run, and shoot again generally is a better tactic than shoot, shoot, and shoot until you're surrounded by a bunch of enemies and can't move in any direction.
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Honktown
Smart Inserter
Smart Inserter
Posts: 1045
Joined: Thu Oct 03, 2019 7:10 am
Contact:

Re: Using LuaSurface.find_nearest_enemy* with min_distance

Post by Honktown »

I did not see shooting_state before, thanks. Strange. I see it's in the bottom of a LuaEntity, and I searched for many different terms...
I have mods! I guess!
Link
Post Reply

Return to “Modding interface requests”