Jump to content
The Dark Mod Forums

Tips on advanced AI patrolling?


Rooz

Recommended Posts

I'd like to have my city guards operate as realistically as I can manage. I've looked over the wiki on triggers, stim/responses, signals and scripting and between some combination of those the system has gotta be possible. I'm a competent enough programmer that if I pour over the documentation I could eventually get something working, but it wouldn't necessarily be pretty and could really impact performance. I'm up for a challenging project, but I'd like to start off in the right direction. It'll be great if anyone had helpful tips before I dig in.

 

Here's an abstraction of the map that'll be useful when you hear the system.
post-38243-0-60639100-1525654673_thumb.jpg

And here's an overview of the system I'm thinking about.

 

START

Guard 1 patrolling Zone 1 via Path 1, each loop checks in with Capt
Guard 2 patrolling Zone 2 via Path 2, each loop checks in with Capt
(Say loop time is 5min +/- 1min)
STEP 1
Guard 1 doesn't check in with Capt. after 6min
When Guard 2 checks in, Capt. directs Guard 2 & 3 to patrol on Path 1
STEP 3
Next time Guard 2 & 3 check in w/o Guard 1, Guard 4 & 5 woken up and patrol Path 2
Archer 3 & 4 woken up and take position 3 & 4 (red squares)
IF PLAYER SPOTTED
During STEP 1: guard engages, if player escapes, guard returns to Capt. -> FULL ALERT STATUS
During STEP 2: one guard engages and the other runs to raise alarm -> FULL ALERT STATUS
During STEP 3: one guard engages and the other runs to raise alarm -> FULL ALERT STATUS (really only has to run to nearest archer, right? then alarm can be yelled around?)
FULL ALERT STATUS
Whichever guard raises alert passes on the last known location. (Zone, Section, Area.) All guards move to that location and search (ideal would be they approach from different directions). Archer 4 drops back to archer 3. Capt. calls for Backup 1 & 2
Link to comment
Share on other sites

There are spawnargs you can put on AI pathnodes so AI will only go to those nodes once they are alerted to an intruder. I forget what it is off the top of my head--something like "alert_idle" "1".

 

The rest of it sounds like it would require some hefty scripting, which I know little about.

Link to comment
Share on other sites

It's all good Springheel. Those kinds of tips are what I was looking for right now. I usually do more homework before I start asking questions, but I figured it couldn't hurt. Having a short (or long) list of elements that will be necessary/useful in a system like this would shave off some time finding them myself.

 

My first goal is just getting the captain to dispatch the stationed guard to the missing guard's path. Even that mechanic would be cool to see in missions.

 

I'll start having more specific questions soon though.

Link to comment
Share on other sites

Grayman, I'm hoping you see this. I just read your name a bunch.

 

I looked at the source code and it seems like I'll have to be scripting around these areas:

 

AI_events.cpp - FindFriendlyAI, GetAlertLevelofOtherAI

Memory.cpp - too much to list (enemylastseen is among the most crucial to share with other AI)

tasks - FollowActor, GuardSpot, InvestigateSpot

 

There were a bunch of other AI behaviors I'd like to see in the game. I appreciate the whole "guards are ambivalent unless you do something shady." Since you can't easily conceal a bow or sword I think just having one of them on you should be suspicious. It looks like Inventory.cpp line 1014 could be related to that ent->spawnArgs.GetString(inv_weapon_name)

 

I also think it'd be shady to be seen walking around with a sack of 15 gold cups, 6 gold statues, some plates, etc. All that stuff would be rustling too. Making CInventory.GetLoot() or something similar and making guards alert to that seems doable.

Link to comment
Share on other sites

I would recommend ot take a look at the path nodes and RIT Networks Wiki pages, if you have not already done so. These will be your best friends for this project ;)

One idea I have for "one guard fights, the other alerts others" would be that you could let one guard flee as soon as the fight starts (perhaps make him a civilian with a guard skin and a prop sword). If you set a flee point near the guard, any AI will flee there. Information of the player location is usually transfered to AI that the fleeing AI meets on the way. There you could replace the fleeing civilian AI with an actual guard that will then return to the fight.

