How do I move characters that don't have a player (and never will)?

Place to get help with not working mods / modding interface.
Post Reply
credomane
Filter Inserter
Filter Inserter
Posts: 278
Joined: Tue Apr 12, 2016 6:21 pm
Contact:

How do I move characters that don't have a player (and never will)?

Post by credomane »

I'm trying to create NPCs for a scenario I'm working on but I can't seem to figure out how to make the created entity of the character prototype move around in the way a player/biter would. Meaning walk around navigating around obstacles VS teleport() to instantly reach the desired destination.

Take the snippet of code at the bottom of this post. I create a character then tell it to move to {50,0} and (hopefully) do whatever path-finding might be necessary to reach that location. Instead of these results I get "Error: Entity is not unit."

Is there any way to accomplish what I'm wanting? I've looked around the API docs but this is one of those times they confuse me because of how overloaded LuaEntity is. Even doing `/c log(game.player.selected.help()` just returns the same info as the API docs and not just the methods/properties that are valid for an entity of the character prototype (which is what I had under my mouse for the "selected" entity in that command).

Preferably without having to do modifications in the data stage but I can go that route if I must.

Code: Select all

local e = game.surfaces.nauvis.create_entity({
    name = "character",
    position = {0,0}
})

e.set_command({
    type = defines.command.go_to_location,
    destination = {50,0},
    distraction = defines.distraction.none
})
TL;DR:
I'd like to know how to do these "player" type actions on a entity of the character prototype but I'm too inexperienced to figure it out.

Move a "NPC" (really a character) to LuaPosition or LuaEntity.
Look at LuaPosition or LuaEntity (kinda like when a player mouses over an entity and the player's character looks in that direction.
Shoot at LuaPosition or LuaEntity.

FuryoftheStars
Smart Inserter
Smart Inserter
Posts: 2553
Joined: Tue Apr 25, 2017 2:01 pm
Contact:

Re: How do I move characters that don't have a player (and never will)?

Post by FuryoftheStars »

I've never done this so I don't know the answer, but you should maybe look at some mods that have to see if you can figure out what they did.

Example mods:
Robot Army
AAI Programmable Vehicles
My Mods: Classic Factorio Basic Oil Processing | Sulfur Production from Oils | Wood to Oil Processing | Infinite Resources - Normal Yield | Tree Saplings (Redux) | Alien Biomes Tweaked | Restrictions on Artificial Tiles

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

Re: How do I move characters that don't have a player (and never will)?

Post by Pi-C »

FuryoftheStars wrote:
Wed Sep 14, 2022 4:59 am
Example mods:
AAI Programmable Vehicles
AAI is nuts. :-) It actually uses biters for navigation, so it takes advantage of the biters' pathing algorithm. But there's a lot more going on there, and I wouldn't say the code is easy to understand.

Anyway, I'm just working on Autodrive again, which takes a somewhat different approach to AAI: Instead of utilizing biters directly, it uses LuaSurface.request_path (according to the description, this will use the unit pathfinding algorithm) to get an array of waypoints from the vehicle position to the selected destination. The vehicle is rotated so that it faces in the direction of the next waypoint:

Code: Select all

vehicle.orientation = AD_calc.angle(vehicle.position, waypoint)/360
The vehicle is then put in motion (or stopped) using LuaControl.riding_state:

Code: Select all

vehicle.riding_state = {
        acceleration = defines.riding.acceleration.accelerating,
        direction = defines.riding.direction.straight
      }
The vehicle's position is polled in on_tick. If it has reached the next waypoint, the first waypoint is removed from the array and the vehicle is rotated into the direction of the waypoint after that. When the path array is empty, the vehicle has arrived at its destination and can be stopped.

Unfortunately, riding_state is only available for "[the] car or the vehicle this player is riding in", so using character.riding_state wouldn't work. However, it may be possible to put the character into an invisible car. Potential problems: Not sure if the character would be visible if the car isn't. Even if it was visible, it wouldn't be walking, so this may look awkward.


credomane wrote:
Wed Sep 14, 2022 3:24 am
I'm trying to create NPCs for a scenario I'm working on but I can't seem to figure out how to make the created entity of the character prototype move around in the way a player/biter would. Meaning walk around navigating around obstacles VS teleport() to instantly reach the desired destination.
There is precedence for an NPC in Factorio: Compilatron from the tutorial mission! Actually, Compilatron is a unit (use CTRL+SHIFT+E to open the prototype browser and search for "compilatron"). So I'd recommend to base your NPCs on the unit prototype. The NPCs could be created on account of the player's force, or you could even use a dedicated force for all your NPCs. In this case, you can use force.set_friend and force.set_cease_fire to make sure the NPCs don't attack the players they are meant to help. :-)
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!

User avatar
Deadlock989
Smart Inserter
Smart Inserter
Posts: 2528
Joined: Fri Nov 06, 2015 7:41 pm

Re: How do I move characters that don't have a player (and never will)?

