AI behaviour depending on player actions

From The DarkMod Wiki
Revision as of 16:18, 2 January 2013 by Obsttorte (talk | contribs) (This article describes the setup of AI that is neutral to the player until he does something illegal)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

I am going to describe the setup of a mission, in which the AI is neutral to the player as default. It only gets hostile to him, if he is seen by an illegal action. Such actions include: Being seen in an area where the player isn't supposed to be, stealing loot or carrying a weapon.

The first thing you have to do is to put all AI who should be affected into one team. Let's just take team 1. So set the spawnarg "team" "1" on all affected AI and make sure possible other AI are in a different team. Create a target_setrelation entity and set the following spawnarg on it: "rel 1,0" "0". This will cause the AI in team 1 to see the player (team 0) as neutral (0). Target this entity from a worldspawn brush or trigger it via the command

 sys.trigger($nameof_target_setrelation);

included in your main function.

Being seen in an area where you aren't supposed to be

The first thing you need to do is to make use of the zone system. This approach is described here. This system allows you to call functions when the player enters from one zone to an other. Here we'll make use of the call_on_entry script function. The following setup has to be applied on all allowed/disallowed zones neighbouring each other. On the info_location entities belonging to the zones set the spawnarg "call_on_entry" "functionname", where functionname is:

setNeutralZone on allowed zones setHostileZone on disallowed zones

The functions used here have to have the form void functionname(entity entityname). The entity is the zone where the player enters. As we don't need it here but need the basic behavior for the weapon-based AI-player relation further below, they just call other functions with the same names without Zone at the end and no arguments passed. What they do is to trigger the target_setrelation entities from the next section named ...

Beeing seen steeling something

This setup makes use of some triggers. You'll need: Two target_setrelation and one trigger_relay entity.

On the first target_setrelation entity set the spawnarg "rel 1,0" "-1", on the second set "rel 1,0" "0". Let the trigger_relay target the second target_setrelation entity and set the spawnarg "delay" "T" on the trigger_relay, where T specifies the timespan in which the player is detected as hostile after stealing something (see description further below).

Now let every item that the player is not allowed to take target both the first target_setrelation and the trigger_relay entity. The next thing you need to do is to set up a hidden objective with the content "If one AI of team 1 goes to alert state 5". In the success script field enter isHostile. This function will then destroy the second target_setrelation entity, so the AI stays hostile to the player.

Note: alert state 5 is the highest alert state and means, that the player was seen by an AI

What does the setup do?

Everytime you steal something the AI from team 1 will be set hostile to you for a certain amount of time. After that period the will become neutral again to you, unless the see you within this amount of time. If so, they'll stay hostile. As you can see the amount of time (called T above) has an impact on how difficult it is for the player to get away with disallowed actions. Setting it on a higher value makes it more difficult and vice versa.

Being seen carrying a weapon

Basically you'll need the following script:

 void CheckWeapon()
 {
       do
       {
               if ($player1.getCurrentWeapon() == 'atdm:weapon_unarmed')
               {
                       setNeutral();
               }
               else
               {
                       setHostile();
               }
               sys.wait(1);
       } while(true); 
 }

This function is started from the main method via

 thread checkWeapon();

The functions setNeutral and setHostile are the same as above. The script set the AI to hostile as long as you carry a weapon. Again, being seen by any hostile AI will cause the hostility to stay.

What is missing

There are some other situations in which the player would be counted as a threat. For example if he is seen attempting to pick a door or opening one that is normally locked by a key the player isn't suppose to have. Also the player should be counted as threat when being seen carrying a body.

In addition, it is also not very realistic that all the AI in Team 1 will become your enemies once one AI has seen you doing something your not allowed to, especially as you have the possibility to kill him and hide him without being seen.

Another point is that there is a delay on how long you can be detected after stealing something. Applying such a behaviour to the other DONT'S may be a useful.

This needs fixing and I will add solutions once I have them.

Summary

Now that we have all the pieces together, let's sum up on how to set up the complete behaviour. (We are starting from ero here, nothing has been done so far).

We need:

Two target_setrelation entities called makeHostile and makeNeutral

One trigger_relay entity called relay

A script file called mymapname.script, where mymapname.map is the name of your map file.

An invisible objective "If one AI of team 1 get to alert level 5"




On all affected AI set "team" "1". Non-affected AI goes to another team

On makeHostile set "rel 1,0" "-1"

On makeNeutral set "rel 1,0" "0"

On relay set "target" "makeNeutral" and "delay" "1"

On the objective put stayHostile in the success script field

On all objects that are not allowed to be taken by the player set "target" "makeHostile" and "target0" "relay"

On all info_location entities belonging to zones where the player is not allowed to be set "call_on_entry" "setHostileZone"

Do the same for all other info_location entities but with the method "setNeutralZone"

Hint: The last two steps can be restricted to zones neighbouring zones of the other kind

In the script file include

 void setHostileZone(entity zone) {
   setHostile();
 }
 void setNeutralZone(entity zone) {
   setNeutral();
 }
 void setHostile() {
   sys.trigger($makeHostile);
 }
 void setNeutral() {
   sys.trigger($makeNeutral);
 }
 void stayHostile() {
   setHostile();
   $makeNeutral.remove();
 }
 void checkWeapon() {
   do {
     if ($player1.getCurrentWeapon()=="atdm:weapon_unarmed") {
       setNeutral();
     }
     else {
       setHostile();
     }
     sys.wait(1);
   } while(true);
 }
 void main() {
   thread checkWeapon();
 }

That's it. If you want to make the detection time for stealing things difficulty dependent, add the following spawnargs on relay:

"diff_1_change_0" "delay" "diff_1_arg_0" "1.5" "diff_2_change_0" "delay" "diff_2_arg_0" "2.0"

Of course you can use other times then mentioned here.

--Obsttorte (talk) 11:18, 2 January 2013 (EST)