For your "patrol checking back" scenario, the first thing that comes to mind is a timed trigger. The timer gets reset each time the guard passes. If the guard does not pass, the trigger targets a "path_waitfortrigger" for one of the guards in the waiting area. It would be easier to just send another guard rather than reroute guard 2, but if you really want to reroute him, this can be achieved with means described in "Switching form one Path network to another" on the Path Nodes page.

  • Like 1
Link to comment
Share on other sites

I also think it'd be shady to be seen walking around with a sack of 15 gold cups, 6 gold statues, some plates, etc. All that stuff would be rustling too.

 

That seems like a terrible idea, gameplay-wise. The endless space for loot is unrealistic in the first place, and that is a deliberate simplification. Making a system like that would basically punish players for getting a lot of loot.

Link to comment
Share on other sites

Grayman, I'm hoping you see this. I just read your name a bunch.

The scripts talk to the code using a set of interface routines, which are described on this Wiki page.

 

Unfortunately, that page is a bit out of date (I need to re-generate it for 2.06).

 

Since you're reading source files, you can search for "idEventDef". This should give you all the current interface routines and their descriptions.

 

Finding an interesting routine in the source that seems to give you what you want only helps you if there's an interface routine that gives the script access to that source routine.

Link to comment
Share on other sites

I appreciate the whole "guards are ambivalent unless you do something shady." Since you can't easily conceal a bow or sword I think just having one of them on you should be suspicious. It looks like Inventory.cpp line 1014 could be related to that ent->spawnArgs.GetString(inv_weapon_name)

 

 

Obsttorte created a script that caused AI to ignore you unless certain conditions were met. It's probably somewhere in his "apples and peaches" (IIRC?) thread.

Link to comment
Share on other sites

Thank you everybody that's responded!

I would recommend ot take a look at the path nodes and RIT Networks Wiki pages, if you have not already done so. These will be your best friends for this project ;)
One idea I have for "one guard fights, the other alerts others" would be that you could let one guard flee as soon as the fight starts (perhaps make him a civilian with a guard skin and a prop sword). If you set a flee point near the guard, any AI will flee there. Information of the player location is usually transfered to AI that the fleeing AI meets on the way. There you could replace the fleeing civilian AI with an actual guard that will then return to the fight.
For your "patrol checking back" scenario, the first thing that comes to mind is a timed trigger. The timer gets reset each time the guard passes. If the guard does not pass, the trigger targets a "path_waitfortrigger" for one of the guards in the waiting area. It would be easier to just send another guard rather than reroute guard 2, but if you really want to reroute him, this can be achieved with means described in "Switching form one Path network to another" on the Path Nodes page.


Yes, I checked out those pages and knew they'd be very helpful. The "waitfortrigger" was the way I thought it'd best be handled, and I was really glad to see that switching path nodes is built in.

The civilian-in-guards-clothes sounds like a great idea. I read up on the fleeing system and thought I could make a guard operate like that. I hadn't thought of just switching them out though which will probably be the easier way. Thanks!

That seems like a terrible idea, gameplay-wise. The endless space for loot is unrealistic in the first place, and that is a deliberate simplification. Making a system like that would basically punish players for getting a lot of loot.


I hear that and agree that it makes gameplay better across missions. It could be an interesting dynamic for the way I'm envisioning the map in my case. A major feature in it is going to be a bridge between the rich part of town and the poor part. There's a bridge between the two (choke point!) which you'll have to cross to get from where you live in the poor part and where you steal in the rich part. The bridge is heavily guarded though there will be two tricky ways to navigate around it. Since you don't have loot to start with getting there won't be the issue as you can just walk on through. I don't think you can drop loot the way you can drop inventory items but I could probably figure that out. I'd place openable crates in locations on the other side of the river so players would have the option of stashing loot there between houses. When you've got what you needed you'd then pick it up and have to make your way back via one of the tricky routes. Granted, I'd probably recommend never getting caught entirely.

To be sure, these dynamics would significantly alter the common strategies. That's intentional though. I think it'd be fun to have a mission where your play is based on certain mechanics in addition to the map. It might not be for everybody though.

The scripts talk to the code using a set of interface routines, which are described on this Wiki page. [...] Finding an interesting routine in the source that seems to give you what you want only helps you if there's an interface routine that gives the script access to that source routine.