Post by Deadlock989 »

You can only give commands to entities of type "unit" and they are the only entities capable of using the built-in pathfinding to move themselves. In the base game, units are biters and spitters.

The Robot Army mod uses units (presumably on the same force as the player) and UnitGroups as an anti-biter allied force whose behaviour is based on biter behaviour but topped up with some command logic based on player actions.

AAI Programmable Vehicles used to use an invisible unit and then teleported/oriented its moving vehicles every tick to match. Later Factorio exposed some of the workings of the pathfinder algorithm via LuaSurface::request_path() so you can request a set of waypoints and then take some kind of action to move things along them. Pathfinder requests are not synchronous - you have to listen for an event which returns the result of the pathfinder request. However, if the things to be moved are not themselves units, you are back to teleporting/orienting shenanigans, but at least you now have a (probably) obstacle free path to move them along.

I feel like I have seen a mod which uses units that have the character animation so they look like a player but are in fact units - can't recall which right now.

Edited to add: Pi-C posted the more detailed response above while I was writing this.
Image

User avatar
Deadlock989
Smart Inserter
Smart Inserter
Posts: 2528
Joined: Fri Nov 06, 2015 7:41 pm

Re: How do I move characters that don't have a player (and never will)?

Post by Deadlock989 »

I just did a bit of fiddling and it looks like unattached characters do respond to changes to walking_state, which lets you move a character in one of the eight compass directions with all the proper animations, correct speed (including terrain modifiers) etc. Unlike player-controlled characters though, the state persists for an unattached character - it will continue walking in the specified direction until told to stop, whereas with a player-controlled character this is overridden by input (including no input) so you have to update it every tick.

So to have a pathfinding unattached character your routine would be something like this:
  • Send a request for a path to surface.request_path(), starting from the character's current position, ending where you want them to be
  • Listen to the on_script_path_request_finished event and file the result away safely
  • Start an on_tick event processing character moves if it isn't already running
  • For each moving character, get the first waypoint in the list (if there are any)
  • If it is close enough, stop the character and delete the waypoint from the list or increment an index or whatever
  • If it is not close enough, work out which direction to move in to get there and set walking_state appropriately
  • Repeat until no characters have any pending waypoints, at which point, stop the on_tick event
Probably more finesse required (e.g. path gets obstructed by something else that can move) but that's the very basic idea I think.
Image

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

Re: How do I move characters that don't have a player (and never will)?

Post by Pi-C »

Deadlock989 wrote:
Wed Sep 14, 2022 10:03 am
Probably more finesse required (e.g. path gets obstructed by something else that can move) but that's the very basic idea I think.
Checking whether a vehicle's path is obstructed is easy -- just listen to on_entity_damaged, filtered by damage type "impact". However, a character bumping into something doesn't cause damage (it could be on the receiving end if it runs into a moving car or train, but not when it collides with an assembler). So you'd have to check the character's position on every tick. Also, if you have a long path calculated before you start the character, it will be valid at the time you get the path -- but while the character has been walking for a couple hundred tiles, somebody may have put something into its way. Unless the NPCs need a property that only characters have it still should be way easier to use a unit prototype.
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!

credomane
Filter Inserter
Filter Inserter
Posts: 278
Joined: Tue Apr 12, 2016 6:21 pm
Contact:

Re: How do I move characters that don't have a player (and never will)?

Post by credomane »

Sorry this took so long to reply. Got busy and haven't had time to mess with much.
Pi-C wrote:
Wed Sep 14, 2022 9:20 am
There is precedence for an NPC in Factorio: Compilatron from the tutorial mission! Actually, Compilatron is a unit (use CTRL+SHIFT+E to open the prototype browser and search for "compilatron"). So I'd recommend to base your NPCs on the unit prototype. The NPCs could be created on account of the player's force, or you could even use a dedicated force for all your NPCs. In this case, you can use force.set_friend and force.set_cease_fire to make sure the NPCs don't attack the players they are meant to help. :-)
The NPE and compilatron is 50% of what got me into wanting to make this scenario! I'm so sad that it was eventually scrapped. My scenario has been an off/on (mostly off) project for well over a year with very little to show for it other than ideas on paper. I actually planning to reinstall the 0.17.X just so I can deeply explore how a lot of that scenario worked as there are parts/features/whatever that I want to potentially use myself. I'm pretty sure there is a "background" surface that has the whole scenario map and they use the LuaSurface.clone_*() functions to bring in the "background" surface piece by piece to expand the active surface bit by bit as the scenario progresses. I'm at the point now that I want to create some of the ideas to see what is possible and what works/doesn't.

The other 50% is the "Story Missions" scenario on the mod portal. I've only reached the 4th mission and I'm loving it. Makes me wish there were more story oriented scenarios on the portal.

