AI behaviour depending on player actions: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
No edit summary
Line 1: Line 1:
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.
I am going to describe the setup of a mission, in which the AI is neutral to the player as default. The AI only gets hostile to the player, if the player is seen performing 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
The first thing you have to do is to put all affected AI on one team. Let's just take team 1. So set the spawnarg "team" "1" on all affected AI and make sure non-affected AI are on a different team. Create a ''target_setrelation'' entity and set the following spawnarg on it: "rel 1,0" "0". This will cause the AI on 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);
   sys.trigger($nameof_target_setrelation);


included in your main function.
included in your main() script function.


== Being seen in an area where you aren't supposed to be ==
== 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 [http://wiki.thedarkmod.com/index.php?title=Ambient_Sounds,_a_zone_approach, 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:
The first thing you need to do is to make use of the zone system. This approach is described [http://wiki.thedarkmod.com/index.php?title=Ambient_Sounds,_a_zone_approach, here]. This system allows you to call functions when the player passes from one zone to another. Here we'll make use of the ''call_on_entry'' script function. The following has to be applied to all allowed/disallowed zones neighboring 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
''setNeutralZone'' on allowed zones
''setHostileZone'' on disallowed 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 ...  
The functions used here have to have the form '''void''' ''functionname''('''entity''' ''entityname''). The ''entity'' is the zone the player enters. As we don't need it here, but need the basic behavior for the weapon-based AI-player relation discussed below, they just call other functions with the same names without ''Zone'' at the end and no arguments passed. What they do is trigger the ''target_setrelation'' entities from the next section named ...  


== Beeing seen steeling something ==
== Caught stealing ==


This setup makes use of some triggers. You'll need: Two ''target_setrelation'' and one ''trigger_relay'' entity.
This makes use of some triggers. You'll need two ''target_setrelation'' entities 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).
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 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.
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''
''Note: alert state 5 is the highest alert state and means that the player was seen by an AI.''


What does the setup do?
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.
Every time you steal something the AI from team 1 will be set hostile to you for a certain amount of time. After that period they will become neutral to you again, unless they 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 to a higher value makes it more difficult and vice versa.


== Being seen carrying a weapon ==
== Being seen carrying a weapon ==


Basically you'll need the following script:
You'll need the following script:


   void CheckWeapon()
   void CheckWeapon()
Line 52: Line 52:
This function is started from the ''main'' method via  
This function is started from the ''main'' method via  


   thread checkWeapon();
   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.
The functions ''setNeutral'' and ''setHostile'' are the same as above. The script sets the AI to hostile as long as you carry a weapon. Again, being seen by any hostile AI will cause the hostility to be permanent.


== What is missing ==
== 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.
There are other situations in which the player could be seen 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 could be seen as a threat when discovered 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.  
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 you're not allowed to do, especially since you have the possibility of killing him and hiding 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.
Another point is that there is a delay on how long you can be detected after stealing something. Applying such a behavior to the other '''DONT'S''' may be useful.


This needs fixing and I will add solutions once I have them.
This needs fixing and I will add solutions once I have them.
Line 68: Line 68:
== Summary ==
== 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).
Now that we have all the pieces together, let's sum up how to set up the complete behavior. (We are starting from zero here; nothing has been done so far).


We need:
We need:
Line 76: Line 76:
One ''trigger_relay'' entity called '''relay'''
One ''trigger_relay'' entity called '''relay'''


A script file called ''mymapname''.script, where ''mymapname''.map is the name of your map file.
A script file called ''mymapname''.script, where ''mymapname'' is the name of your map.
 
An invisible objective "If one AI of team 1 get to alert level 5"


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


----
----


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


On all affected AI set "team" "1". Non-affected AI goes to another team
On '''makeHostile''' set "rel 1,0" "-1".
 
On '''makeHostile''' set "rel 1,0" "-1"
 
On '''makeNeutral''' set "rel 1,0" "0"


On '''relay''' set "target" "makeNeutral" and "delay" "1"
On '''makeNeutral''' set "rel 1,0" "0".


On the objective put ''stayHostile'' in the '''success script''' field
On '''relay''' set "target" "makeNeutral" and "delay" "1".


On '''all''' objects that are not allowed to be taken by the player set "target" "makeHostile" and "target0" "relay"
On the objective put ''stayHostile'' in the '''success script''' field.


On '''all''' ''info_location'' entities belonging to zones where the player is not allowed to be set "call_on_entry" "setHostileZone"
On '''all''' objects that are not allowed to be taken by the player set "target" "makeHostile" and "target0" "relay".


Do the same for '''all''' other ''info_location'' entities but with the method "setNeutralZone"
On '''all''' ''info_location'' entities belonging to zones where the player is not allowed to be, set "call_on_entry" "setHostileZone".


''Hint: The last two steps can be restricted to zones neighbouring zones of the other kind''
Do the same for '''all''' other ''info_location'' entities but use the method "setNeutralZone".


On '''any''' worldspawn set "target" "makeNeutral"
''Hint: The last two steps can be restricted to zones neighboring zones of the other kind''.


On '''any''' worldspawn set "target" "makeNeutral".


----
----


In the script file include
In the script file include
Line 126: Line 122:
     $makeNeutral.remove();
     $makeNeutral.remove();
   }
   }
   void checkWeapon() {
   void CheckWeapon() {
     do {
     do {
       if ($player1.getCurrentWeapon()=="atdm:weapon_unarmed") {
       if ($player1.getCurrentWeapon() == "atdm:weapon_unarmed") {
         setNeutral();
         setNeutral();
       }
       }
Line 138: Line 134:
   }
   }
   void main() {
   void main() {
     thread checkWeapon();
     thread CheckWeapon();
   }
   }


That's it. If you want to make the detection time for stealing things difficulty dependent, add the following spawnargs on '''relay''':
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_change_0" "delay"
Line 148: Line 144:
"diff_2_arg_0" "2.0"
"diff_2_arg_0" "2.0"


Of course you can use other times then mentioned here.
Of course, you can use other times than mentioned here.


--[[User:Obsttorte|Obsttorte]] ([[User talk:Obsttorte|talk]]) 11:18, 2 January 2013 (EST)
--[[User:Obsttorte|Obsttorte]] ([[User talk:Obsttorte|talk]]) 11:18, 2 January 2013 (EST)

Revision as of 19:41, 2 January 2013

I am going to describe the setup of a mission, in which the AI is neutral to the player as default. The AI only gets hostile to the player, if the player is seen performing 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 affected AI on one team. Let's just take team 1. So set the spawnarg "team" "1" on all affected AI and make sure non-affected AI are on a different team. Create a target_setrelation entity and set the following spawnarg on it: "rel 1,0" "0". This will cause the AI on 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() script 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 passes from one zone to another. Here we'll make use of the call_on_entry script function. The following has to be applied to all allowed/disallowed zones neighboring 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 the player enters. As we don't need it here, but need the basic behavior for the weapon-based AI-player relation discussed below, they just call other functions with the same names without Zone at the end and no arguments passed. What they do is trigger the target_setrelation entities from the next section named ...

Caught stealing

This makes use of some triggers. You'll need two target_setrelation entities 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 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?

Every time you steal something the AI from team 1 will be set hostile to you for a certain amount of time. After that period they will become neutral to you again, unless they 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 to a higher value makes it more difficult and vice versa.

Being seen carrying a weapon

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 sets the AI to hostile as long as you carry a weapon. Again, being seen by any hostile AI will cause the hostility to be permanent.

What is missing

There are other situations in which the player could be seen 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 could be seen as a threat when discovered 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 you're not allowed to do, especially since you have the possibility of killing him and hiding 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 behavior to the other DONT'S may be 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 how to set up the complete behavior. (We are starting from zero 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 is the name of your map.

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


On all affected AI set "team" "1". Non-affected AI go 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 use the method "setNeutralZone".

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

On any worldspawn set "target" "makeNeutral".


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 than mentioned here.

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