Oh jeez :blush: I can't believe I missed that page before checking out the source code. Though I guess it never hurts to look at the source code at least once. Thanks for already regenerating it!


Obsttorte created a script that caused AI to ignore you unless certain conditions were met. It's probably somewhere in his "apples and peaches" (IIRC?) thread.


Yep, I came across that script early on. Since I've seen it in play on certain missions I figured I wouldn't have to start from scratch on it and just would have asked the person who created the FM if I could use it.

 

Edit: I look forward to sharing my scripts too!

Edited by Rooz
Link to comment
Share on other sites

To be sure, these dynamics would significantly alter the common strategies. That's intentional though. I think it'd be fun to have a mission where your play is based on certain mechanics in addition to the map. It might not be for everybody though.

 

It will probably need to be thoroughly tested first, and clearly communicated to the player as well. Not sure whether it generates anything than backtracking/busywork though. Maybe it would be more interesting on a relatively small map.

Link to comment
Share on other sites

Any time the player has to make meaningful decisions (as long as they're reasonably aware of the consequences), that is a good thing for gameplay. I would argue that in stealth games, at least, it's the ONLY thing.

Link to comment
Share on other sites

 

It will probably need to be thoroughly tested first, and clearly communicated to the player as well. Not sure whether it generates anything than backtracking/busywork though. Maybe it would be more interesting on a relatively small map.

 

Yeah, I'll have a thorough preface on the mission and will appreciate the testing. I'm also thinking that the difference in difficulty levels could be more from these scripts than increasing the health/senses/damage from AI.

 

The map is going to be pretty small too and I really like platforming gameplay so there will be plenty of ways to stay above the streets entirely. I don't think the loot handling has to affect the way people play until they try to make it back. Even then, all you'd have to do is stop moving when a guard gets too close. It's really no blackjacking when you make your escape.

 

Any time the player has to make meaningful decisions (as long as they're reasonably aware of the consequences), that is a good thing for gameplay. I would argue that in stealth games, at least, it's the ONLY thing.

 

Agreed. A main thing I'm aiming for with my mission is offering multiple ways to approach the objectives and make each one carries its pros and cons. Thinking about those aspects is my favorite part of the process. After that it's figuring out the coding. Creating a playable map will be cool too, but I doubt making it really beautiful is going to be my thing. That could change though once I get more familiar with DR. I'm hoping so at least.

  • Like 1
Link to comment
Share on other sites

 

Obsttorte created a script that caused AI to ignore you unless certain conditions were met. It's probably somewhere in his "apples and peaches" (IIRC?) thread.

This hsould be the latest version: http://forums.thedarkmod.com/topic/14394-apples-and-peaches-obsttortes-mapping-and-scripting-thread/?p=310926

 

There is also a wiki article but it is referring to an older version. So don't get confused. I really have to clean out my closet :)

  • Like 1

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

This hsould be the latest version: http://forums.thedarkmod.com/topic/14394-apples-and-peaches-obsttortes-mapping-and-scripting-thread/?p=310926

 

There is also a wiki article but it is referring to an older version. So don't get confused. I really have to clean out my closet :)

 

Nice. I only saw the wiki one and I like what you've done with the recent version. I was thinking that crouching would be among the shady activities.

 

I could have missed a line in that but is there a place where the observer has to see the player doing something? The way I read it it looks like if the player is carrying around a forbidden item then every guard they encounter is going to be hostile.

 

there will be always those people who like to make games as hard as possible for other players in such a way that you don't want to play it ever again.

 

Perhaps. I will tone it down on the easy difficulty. Guards probably won't double up on patrols, the loot limit probably won't exist, etc. I'm hoping some players realize that if they were to KO the sleeping guards before doing their thieving...

Link to comment
Share on other sites

I could have missed a line in that but is there a place where the observer has to see the player doing something? The way I read it it looks like if the player is carrying around a forbidden item then every guard they encounter is going to be hostile.

It's handled both in the observer and the ai script. The observer adds a stim to the player that gets activated once the player does something forbidden and gets deactivated once he stops doing so.

 

}
void observer::setHostile()
{
    $player1.StimEnable(m_stim_number,1);
}
void observer::setNeutral()
{
    $player1.StimEnable(m_stim_number,0);
}

If this stim is active and the player is close enough to the ai, the ai script checks whether the ai can see the player. If so, the ai is set to hostile. In addition, it will "inform" every other ai about the player beeing the bad guy if that other ai can see the player.

 

void ai_observer::becomeHostile(entity inflictor,float f) {
    if (canSee($player1) && canSee(inflictor))
    {
        setEntityRelation($player1,-1);
        moveToEnemy();
        ResponseEnable(m_stim_number,0);
        ResponseEnable(23,0);
        StimAdd(m_stim_number,512);
        StimEnable(m_stim_number,1);
        thread stillConscious();
    }
}

To clear up things a bit. If an ai sees the player doing something forbidden, the function above is called due to the player, which is then the inflictor. So the if-clause reads like

 

if (canSee($player1) && canSee($player1))

The other case would be that the ai gets informed by an ai that already saw the player doing something wrong, where inflictor is the other ai. This means that the new ai gets hostile if it sees the player and an already informed ai at the same time, but the informed ai doesn't has to see the player at that moment. (Think about like the informed ai tells the uninformed ai about the player, and the uninformed currently sees the player and thinks, "o gosh, this guy looks like the one my pale just described") :)

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

Through another thread I just got reminded of the mission "Not an Ordinary Guest". This not only implements the behaviour depndent hostility, but also uses a "hostility meter" in the GUI, so this might also be of interest to you.

Link to comment
Share on other sites

Yep, I see that now. Thanks for explain the explanation Obsttorte.

 

Through another thread I just got reminded of the mission "Not an Ordinary Guest". This not only implements the behaviour depndent hostility, but also uses a "hostility meter" in the GUI, so this might also be of interest to you.

 

Yeah, that meter was great. I'm thinking about implementing something like that myself. I figure crouching/sprinting is less suspicious than picking a lock but they'd still get some attention. The other thing I really liked about that mission was using the difficulties to let you play three very different games. It made me think about how I could have a mission where two thieves are working together and you could play the one doing the burglary or the one providing the distraction.

Link to comment
Share on other sites

I'm making some baby steps. At this point I have an ai_patrol scriptobject skeleton. The AI_DEAD error threw me off for a little until I found this: http://forums.thedarkmod.com/topic/14394-apples-and-peaches-obsttortes-mapping-and-scripting-thread/page-14 so thank you Obsttorte and Springheel.

 

I think I have a decent plan for how to handle this system. A goal is to make it as easy to integrate as Obsttorte's Hitman script. Attaching the timers to the patrolling guards would make that dropping it in easier, right? Otherwise people would have to manually set up a bunch of triggers off of the captain to every guard.

 

Here's my pseudocode for the ai_patrol at the moment in case anybody has feedback.

 

object ai_patrol : ai_darkmod_base
{
float timer
float patrol_time [is the format for this the number of seconds?]
entity patrol_start_point
entity patrol_base [any static entity, simply used to measure a distanceTo]
entity patrol_captain
}
void ai_patrol::init()
{
timer = createTimer(timer_stimID,0,0,0,0)
patrol_time = getFloatKey("patrol_time") [spawnArg]
patrol_start_point = getFloatKey("target0") [pretty sure there's something like getTarget() that'd be appropriate]
patrol_base = getEntity("patrol_base") [by entity name]
patrol_captain = getEntity("patrol_captain") [by entity name]
StartTimer(timer_stimID)
updateLoop()
}
void ai_patrol::updateLoop()
{
if distanceTo(patrol_base)>X && timer>max_time [i don't know how to compare these values]
patrolMissing(patrol_start_point)
else
resetTimer(timer)
StartTimer(timer)
}

 

At first I thought I was going to have to define a bunch of stuff for a patrol_captain and the patrol_base. It seems like all the captain really does is link the patrolMissing to some kind of "dispatchBackup" function which just sets the target of the patrol_backup to the path_corner. (I like how with this system if the player incapacitates the captain the whole thing goes into disarray.)

 

The two main things I'm trying to figure out now are what exactly CreateTimer does and where I need to use stim/responses.

 

Timers are a bit confusing because the CreateTimer returns void. Maybe I haven't read the documentation right though. Also, I'm not sure if I even need to use timers. The ai_patrol updateLoop() doesn't need to get run more than once a minute. The patrol_time spawnarg could be given in minutes then, and the loop just increments that number.

 

With the stim/response, the only one I think I need to have is a stim on the patrol_base with the response on the ai_patrol to set the timer to 0. With the radius parameter it looks like stims/responses are only meant to trigger actions within a specified location.

Link to comment
Share on other sites

The two main things I'm trying to figure out now are what exactly CreateTimer does and where I need to use stim/responses.

From what the documentation in the source code says the timer is intented to activate a stim after the given time has passed.

 

BTW: http://wiki.thedarkmod.com/index.php?title=TDM_Script_Reference/2.03

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

Thanks for clearing that up. The relevant documentation is in Trigger.cpp, right? I wasn't making the direct connection between idTrigger_Timer and CreateTimer. The trigger_timer looks like it's unique because I don't think any other trigger types have their own full set of script events?

 

I think I read that one thing about stim/responses is you can't pass parameters? Or you can't without using a hack. So if the captain has a response to the trigger_timer it would be the same response no matter which stim triggered it?

 

Sorry it's taking me a bit longer than I expected to wrap my head around these core concepts. I haven't come across any scripts that show trigger_timers in action which would have been greatly helpful. I'm sticking with it though and this weekend I should have this dispatching script down. Once I figure out how to have a captain send out one backup after a patrol has been gone for 10 seconds the rest could happen pretty quickly.

Link to comment
Share on other sites

Stim timers (that you set up with CreateTimer) and trigger_timer are two completely different things. They don't belong to each other.

 

If you want the response to a stim to differ depending on the entity causing the stim you have to use a script. You can specify functions to be called upon a stim of a certain type has arrived. The setup is as follows:

 

void init() // for example, you could place it elsewhere if it should get active later on
{
   ResponseSetAction(STIM_TYPE, "function_name");
}
void function_name(entity inflictor, float f)
{
   // inflictor is the entity causing the stim, I forgot what f is
}

Once I figure out how to have a captain send out one backup after a patrol has been gone for 10 seconds the rest could happen pretty quickly.

Let the patrol stim the captain. The stim could reset a timer on the captain. If said timer exceeds a specific time limit (like 10 seconds in your case), the backup is send.

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

Is that approach going to allow someone to set different patrol durations as spawnargs on the ai_patrols? I'll take time to try and figure it out on my own if it does. If there's no getting around hardcoding things with that approach it'd be good to know now.

 

What I've done so far is pretty hacked together, but it does let you set a patrol duration spawnarg and it's to the point where it fires a function that'll pass the target0. It seems pretty close to fully working, but it's my first script so everything could be done in a stupid way.

tdm_ai_patrol.script.txt

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recent Status Updates

    • Petike the Taffer  »  DeTeEff

      I've updated the articles for your FMs and your author category at the wiki. Your newer nickname (DeTeEff) now comes first, and the one in parentheses is your older nickname (Fieldmedic). Just to avoid confusing people who played your FMs years ago and remember your older nickname. I've added a wiki article for your latest FM, Who Watches the Watcher?, as part of my current updating efforts. Unless I overlooked something, you have five different FMs so far.
      · 0 replies
    • Petike the Taffer

      I've finally managed to log in to The Dark Mod Wiki. I'm back in the saddle and before the holidays start in full, I'll be adding a few new FM articles and doing other updates. Written in Stone is already done.
      · 4 replies
    • nbohr1more

      TDM 15th Anniversary Contest is now active! Please declare your participation: https://forums.thedarkmod.com/index.php?/topic/22413-the-dark-mod-15th-anniversary-contest-entry-thread/
       
      · 0 replies
    • JackFarmer

      @TheUnbeholden
      You cannot receive PMs. Could you please be so kind and check your mailbox if it is full (or maybe you switched off the function)?
      · 1 reply
    • OrbWeaver

      I like the new frob highlight but it would nice if it was less "flickery" while moving over objects (especially barred metal doors).
      · 4 replies
×
×
  • Create New...