CTRL+SHIFT+E So that's what it was! I did it by mistake once and couldn't figure out how to do it intentionally after that.
Basing my NPC's off the unit prototype would require me to do stuff in the data stage. Which I was hoping to avoid but it is looking more and more like I will have to do so if for no other reason than to make things that much easier on myself. NPC will mostly be on forces different from players so I've already got the diplomancy stuff figured out.
Deadlock989 wrote:
Wed Sep 14, 2022 9:25 am
I feel like I have seen a mod which uses units that have the character animation so they look like a player but are in fact units - can't recall which right now.
Guess I will have to try to find that mod and see what idea/help it can provide me with doing the same if I can't get my dumb LUA "AI" working to move units around. Basically tells the npc to move in a direction while checking if the current position against the previous position (is stuck?) and the destination waypoint. I want to add in a teleport command if the unit is stuck for too long and just move them to the next WP location instantly if they don't arrive there within a timelimit. Idealy that time limit would be something like (UnitSpeedInTilePerSecond*TilesToTravel)+XSeconds that if exceeded would trigger an instant teleport.
Pi-C wrote:
Wed Sep 14, 2022 11:08 am
Unless the NPCs need a property that only characters have it still should be way easier to use a unit prototype.
The NPCs will for sure need access to movement, shooting, equipment grid, logistic requests, inventory, enter/exit vehicles and that selection/looking thing the player character does as you mouse over stuff. As well as the ability to set their color. Crafting isn't needed as I can just directly insert the require item(s). The mining animation might be neat to have for fun but isn't required.

Technically I could fake the enter/leave vehicles with teleports and if I make units I can just pre-color the sprite sheets (note: terribly) to the colors I require.

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

Re: How do I move characters that don't have a player (and never will)?

Post by Pi-C »

credomane wrote:
Mon Sep 19, 2022 8:46 pm
The NPE and compilatron is 50% of what got me into wanting to make this scenario! I'm so sad that it was eventually scrapped. My scenario has been an off/on (mostly off) project for well over a year with very little to show for it other than ideas on paper. I actually planning to reinstall the 0.17.X just so I can deeply explore how a lot of that scenario worked as there are parts/features/whatever that I want to potentially use myself. I'm pretty sure there is a "background" surface that has the whole scenario map and they use the LuaSurface.clone_*() functions to bring in the "background" surface piece by piece to expand the active surface bit by bit as the scenario progresses. I'm at the point now that I want to create some of the ideas to see what is possible and what works/doesn't.
I still have several old versions installed, so I've attached the zipped data.base.lualib directory. This seem to be the files used in the control stage of the NPE. Perhaps that may be useful …
CTRL+SHIFT+E So that's what it was! I did it by mistake once and couldn't figure out how to do it intentionally after that.
You can also hover the cursor over an entity and use CTRL+SHIFT+F to browse its prototype properties.
I want to add in a teleport command if the unit is stuck for too long and just move them to the next WP location instantly if they don't arrive there within a timelimit. Idealy that time limit would be something like (UnitSpeedInTilePerSecond*TilesToTravel)+XSeconds that if exceeded would trigger an instant teleport.
Don't forget that units also are affected by movement speed buffs/nerfs from tiles!
Pi-C wrote:
Wed Sep 14, 2022 11:08 am
Unless the NPCs need a property that only characters have it still should be way easier to use a unit prototype.
The NPCs will for sure need access to movement, shooting, equipment grid, logistic requests, inventory, enter/exit vehicles and that selection/looking thing the player character does as you mouse over stuff. As well as the ability to set their color. Crafting isn't needed as I can just directly insert the require item(s). The mining animation might be neat to have for fun but isn't required.
Yesterday, I've dealt with making my mod compatible with spider-vehicles. It was a bit frustrating to see that they do many things out of the box which my mod adds to "car"-based vehicles by heavy scripting (movement, shooting, logistics). But yes, using spider-vehicles (just the body, without the legs) as NPC would also make sense in your case. For example, you can control movement by setting

Code: Select all

vehicle.autopilot_destination = position
and you can queue a complete path by using

Code: Select all

vehicle.autopilot_destinations = { position_1, position_2, … }
Once the position stored in vehicle.autopilot_destination has been reached (triggering on_spider_command_completed), it will be replaced with the position from vehicle.autopilot_destinations[1], which will then be cleared. Best of all: you can directly set the color of a vehicle!
Technically I could fake the enter/leave vehicles with teleports and if I make units I can just pre-color the sprite sheets (note: terribly) to the colors I require.
Yes, teleporting your NPC to another surface should work. However, vehicles based on a "car" prototype will need a real character to open gates or shoot at enemies. So, unless you ask the player to enter the vehicle "together" with an NPC (which really is teleported out of the way), you should set vehicle.driver or vehicle.passenger to a dummy character (a direct copy of data.raw.character.character should do the trick). However, don't forget to destroy the dummy when the vehicle is destroyed or when the NPC reappears!
Attachments
0-17-npe.zip
(88.13 KiB) Downloaded 34 times
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!

Post Reply

Return to “Modding help”