AI: Difference between revisions

From OniGalore
Jump to navigation Jump to search
m (link fixes)
m (wording tweaks around chenille vs. supershield; is it true that Mutant Muro's supershield goes away if he switches away from his melee behavior?)
 
(22 intermediate revisions by 2 users not shown)
Line 1: Line 1:
==Foreword==
An action game like Oni needs artificial intelligence-driven characters ("AIs" or "bots") and some sort of interaction amongst these characters and between them and the world. The goal is to make an AI act at least a bit like a human being. That means giving the AI abilities such as moving in the game world believably, and seeing, hearing, and reacting to events in the game world. Different games deal with these problems in various ways, but in this article, we will take a look at Oni and its AI.
Motivational video: http://www.youtube.com/watch?v=8Okn7u_-oVs


An action game like Oni needs artificial intelligence driven characters ("bots") and some sort of interaction between these characters and between the character and world. The goal is to make AI look at least a bit like human being with its behavior resembling real life humans. That means giving the A.I. abilities such as moving in the game world believeably or see, hear and react on events in the game world. Different games deal with these probles in various ways, but in this article, we will take a look at Oni and its A.I.
This page serves two purposes: to give an overview of Oni's AI and to help modders with AI tweaking.


This page serves two purposes - to give an overview of Oni A.I. and to help modders with A.I. tweaking.
==Pathfinding and movement==
[[Image:Pathfinding grid.jpg|thumb|right|alt=Example of a pathfinding grid.|An example of a pathfinding grid.]]
[[Image:Ai2 showastar2.png|thumb|right|alt=Example of an A*.|An example of the A* algorithm's work: nodes chosen as a path for AI are highlighted.]]
Oni has two ways to make an AI move in a game world - pathfinding, and what could be called vector-based.


==Pathfinding and movement - "I think I will consult a map for a while..."==
'''Pathfinding''' is used when AI-driven character needs to travel from one place to another. Examples of pathfinding movement are:
[[File:Pathfinding grid.JPG|thumb|right|alt=Example of a pathfinding grid.|An example of a pathfinding grid.]]
:*patrol paths - AI-driven character moves in a pre-designed fashion (see [[PATR]])
[[File:Ai2 showastar2.png|thumb|right|alt=Example of an A*.|An example of the A* algorithm's work: nodes chosen as a path for A.I. are highlighted.]]
:*alarm running - AI character is requested to go to given console and use it, see section [[#Alarm behavior|Alarm behavior]]
Oni A.I. has two ways how to make A.I. move in a game world - pathfinding-based and ???vector-based??? (needs proper term).
:*pursuit of target - AI character loses direct sight of the enemy, see section [[#Pursuit|Pursuit]]
:*running to weapons in order to pick them up, see [[#Extra combat behaviors|Extra combat behaviors]]


'''Pathfinding''' is used when A.I. driven character needs to traverse in level from one place to another. Examples of pathfinding-based A.I. movement are:
:Pathfinding utilizes an [[wikipedia:A*_search_algorithm|A* (A-star)]] algorithm to design routes for AI within the game world.
:*patrol paths - A.I. driven character moves in a pre-designed fashion, see [[PATR]]
:*alarm running - A.I. character is requested to go to given console and use it, see section [[#Alarm behavior - "She's everywhere!"|Alarm behavior]]
:*pursuit of target - A.I. character loses direct sight of the enemy, see section [[#Pursuit of enemy alias "I will find you..."|Pursuit of enemy]]
:*running to weapons in order to pick them up, see '''LINK TO COMBAT BEHAVIOR'''


:Pathfinding utilizes an [http://en.wikipedia.org/wiki/A*_search_algorithm A* (A-star)] algorithm to design route for A.I. within the game world.
:Human players see walls and obstacles placed between their current location and their desired location, thus they can plan their route thanks to the best computer so far known to man -- the human brain. The AI, on the other hand, has to be told where it can go and where it cannot (a wall, a pit, an obstacle, etc.). Since the A* is a chart-searching algorithm, there is a need to have some sort of chart, conveniently mapping the environment for AI purposes. And that is a '''pathfinding grid''', which can be seen in-game by entering '''ai2_showgrids = 1''' (see picture on right).


:Human players see walls and obstacles placed in a way between current location and goal location, thus they can adapt their behavior thanks to the best computer so far known to a man - human brain. The A.I. on the other side has to be told where it can go and where it cannot (wall, pit, obstacle etc). Since the A* is a chart search algorithm, there is a need to have some sort of chart, conveniently mapping the environment for A.I. purposes. And that is '''pathfinding grid''', which can be seen ingame by activating '''ai2_showgrids = 1''' (see picture on the right).
:If an AI has to travel through the level by pathfinding, then a "mark" is set at the final destination and the "chart" mentioned above is consulted to get the shortest available route. After this process, the AI is continually fed with "traversal nodes" -- temporary marks placed in the part of the pathfinding grid which the AI is currently running through. An AI will simply run directly towards each mark, so when an AI needs to turn a corner, a number of these nodes have to be generated in order to make the AI run around the corner.


:If A.I. has to travel in the level and pathfinding is used, then a "mark" is set at the final destination and the "chart" mentioned above is consulted to get the shortest available route. After this process, the A.I. is continually fed with "traversal nodes" - temporary marks set in AKVAs A.I. is currently running through. Artificial Intelligence keeps running directly towards these marks, so when A.I. needs to turn around the corner, a number of these nodes are generated in order to make A.I. turn the corner.
:Pathfinding grids are tied to [[AKVA]]s and are loaded into memory only for the period of time that they serve some purpose (i.e., when the character is inside the AKVA volume). More detailed info about various types of pathfinding grid tiles and their effects on pathfinding can be found [[OBD talk:AKVA/0x24|here]].


:Pathfinding grids are tied to [[AKVA]]s and are loaded into memory only for the time when they serve some purpose (character is inside the AKVA volume). More detailed info about various types of pathfinding grid tiles and their effects on pathfinding can be found at [[OBD talk:AKVA/0x24]].
:There was a short-lived modding initiative to alter pathfinding grids manually, but it failed due to the extreme amount of labor required. These days, [[OniSplit]] can import levels and generate pathfinding grids.


:There used to be a short modding initiative to alter pathfinding grids manually, but it deceased due to extreme amount of labor required to do so. Currently, [[OniSplit]] can import levels and generate pathfinding grids.




:Modding hints: if an AI has to turn a sharp corner, the pathfinding still picks the shortest route possible. This usually results in the AI having problems turning corners at full running/sprinting speed -- the AI stops at the corner, turns, runs past the corner, turns again to finish the path, and continues on its way. This is caused by the limited rotation speed assigned to the character in his [[ONCC]].


:Modding hints: if A.I. has to turn sharp corners, pathfinding still picks the shortest route possible. That usually results in A.I. having problems with turning corners at full running/sprinting speed - A.I. stops at corner, turns, runs past the corner, turns again to finish it and continues on its way. That is caused by low Rotation speed assigned to the character in his [[ONCC]] file.
:In an ONCC XML file there is a '''<RotationSpeed>''' under '''<AIConstants>'''. The default is 1, but 1.5 works way better without causing any visible negative influence on the game. A rotation speed of 2.0 is the maximum recommended because the pathfinding in the game is designed for a speed of 1.0, so with a much higher rotation rate comes the [[User:Paradox-01|paradox]] that new problems in pathfinding may appear, instead of issues being erased (mainly the AI colliding with obstacles).


:In ONCC xml file there is '''<RotationSpeed>''' under '''<AIConstants>'''. Default is 1, but 1.5 works way better without causing any visible negative influence on the game. Rotation speed 2.0 is recommended to be the maximal because the pathfinding in the game is designed for speed 1.0 and with such a high rotation rate there raises a [[User:Paradox-01|paradox]] as new problems in pathfinding may appear instead of issues being erased (mainly A.I. colliding with obstacles).




'''Vector-based''' movement is used when an AI-driven character:
:*enters close combat state and begins to use melee
:*is dodging gunfire, be it firing spreads or projectiles
:*is asked to run away from an enemy by a special setting in their [[CMBT]] profile


???'''Vector'''??? movement is used when
:In this mode, an AI is not given an exact destination. Instead it is given a "desire" to go in some direction. This mode still uses the pathfinding grid, however in a bit of a different way than pathfinding does, so glitches occur, mainly unexpected collisions and ignored tiles (e.g., an AI runs off a ledge and falls to its death).
:*A.I. driven character enters close combat state and goes into melee
:*A.I. driven character is dodging gunfire, be it firingspreads or projectiles
:*A.I. driven character is requested to run away from enemy by special setting in [[CMBT]] profile


:In this mode A.I. is not given exact destination where to move. Instead it is given a "desire" to go to some direction. This mode still uses pathfinding grid, however in a bit different way than pathfinding does so glitches occur, mainly unexpected collisions and ignored tiles (A.I. runs over the edge and falls down to its death).


'''Unexpected Collision''' movement happens when an AI runs on its own towards some destination and suddenly hits an obstacle. Ideally that should never happen, as the pathfinding grid is designed to prevent it, but still... when a collision happens, the game decides what to do according to which method is being used to move the character:
:*Pathfinding: the game makes the AI take a few steps back, rotate a bit, and lets the AI continue its journey. There is a limit to how many unexpected collisions an AI can undergo before it gives up on its destination as unreachable.
:*Vector-based: according to the angle at which the AI is facing the obstacle, the game decides either to let the character slide along the obstacle or to stop the character completely until the angle of the AI's vector of movement changes.


'''Unexpected Collision''' movement happens when A.I. runs on its own towards some destination and suddenly hits an obstacle. Ideally that should never happen as pathfinding grid should prevent it, but still...Anyway, when collision happens, the game decides what to do according to actually selected way how to move a character:
==Vision and hearing==
:*Pathfinding -  the game makes A.I. do a few steps back, rotate a bit and lets the A.I. continue its journey. There is limit of how many unexpected collisions can A.I. undergo before it gives up its destination as unreachable.
[[Image:VisionFields.jpg|thumb|right|alt=Visualization of vision fields.|An example of a blue Striker's central and peripheral vision.]]
:*???Vector??? - according to the angle between A.I.'s facing and obstacle the game decides either to let the character slide along the obstacle or to stop the character completely until direction of the A.I.'s vector of movement changes.
[[Image:SoundSpheres.jpg|thumb|right|alt=Visualization of sound spheres.|Three examples of sound spheres.]]
When emulating humans with AI, senses have to be taken into an account: sight, hearing, taste, smell, touch. Unfortunately, Oni emulates only sight and hearing.


==Congitive possiblities of A.I. characters ... "COME TO YOUR SENSES!"==
'''Sight''' is important. Without it, the only option for AI to recognize an enemy would be getting attacked by the enemy first. Unlike the majority of action games, Oni AIs have two kinds of vision:
[[File:VisionFields.JPG|thumb|right|alt=Visualization of vision fields.|An example of Blue Striker's central and peripheral vision.]]
:*Central: an enemy seen by central vision will be recognized and attacked
[[File:SoundSpheres.JPG|thumb|right|alt=Visualization of sound spheres.|Three examples of sound spheres.]]
:*Peripheral: an enemy seen by peripheral vision will raise the AI's alert level to low and the AI will go into pursuit of the enemy; see [[#Pursuit|Pursuit]] section
When talking about life-like A.I., senses have to be taken into an account. Sight, hearing, taste, smell, touch. Unfortunately Oni emulates only sight and hearing.


'''Sight''' is important. Without it the only option for A.I. to recognize the enemy is to be attacked by the enemy first. Unlike majority of action games, Oni A.I. characters have two visions:
:Modding hints: the parameters of the vision fields are stored in ONCC, under '''<VisionConstants>'''. The central vision field distance has to be greater than the peripheral vision field distance, otherwise peripheral vision detection will somehow be broken (it will not detect). Since peripheral vision makes the AI pursue the enemy but not attack it, it can be set quite large in order to surprise lousy stealth players. But be warned: nobody likes cheating AI ^_^.
:*Central - enemy seen by central vision = enemy recognized and attacked.
:*Peripheral - enemy seen by peripheral vision = alert risen to low and A.I. goes into pursuit mode with given enemy, see '''LINK TO PURSUIT'''




Modding hints - parameters of vision fields are stored in ONCC, under '''<VisionConstants>'''. Central vision field distance has to be greater than peripheral vision field distance, otherwise peripheral vision detection will be somehow broken (it will not detect). Since peripheral vision makes A.I. pursue the enemy but not attack it, it can be set quite large in order to surprise lousy stealth players. But be warned - nobody likes cheating A.I. ^_^.


'''Hearing''' is crucial in Oni. The majority of AI character interaction is done via the sound system. Oni recognizes these types of sound (colors in parentheses are used for sound visualization when [[ai2_showsounds]] is set to 1):
:*Unimportant (blue) - is ignored to some extent if alert level of AI is "lull", but after some period of time, the AI will register it.
:*Interesting (green) - raises alert level to "low"
:*Danger (yellow) - raises alert level to "medium"
:*Melee (orange) - raises alert level to "medium", but the AI reacts a bit differently than to a Danger sound
:*Gunfire (red) - raises alert level to "high"


:For more info about AI alert levels, see section [[#Reactions and awareness|Reactions and awareness]]. These sound types are used by impact effects ([[ONIE]]), and a danger sound type can be set in a particle's as part of its "danger radius".


'''Hearing''' is crucial in Oni. Majority of A.I. character interaction is done via sound system. Oni recognizes these types of sound (in brackets visualization when '''ai2_showsounds''' is set to 1):
:For a video illustration of AI hearing, see [https://www.youtube.com/watch?v=LxX5dbYGZow this video].
:*Unimportant (blue) - is ignored to some extent if alert level of A.I. is lull, but after some period of time A.I. will register it.
:*Interesting (green) - causes alert rise to low level.
:*Danger (yellow) - causes alert rise to medium level.
:*Melee (orange) - causes alert rise to medium level but A.I. reacts a bit differently than in case of Danger sound.
:*Gunfire (red) - causes alert rise to high level.


:For more info about A.I. alert levels, see section [[#Reactions on stimuli a.k.a. "What was that?!"|Reaction on stimuli]]. These sound types are used by impact effects [[ONIE]] and danger sound type can be set in particle as a "danger radius".
:Modding hints: The sound system and ONIE are mighty tools if a modder knows how to use them. Even doors can have attached to them a sound sphere of one of the types listed above, so a modder can create doors which draw the attention (sound type Interesting) of nearby AIs when those doors are used.


:Another example is a workaround for AIs to get alerted by dead bodies: set the death particle in the ONCC to emit a custom impact effect. That impact effect will have no sound or effect attached, but will be set to be heard by AIs as gunfire within a large radius (say, 200 units).


:Modding hints: Sound system and ONIE are mighty tools if modder knows how to use them. Even doors can be attached a sound sphere of any one of those listed above, so a modder can create doors which draw attention (sound type interesting) of nearby A.I. characters if these doors are manipulated.
==Reactions and awareness==
In real life, each human being is unique in its reactions. But even then, reactions differ with mood; when calm or when nervous or when suspicious, a man does not always react the same way. And what about Oni?


:Another example is a workaround for A.I. to get alerted by dead bodies -
In Oni, reaction to a stimulus is based on the type of stimulus (see previous section) and on the alert level of the AI. Oni AIs have these alert levels:
::Set dead particle in ONCC to be one special custom made - this particle will for given time keep emiting custom impact effect. That custom impact effect will have no sound or effect attached, but will be set to be hearable by A.I. as a gunfire within a large radius (200 units).
 
 
==Reactions on stimuli a.k.a. "What was that?!"==
In real life each human being is unique with its reactions. But even then reaction differ - when calm or when nervous or when suspicious, a man does not always react the same way. And what about Oni?
 
In Oni, reaction on stimulus is based on type of stimulus (see previous section) and on level of AI alert level. Oni A.I. characters have these alert levels:
:*Lull
:*Lull
:*Low
:*Low
Line 87: Line 82:
:*Combat
:*Combat


:Level of alert can be set via BSL as '''ai2_setalert''' ''ai_name/chr_index'' '''desired level of alert'''. Levels of alert play the role of "behavior modifier". Artificial Intelligence reacts on seen or heard allies/enemies according to its own level of alert. Level of alert can be increased by:
:The level of alert for an AI can be set via BSL using [[ai2_setalert]]. Alert levels play the role of "behavior modifier" in how an AI reacts to seeing or hearing allies and enemies. Alert levels can be increased in the following ways:
:*hearing a sound which causes rise of alert level (for detailed info read previous section)
:*hearing a sound which raises alert level (for detailed info, read previous section)
:*special rise of alert level from Lull to Low is by enemy being seen by peripheral vision or by enemy causing too many unimportant sounds
:*a special rise from Lull to Low can come from an enemy being seen by peripheral vision or by an enemy causing too many Unimportant sounds
:*special rise of alert level to Combat is by being hit by the enemy or by alarm being triggered (see [[OBD:BINA/OBJC/CONS]]) or by script functions '''ai2_tripalarm''', '''ai2_makeaware''' or '''ai2_attack''' (see [[BSL:Functions]]).
:*a special rise to Combat level will come from being hit by the enemy or by an alarm being triggered (see [[OBD:BINA/OBJC/CONS]]), or by the scripting functions [[ai2_tripalarm]], [[ai2_makeaware]] or [[ai2_attack]].


:Alert level also affects movement mode of A.I. driven characters. There are six movement modes - creep, walk, walk_noaim, run, run_noaim, by_alert_level. Those "_noaim" movement modes are forcing A.I. character to not aim with weapon in case the A.I. is armed (so A.I. character walks or runs with the gun in hand but it does not aim with it). Movement mode can be forced via bsl command '''ai2_setmovementmode'''. Alert level affects movement mode only if movement mode is set as '''by_alert_level'''. In that case:
:Alert level also affects the movement mode of AI-driven characters. There are six movement modes: "creep", "walk", "walk_noaim", "run", "run_noaim", and "by_alert_level". The "*_noaim" movement modes tell the AI that, if it is armed, it should walk or run with the gun in hand but not aim with it. Movement mode can be forced via the BSL command [[ai2_setmovementmode]]. Alert level affects movement mode only if movement mode is set as "by_alert_level". In that case:
:* Lull and Low alerts use walk_noaim
:*Lull and Low alerts use "walk_noaim"
:* Medium, High and Combat use run
:*Medium, High and Combat use "run"


:If patrol path ([[PATR]]) is assigned to a character, it can override movement mode for patrol path purposes and for example force Lull alert character to run with aimed weapon. However, when A.I. is disturbed and starts pursuit of ally/enemy, movement mode is then chosen by coresponding alert level (given the fact the movement mode is set as '''by_alert_level''').
:If a patrol path ([[PATR]]) is assigned to a character, it can force a Lull-alerted character to run with an aimed weapon. However, when the AI becomes aware of and starts its pursuit of an ally/enemy, the movement mode is then dictated by its alert level (if the movement mode is set as '''by_alert_level''').
:Level of alert can decrease via BSL ai2_setalert or with time , exact location of timers unknown (maybe hardcoded).
:An alert level can be decreased via BSL's ai2_setalert or with the passage of time (the location of the timer settings is unknown, maybe hardcoded).






Next component of A.I. reaction logic is its '''awareness''' of ally/enemy. Oni recognizes between ally (friendlythreat) and enemy (hostilethreat). Oni A.I. characters always know whether the disturbance was caused by ally or enemy. That means if player is playing as standard Konoko, shoots and some Striker gets alerted, the Striker knows which character (from [[CHAR]]) shot, which team does the character belong to and according to it the Striker reacts (but more about it later). Oni defines four levels of awareness:
The next component of the AI's reaction logic is its '''awareness''' of the ally/enemy. Oni distinguishes between allies ("friendlythreat") and enemies ("hostilethreat"). Oni's AIs always know whether a disturbance was caused by an ally or enemy. That means that if player is playing as Konoko and shoots, alerting some Striker, the Striker knows which character (from [[CHAR]]) shot and which team the character belongs to, and reacts accordingly (but more about that later). Oni defines four levels of awareness:
:'''firendlythreat'''
:'''friendlythreat'''
:*Definite - A.I. is 100% sure where ally stands and ignores him. Is achieved by seeing the ally with central vision field or by being hit by his gun by accident or by being told of its presence by BSL commands ai2_makeaware, ai2_tripalarm or ai2_attack.
:*Definite: the AI is 100% sure where the ally is located and ignores him. Is achieved by seeing the ally with the central vision field, being hit by his gun by accident, or being told of the ally's presence by the BSL function ai2_makeaware, ai2_tripalarm or ai2_attack.
:*Strong - A.I. has strong awareness of ally presence, but cannot pinpoint exact location of the ally character itself. Is caused by all sound types, which are described in previous section. Also if ally is off central vision field and <FriendlyThreatDefiniteTimer> runs out, A.I. decreases level of awareness from definite to strong.
:*Strong: the AI has a strong awareness of an ally's presence, but cannot pinpoint the exact location of the ally. Is caused by all sound types, which are described in previous section. If the ally is outside the central vision field and <FriendlyThreatDefiniteTimer> runs out, the AI decreases its level of awareness from Definite to Strong.
:*Weak - A.I. has weak awareness of the character's presence. It is caused either by seeing ally with peripheral vision or by <FriendlyThreatStrongTimer> running out.
:*Weak: the AI has a weak awareness of the ally's presence. It is caused either by seeing an ally with peripheral vision or by <FriendlyThreatStrongTimer> running out.
:*Forgotten - A.I. has ecountered some ally, but over time forgot about its presence. <FriendlyThreatWeakTimer> ran out.
:*Forgotten: the AI encountered some ally, but over time forgot about its presence (<FriendlyThreatWeakTimer> ran out).


:'''hostilethreat'''
:'''hostilethreat'''
:*Definite - A.I. is 100% sure where enemy stands and will go attack her/him. Is achieved by seeing the enemy with central vision field or by being hit by her/him (or her/his gun) or by being told of its presence by BSL commands ai2_makeaware, ai2_tripalarm or ai2_attack.
:*Definite: the AI is 100% sure where the enemy is located, and will go attack her/him. Is achieved by seeing the enemy with its central vision field, being hit by her/him (or her/his gun), or being told of the enemy's presence by the BSL function ai2_makeaware, ai2_tripalarm or ai2_attack.
:*Strong - A.I. has strong awareness of enemy presence, but cannot pinpoint exact location of the enemy character itself. Is caused by all sound types, which are described in previous section. If enemy manages to get is off central vision field and <HostileThreatDefiniteTimer> runs out, A.I. decreases level of awareness from definite to strong. If A.I. is allowed to investigate, corresponding pursuit behavior is excuted (more about this later).
:*Strong: the AI has a strong awareness of an enemy's presence, but cannot pinpoint the exact location of the enemy. Is caused by all sound types, which are described in previous section. If enemy manages to out of an AI's central vision field and <HostileThreatDefiniteTimer> runs out, the AI decreases its level of awareness from Definite to Strong. If the AI is allowed to investigate, the corresponding pursuit behavior is executed (more about this later).
:*Weak - A.I. has weak awareness of enemy's presence. It is caused either by seeing enemy with peripheral vision or by <HostileThreatStrongTimer> running out. If A.I. is allowed to investigate, corresponding pursuit behavior is excuted (more about this later)
:*Weak: the AI has a weak awareness of an enemy's presence. It is caused either by seeing an enemy with peripheral vision or by <HostileThreatStrongTimer> running out. If the AI is allowed to investigate, the corresponding pursuit behavior is executed (more about this later)
:*Forgotten - A.I. has ecountered some enemy, but over time forgot about its presence. <EnemyThreatWeakTimer> ran out.
:*Forgotten: the AI encountered an enemy, but over time forgot about its presence (<EnemyThreatWeakTimer> ran out).
 
:When A.I. character is freshly spawned, it does not have any contact with other characters (Tabula Rasa). Through sounds and vision, A.I. learns about presence of other characters and reacts on them according to team affiliation, alert level and awareness. Even when A.I. character "forgets" about ally/enemy, it does not completely abandon their existence. For example startle behavior when A.I. character sees an enemy is played only once vs this particular enemy. Even when A.I. character forgets, it won't play startle animation next time it sees this one enemy, but goes directly attack him.
:Friendly warning: awareness "Forgotten" '''IS NOT''' equal to '''ai2_forget''' command. "Ai2_forget" clears A.I. character's memory back to Tabula Rasa status.


:When an AI character is freshly spawned, it does not have any record of contact with other characters (a ''tabula rasa''). Through hearing and vision, an AI learns about the presence of other characters and reacts to them according to team affiliation, alert level, and awareness level. Even when an AI character ceases to be aware of an ally/enemy, it does not completely forget them. For example, the startle behavior when an AI sees an enemy is played only once for this particular enemy; it won't play the startle animation the next time it sees him, but will go directly to attacking him.
:Friendly warning: the awareness level "Forgotten" '''IS NOT''' equivalent to the result of the '''ai2_forget''' command. "Ai2_forget" actually sets the AI's memory back to ''tabula rasa'' status.




==Pursuit of enemy alias "I will find you..."==
Everything that was needed was explained in section above so let's take a look at '''pursuit''' behavior. Pursuit behavior in Oni emulates the situation when a man knows "somebody is here", but does not see anybody.


Oni deals with this problem by using pursuit behaviors. In Oni there are following types of '''pursuit''' behavior:
==Pursuit==
:*None - simply nothing
Now that alert and awareness levels have been covered, let's take a look at '''pursuit''' behavior. Pursuit behavior in Oni emulates the situation when a person knows "somebody is here", but does not see anybody. In Oni there are following types of '''pursuit''' behavior:
:*Forget - A.I. goes into forgotten awareness with this enemy
:*None: No pursuit taking place
:*GoTo - A.I. moves to the source of distrubance and executes timer-based 600 frames Look behavior (600 frames = 10 seconds)
:*Forget: the AI drops to the Forgotten level of awareness of this enemy
:*Wait - A.I. simpy stands and waits
:*GoTo: the AI moves to the source of the disturbance and performs 600 frames (10 seconds) of Look behavior
:*Look - A.I. rotates on spot and looks all around
:*Wait: the AI simply stands and waits to see/hear something more
:*Move - unimplemented, probably was meant to be similar to Look, but with character randomly moving around
:*Look: the AI turns in place, looking all around
:*Hunt - unimplemented, probably was meant to make A.I. purposefully look around for the enemy
:*Move: unimplemented; probably was meant to be similar to Look, but with character randomly moving around
:*Glance - A.I. does not rotate whole body, only rotates its head
:*Hunt: unimplemented; probably was meant to make AI purposefully hunt around for the enemy
:*Glance: the AI does not rotate its whole body, but only turns its head


Plus there are three types of '''lost''' behavior (when A.I. has definite contact with enemy but enemy manages to get away)
Plus there are three types of '''lost''' behavior (when an AI had definite contact with the enemy but the enemy managed to get away):
:*ReturnTo Job - A.I. returns to its job
:*ReturnTo Job: the AI returns to its job
:*KeepLooking - A.I. does not return to its job but keeps using the last used pursuit behavior
:*KeepLooking: the AI does not return to its job, and keeps using the last used pursuit behavior
:*FindAlarm - A.I. tries to switch to alarm behavior (see section [[#Alarm behavior - "She's everywhere!"|Alarm behavior]]), if it does not suceed, A.I. returns to its job.
:*FindAlarm: the AI tries to switch to alarm behavior (see section [[#Alarm behavior|Alarm behavior]]); if it does not succeed, then it returns to its job.






In Oni, a character which is spawned in the level is a character profile from [[CHAR]] file. This CHAR profile contains links to:
In Oni, a character is spawned in the level from a character profile (a [[CHAR]] file). This CHAR profile contains links to:
:*[[ONCC]] file - character class, eg. Konoko or Comguy_1
:*[[ONCC]] file, for character class, eg. Konoko or Comguy_1
:*[[CMBT]] file - combat profile for this character
:*[[CMBT]] file, for the combat profile for this character
:*[[MELE]] file - melee profile  for this character
:*[[MELE]] file, for the melee profile  for this character
:*[[PATR]] file - OPTIONAL, patrol path
:*[[PATR]] file (OPTIONAL), for the patrol path
:*[[NEUT]] file - OPTIONAL, neutral behavior (for example civilians giving player some powerup)
:*[[NEUT]] file (OPTIONAL), for neutral behavior (e.g., a civilian giving the player a powerup)


:Pursuit behavior is executed only within the '''Pursuit range''', which is a parameter <PursuitDistance> in [[CMBT]] profile attached to the A.I. character. If anything suspicious happens outside of this range, A.I. only looks in the direction of disturbance for a short time, then ignores it and returns to job.
:Pursuit behavior is executed only within the '''Pursuit range''', which is the parameter <PursuitDistance> in the [[CMBT]] profile attached to the AI. If anything suspicious happens outside of this range, the AI only looks in the direction of the disturbance for a short time, then ignores it and returns to its job.
:Pursuit behavior greatly depends on level of alert. There are four parameters regarding alert levels in [[CHAR]] profile:
:Pursuit behavior greatly depends on the AI's level of alert. There are four parameters regarding alert levels in the CHAR profile:
:*Initial - A.I. is spawned with this level of alert
:*Initial: the AI is spawned with the specified level of alert
:*Minimal - minimal alert level this A.I. can have
:*Minimal: the minimum alert level this AI can have
:*JobStart - Alert level of the A.I. when it starts some job (most typically a patrol)
:*JobStart: the alert level of the AI when it starts some job (typically a patrol)
:*'''Investigate''' - From this alert level and all greater alert levels A.I. will tend to pursue any suspicious sound it hears or any hostile peripheral contact it makes.
:*Investigate: From the alert level specified here, and all greater alert levels, the AI will tend to pursue any suspicious sound it hears or any hostile peripheral contact it makes




:Also in [[CHAR]] there are five fields regarding pursuit behavior:
:Also in [[CHAR]] are five fields regarding pursuit behavior:
:*Lull/Low alert level '''strong''' awareness behavior - in xml labeled as <StrongUnseen>  
:*Lull/Low alert level and '''strong''' awareness behavior: in XML labeled as <StrongUnseen>  
:*Lull/Low alert level '''weak''' awareness behavior - in xml labeled as <WeakUnseen>  
:*Lull/Low alert level and '''weak''' awareness behavior: in XML labeled as <WeakUnseen>  
:*Medium/High/Combat alert level '''strong''' awareness behavior - in xml labeled as <StrongSeen>  
:*Medium/High/Combat alert level and '''strong''' awareness behavior: in XML labeled as <StrongSeen>  
:*Medium/High/Combat alert level '''weak''' awareness behavior - in xml labeled as <WeakSeen>
:*Medium/High/Combat alert level and '''weak''' awareness behavior: in XML labeled as <WeakSeen>
:*Lost - behavior when A.I. had definite contact (confirmed enemy) but lost it, in xml labeled as <Lost>
:*Lost (when an AI had a definite contact but lost it): in XML labeled as <Lost>




:If inside pursue range A.I. character registers any sound or peripheral vision contact while its alert level is below alert level set in '''Investigate''' parameter, then this A.I. will only look in a direction of disturbance for a short time, then ignores it and returns to job. However, if alert level of the A.I. is high enough, A.I. character goes into pursue mode. That means A.I. will get '''strong awareness''' of the enemy (only '''weak''' in case of peripheral contact), goes to the source of disturbance (center of sound sphere in case of sound or the spot where enemy stood in case of peripheral eye contact) and will perform pursuit mode Look for 10 seconds. After this initial Look mode expires, A.I. starts with pursuit behavior prescribed in its [[CHAR]] profile.
:If an AI registers any sound or peripheral vision contact inside its pursuit range while its alert level is below the alert level set in its '''Investigate''' parameter, then this AI will only look in the direction of the disturbance for a short time, then ignore it and return to its job. However, if the alert level of the AI is high enough, the AI goes into pursuit mode. That means that the AI will get a '''strong awareness''' of the enemy (or only '''weak''' in the case of peripheral contact), go to the source of the disturbance (the center of the sound sphere in the case of a sound, or the spot where the enemy stood in the case of peripheral eye contact), and will perform the pursuit behavior Look for 10 seconds. After this initial Look mode expires, the AI will perform the pursuit behavior prescribed in its [[CHAR]] profile.
:Length of each pursuit behavior execution depends on HostileThreat timers ([[ONCC]] file) as described in section above.
:The length of each pursuit behavior's execution depends on the HostileThreat timers ([[ONCC]] file), as described in the section above.








Modding hints: '''Pursuit mess and weird glitches'''
Modding hints: '''Pursuit mode complications and weird glitches'''
:[http://www.youtube.com/watch?v=OMFK5iKcZ5Q Watch this YouTube video.]
:Watch [https://www.youtube.com/watch?v=OMFK5iKcZ5Q this YouTube video]. Pursuit mode is quite buggy, so when setting pursuit behaviors, there are several important things a modder has to have in mind.
:Pursuit mode is quite buggy, so when altering this behavior, there are several important things modder has to have on mind.
:*The pursuit distance parameter in CMBT is important in deciding whether the character should be more of a pursuer or more of a guard.
:*Pursuit distance parameter in [[CMBT]] is important in deciding whether the character should be more a pursuer or more a guard.
:*Within the pursuit distance, peripheral vision pursuit follows its own rules. When an AI sees an enemy with its peripheral vision, this AI always goes into weak awareness mode and either just glances in the direction of this enemy (alert level was below Investigate level) or moves to the spot and performs weak investigation pursuit behavior (alert level was at Investigate on higher).
:*Within the pursuit distance, peripheral vision pursuit runs its own league. When A.I. character sees enemy with its peripheral vision, this A.I. always goes into weak awareness mode and either just glaces at direction of this enemy (alert level was below investigate level) or moves to the spot and performs weak investigation pursuit behavior (alert level was on investigate level on higher).
:*Remember that there are TWO sets of pursuit behavior:
:*Remember there are TWO sets of pursuit behavior:
:**strong and weak pursuit for lull/low alert levels. In XML these are called <StrongUnseen> and <WeakUnseen>, however those names simply reflect how many changes were made to this part of the game.
:**strong and weak pursuit for lull/low alert levels. In xml these are called <StrongUnseen> and <WeakUnseen>, however those names simply reflect how many changes were made to this part fo the game.
:**strong and weak pursuit for medium/high/combat levels, in XML called <StrongSeen> and <WeakSeen>.
:**strong and weak pursuit for medium/high/combat levels, in xml called <StrongSeen> and <WeakSeen>.
:*From all the available pursuit behaviors, only GoTo, Look, Glance, Forget and Wait can be effectively used as CHAR pursuit behavior parameters. Hunt and Move are not finished code-wise.
:*From all available pursuit behaviors GoTo, Look, Glance, Forget and Wait can be effectively used in CHAR pursuit behavior parameters. Hunt and Move are not finished code-wise.
:*'''Remember that general pursuit behavior is simply glitched, and the parameters from CHAR are more often ignored than actually used.''' The glitchiness is somehow connected with vision. When AI vision is turned off via '''ai2_blind=1''', pursuit mechanics work as they should. However, the moment that AIs are allowed to see, then when pursuit should be performed, it results in:
:*'''Remember that whole pursuit behavior is glitched and parameters from CHAR are more often ignored than actually used.''' This glitch is somehow connected with sight. When sight of A.I. characters is turned off via '''ai2_blind=1''', whole pursuit mechanics work as they should. However, the moment A.I. character is allowed to see, then when pursuit should be performed it gets:
:**pursuit values from CHAR being ignored if pursuit mode was called while the character was idle or moving along a patrol path. The AI character performs basic GoTo + timer-based Look for the whole period of pursuit behavior, for both strong and weak awareness. Looks so-so but definitely is a glitch.
:**bugged and results in pursuit values from [[CHAR]] being ignored if pursuit mode was called while the caracter was idle or moving in a patrol path. Our A.I. character performs basic GoTo + timer-based Look for the whole time of pursuit, for both strong and weak awareness. Looks so-so but definitely is a glitch.
:**one GoTo + timer based Look being called, but the timer for Look fails to decrement, so the AI simply stands and stares forever. This happens when pursuit mode is called while an AI stands at a job location on a patrol path. And, well... it looks really bad.
:**bugged and results in one GoTo + timer based Look being called, but timer for Look does not decrement, so A.I. simply stands and stares. This happens when pursuit mode is called while A.I. stand at job location in patrol path. And well... it looks really bad.
:**correct behavior roughly 10% of the time. It is quite random, but it looks like the AI has to be somehow disturbed while going for the source of a previous disturbance. And then Oni writes to the developer console "pursuit mode Hunt not yet implemented" ^_^.
:**in roughly 10% the pursuit performs correctly. It is quite random, but looks like A.I. has to be somehow disturbed while going for the source of previous distrubance. And then Oni writes into console "pursuit mode Hunt not yet implemented" ^_^.
:*The best way how to deal with the pursuit/vision issue is to either ignore it (so the character often gets glitched) or use a BSL script to create a small [[BSL:Manual#Looping|looping function]] where ai2_blind is set to 1 for at least one second (60 frames), then set to 0 again. It can cause funny moments of an AI completely ignoring an enemy right in front of it, but it silently fixes these pursuit problems.
:*The best way how to deal with pursuit sight issue is to either ignore it (so char get often glitched) or use BSL script to create a small self-looping function where ai2_blind is set to 1 for at least one second (60 frames), then set to 0 again. It can cause funny moments of A.I. completely ignoring enemy right in front of it, but it silently fixes these pursuit problems.






==Alarm behavior - "She's everywhere!"==
==Alarm behavior==
{|align=right
{|align=right
|[[Image:CONTROL CONSOLE.png|58px|right]]
|[[Image:CONTROL CONSOLE.png|58px|right]]
Line 195: Line 187:
!Data
!Data
|}
|}
In order to make A.I. look more humane, it is a good idea to grant it ability to interact with the world the same way player does. In Oni that means for example to give A.I. option to use consoles.
In order to make the AI look more human, it is a good idea to grant it the ability to interact with the world the same way that the player does. In Oni, for example, that means giving the AI the ability to use consoles.


::[http://www.youtube.com/watch?v=jnsGuZxqW9I Watch this YouTube video.]
::[https://www.youtube.com/watch?v=jnsGuZxqW9I Watch this YouTube video.]
:BSL scripting provides a command to make A.I. go and use a console - '''ai2_doalarm''' ''ai_name/index'' '''number of console'''. This way A.I. can be told to use any console. But there is a method to make A.I. character use a console completely on it own.
:BSL scripting provides a command to make an AI go and use a console: [[ai2_doalarm]]. This way, an AI can be told to use any console. But there is a method to make an AI use a console completely on it own.
:In order to utilize those mechanics, there is a need for a console which has ALARM CONSOLE flag set (see [[OBD:BINA/OBJC/CONS]]). In XML this flag has a string '''IsAlarm'''. Such a console then can be used by A.I. characters without scripting.
:In order to utilize this mechanic, there is a need for a console which has the ALARM CONSOLE flag set (see [[OBD:BINA/OBJC/CONS]]). In XML this flag is called '''IsAlarm'''. Such a console then can be used by AI characters without scripting.


:Next, there are Alarm parameters in [[CMBT]] profiles which define A.I. character's alarm behavior:
:Next, there are Alarm parameters in [[CMBT]] profiles which define an AI's alarm behavior:
:*Search distance - a perimeter around the character where engine checks for any console with ALARM CONSOLE flag. In xml it is named <SearchDistance>.
:*Search distance: a radius around the AI where the engine checks for any console with the ALARM CONSOLE flag. In XML it is named <SearchDistance>.
:*Ignore distance - a perimeter around A.I. character where this A.I. character (which is currently executing alarm behavior) acknowledges enemies. Enemies outside of this perimeter are ignored by the A.I. character. In xml it is named <EnemyIgnoreDistance>.
:*Ignore distance: a radius around the AI where this AI character (which is currently executing alarm behavior) acknowledges enemies. Enemies outside of this radius are ignored by the AI character. In XML it is named <EnemyIgnoreDistance>.
:*Attack distance - a perimeter around A.I. character where this A.I. character (which is currently executing alarm behavior) temporarily stops its run for the console and attacks enemies if they are within this range and A.I. character sees them with central vision field. In xml it is named <EnemyAttackDistance>.
:*Attack distance: a range within which the AI (which is currently executing alarm behavior) will temporarily stop its run for the console and attack enemies if the AI sees them with its central vision field. In XML it is named <EnemyAttackDistance>.
:*Damage threshold - in xml named <DamageThreshold>. Time interval for which A.I. character keeps awareness of enemy who attacked it. If this enemy crosses Attack distance perimeter, A.I. temporarily stops its run for alarm and immediately attacks this enemy (does not have to see him with central vision field).
:*Damage threshold: The time interval for which an AI stays aware of an enemy who attacked it. If this enemy enters the Attack distance, the AI temporarily stops its run for alarm and immediately attacks this enemy (it does not have to see him with central vision field). In XML it is named <DamageThreshold>.
:*Fight timer - in xml called <FightTimer>, duh. Numer of frames for which A.I. character should fight with the enemy before it attempts to resume its run for alarm.
:*Fight timer: The number of frames for which the AI should fight with the enemy before it attempts to resume its run for the alarm. In XML it is called <FightTimer>.




:Logic for alarm running is set, now how to trip it? There are three ways how to make character run and use a console without BSL. the console must have ALARM CONSOLE flag set and ust lie within Search distance perimeter:
:So the settings for alarm-running behavior are set; now how to trip it? There are three ways to make a character run and use a console without BSL (but the console must have the ALARM CONSOLE flag set and must lie within Search distance):
:*in [[CMBT]]: If no gun behavior set to "Run for Alarm". In xml it is RunForAlarm string inside <NoGunBehavior>. By setting this parameter, A.I. character will attempt to run and use a console when it does not have a loaded weapon or spare clips in inventory (then it reload and continues shooting). If there is no alarm console nearby, A.I. will switch to Melee.
:*using CMBT profile: Set the no-gun behavior to "Run For Alarm" (in XML, use the string "RunForAlarm" inside <NoGunBehavior>). By setting this parameter, an AI will attempt to run and use a console when it does not have a loaded weapon or any spare clips in its inventory. If there is no alarm console nearby, the AI will switch to Melee.
:*in [[CMBT]]: Behaviors (Long, Medium, Short, MediumRetreat, LongRetreat) can be set to be "Run for Alarm". DO NOT confuse with "Run for alarm If no gun" behavior! This behavior is never used in retail Oni, the reason probably being the fact if there is no useable console within Alarm search distance radius, then A.I. character simply stands and stares even when enemy is visible with central vision field.
:*also in CMBT: The Behaviors (Long, Medium, Short, MediumRetreat, LongRetreat) can be set to "Run for Alarm". DO NOT confuse this with the "Run For Alarm" no-gun behavior! This behavior is never used in retail Oni, the reason probably being that if there is no useable console within Alarm search distance radius, then the AI simply stands and stares even when an enemy is visible within its central vision field.
:*In [[CHAR]]: Lost behavior "FindAlarm" - When A.I. character makes definite contact with enemy and then enemy manages to escape, A.I. executes "Lost" behavior (see "Pursuit of enemy" section). This behavior is typically set as ReturnToJob, but FindAlarm works well with no known issues. If alarm console is not found within search distance, A.I. returns to its job.
:*In [[CHAR]]: Use the "Lost" behavior "FindAlarm". When an AI makes definite contact with an enemy and then the enemy manages to escape, the AI executes this "Lost" behavior (see [[#Pursuit|Pursuit of enemy]] section). This behavior is typically set as ReturnToJob, but FindAlarm works well with no known issues. If an alarm console is not found within Search distance, the AI simply returns to its job.




:A couple of notes regarding A.I. character:
:A couple of notes regarding AIs:
:*in order to register enemy and attack her/him pre-emptively, A.I. character must have "HostileThreatDefinite" timer set in ONCC file to some value over 60 (Oni runs 60 frames per second).
:*in order to register an enemy and attack her/him pre-emptively, the AI must have the "HostileThreatDefinite" timer in its ONCC file set to some value over 60 (Oni internal clock runs at 60 frames per second).
:*"If no gun" behavior "Run for Alarm" can get glitched. "Alarm enemy attack distance" is set to some value, let's say 100. Now when A.I. character runs for alarm and enemy attacks it, then if in this [[CMBT]] profile there is not set melee override for range at least 100 (via melee override or by heving "Melee" set in corresponding combat ranges, see section [[#Combat behavior part 1 : "Hokey religions and ancient weapons..."|Combat behavior]]), chances are A.I. will get stuck in a loop trying to reach both enemy and console at the same time.
:*The no-gun behavior "Run For Alarm" can get glitchy. Say that "Alarm enemy attack distance" is set to 100; now when an AI runs for an alarm and an enemy attacks it, then if in the AI's CMBT profile the melee override is not set to a range of at least 100 (via melee override or by having "Melee" set in its corresponding combat ranges, see section [[#Basic combat behaviors|Basic combat behaviors]]), chances are that the AI will get stuck in a loop trying to reach both the enemy and the console at the same time.
:*Similar issue can happen with combat behavior Run For Alarm as well, but this time problems rise when this combat behavior Run For Alarm is set as Short range behavior.
:*A similar issue can happen with the combat behavior "Run For Alarm" as well, but this time problems arise when this combat behavior "Run For Alarm" is set as the Short-range behavior.


:A couple of notes regarding target console:
:A couple of notes regarding the target console:
:*Console must be in "activated" mode. If console is in deactivated or used modes, alarm behavior will not be executed.
:*It must be in "activated" mode. If the console is in a deactivated or "used" mode, the alarm behavior will not be executed.
:*Console must be directly accessible. Oni A.I. cannot use consoles in order to open path to get to the point of interest (target console in this case). Target console must be directly accessible. Still, it can be directly accessible across the whole level ^_^.
:*It must be directly accessible. Oni's AI cannot use consoles in order to open up a path to get to the point of interest (a target console in this case). But the target console can be across the whole level as long as it is not behind any locked doors.




:As already mentioned, Alarm behavior can be tripped by BSL command ai2_doalarm. In that case alarm behavior is executed but this time console is set by command instead of being looked for via Search distance. Also, by ai2_doalarm A.I. can be made to use any console, not only those with ALARM CONSOLE flag.
:As already mentioned, Alarm behavior can be tripped by the BSL command "ai2_doalarm". In that case, alarm behavior is executed but this time the console is being set by a command instead of being looked for within the Search distance. Also, with "ai2_doalarm" the AI can be made to use any console, not just those with the ALARM CONSOLE flag.






Modding hints: ability of A.I. to use consoles is an excellent tool for increasing a challenge.
Modding hints: the ability of the AI to use consoles is an excellent tool for increasing the challenge.
:*Beware of setting Run For Alarm combat behavior as close range one. Such a setup causes glitches.
:*Beware of setting the "Run For Alarm" combat behavior as the close-range one. Such a setup causes glitches.
:*On the other side, combat behavior Run For Alarm can be deliberately used to add element of surprise to fights. In [[CMBT]] profile, set Run For Alarm as either Medium or MediumRetreat behavoir, then shorten interval between <MediumRange> and <ShortRange> values (for example set "Medium Range" to 60 and "Short Range" to 59). Thanks to this setup, A.I. can attempt to find an alarm console while still being capable of fighting even when no alarm is nearby.
:*On the other hand, "Run For Alarm" can be deliberately used to add an element of surprise to fights. In the CMBT profile, set "Run For Alarm" as either the Medium or MediumRetreat behavior, then shorten the interval between the <MediumRange> and <ShortRange> values (for example, set "Medium Range" to 60 and "Short Range" to 59). Thanks to this setup, an AI can attempt to find an alarm console while still being capable of fighting when no alarm is nearby.
:*In [[BSL]] a modder can easily distinguish if console was used by player or A.I. thanks to '''chr_is_player('''ai_name''')''' function. All what is required is a BSL function being triggered when console is used. Here is example where console triggers a function called '''console1_used''':
:*In BSL, a modder can easily determine if a console was used by the player or an AI thanks to the [[chr_is_player]] function. All that's required is a BSL function being triggered when the console is used. Here is an example where a console triggers a function called "console1_used":
  func void console1_used(string ai_name)
  func void console1_used(string ai_name)
  {
  {
  if(chr_is_player(ai_name))
  if (chr_is_player(ai_name))
  {
  {
  *Some code in case player used the console*
    *Some code in case player used the console*
  }
  }
  else
  else
  {
  {
  *Some code in case A.I. used the console*
    *Some code in case AI used the console*
  }
  }
  }
  }
:*Other way of using alarm mechanics is to create a feeling of cooperation - player has to achieve something and in order to do so, an A.I. driven sidekick who goes after needed console and uses it is required.
:*Another way of using alarm mechanics is to create a feeling of cooperation -- in order for the player to achieve something, an AI-driven sidekick must use a console.
 
:*In extreme case, A.I. character can be even made to though the level on it own, moving from one console to another. That can be used to create chasing levels - A.I. character has to activate a certain number of consoles while player is required to stop this A.I. character from doing so. Thanks to Alarm behavior the task of tripping consoles can be fully completed by A.I., no scripting needed. such a setup is on the one side prone to possible A.I. glitches, but on the other side can add element of randomness and increase replayability.
 


:*In extreme cases, an AI can be even made to move through the level on it own, from one console to another. That can be used to create "chase" missions -- an AI wants to activate a certain number of consoles, while the player is required to stop it from doing so. Thanks to Alarm behaviors, the task of tripping consoles can be fully completed by the AI, no scripting needed. Such a setup is on the one hand prone to possible AI glitches, but on the other hand can add an element of randomness and increase replayability. A demonstration of alarm behavior being used by an AI to complete all of Chapter 1 can be found [https://www.youtube.com/watch?v=CkzguNxjGEs HERE].


==Combat behavior part 1 : "Hokey religions and ancient weapons..."==
==Basic combat behaviors==
[[File:combatRanges.PNG|thumb|right|alt=Example of combat ranges.|Combat ranges of an A.I. character.]]
[[Image:combatRanges.png|thumb|right|alt=Example of combat ranges.|Combat ranges of an AI character.]]
Of course an action game like Oni is not complete without guns blazing and fists flying through the air. But combat in real life is usually very fickle and everything has to be considered. How can Oni A.I. possibly deal with such a complex task?
Of course, an action game like Oni is not complete without guns blazing and fists flying through the air. But combat in real life is usually very fickle and everything has to be considered. How can Oni's AI possibly deal with such a complex task?


:Oni A.I. character has to have definite awareness of the enemy in order to actively attack him. Alert level of the A.I. character when in combat mode is Combat (duh). Definite awareness can be achieved by these ways:
:An AI in Oni has to have a definite awareness of the enemy in order to actively attack him. The alert level of an AI when in combat mode is Combat (duh). Definite awareness can be achieved by these ways:
:*Enemy was seen by this A.I. character's central vision field.
:*The enemy is seen in this AI's central vision field.
:*A.I. character is made to attack the enemy by [[BSL]] function '''ai2_attack'''.
:*The AI is made to attack the enemy by the BSL function ai2_attack.
:*A.I. character was hurt by the enemy, be it melee or gun damage.
:*The AI is hurt by the enemy, be it melee or gun damage.


Once combat mode is entered, then as long as HostileThreatDefinite timer for this enemy does not reach zero, A.I. character will always know exact location of this enemy and will attempt to attack it. The moment HostileThreatDefinite timer is depleted, A.I. character loses the privilege of knowing exact location, awareness decerases from definite to strong and A.I. character either switches from combat mode with this enemy to pursuit mode with this enemy (see section [[#Pursuit of enemy alias "I will find you..."|Pursuit of enemy]]) or, in case of other enemy being present in central vision field, picks this new enemy as a target to attack and keeps old enemy in strong (and later weak and later forgotten) awareness.
Once combat mode is entered, then as long as the HostileThreatDefinite timer for this enemy does not reach zero, an AI will always know the exact location of this enemy and will attempt to attack it. The moment HostileThreatDefinite timer is depleted, the AI loses the privilege of knowing the enemy's exact location, its awareness decreases from definite to strong, and the AI either switches from combat mode to pursuit mode with this enemy (see section [[#Pursuit|Pursuit of enemy]]) or, in case of another enemy being present in its central vision field, picks this new enemy as a target to attack and keeps the old enemy in strong (and later weak, then forgotten) awareness.


:Since generally method of combat depends on distance between participants, some sort of spacing is needed. Oni uses system of three ranges around A.I., called combat ranges. See picture on right. Perimeters of these ranges can be set in [[CMBT]] profile.
:Since the means of combat depends on the distance between the participants, some sort of spacing is needed. Oni uses a system of three radii around the AI, called combat ranges. See picture on right. The size of these radii can be set in the [[CMBT]] profile.
:These ranges work as "triggers" to make the A.I. character execute various behaviors, based on enemy's position. Moreover, Oni can distinguish between states when enemy entered specified range or exited specified range. So all range possibilities in Oni which can be assigned some combat behavior are:
:These ranges work as "triggers" to make the AI character execute various behaviors based on the enemy's proximity. Moreover, Oni can distinguish between an enemy entering a specified range or exiting a specified range. All the range possibilities in Oni which can be assigned some combat behavior are:
:*Short - enemy is closest to the A.I. character
:*Short: enemy is close to the AI.
:*Medium - enemy is approaching the A.I. character and crossed from Long Range into Medium Range.
:*Medium: enemy is approaching the AI and crossed from Long Range into Medium Range.
:*Long - enemy is approaching the A.I. character and starts from the Long Range.
:*Long: enemy is approaching the AI starting at the Long Range.
:*Medium Retreat - enemy is retreating from Short Range into Medium Range.
:*Medium Retreat: enemy is retreating from Short Range to Medium Range.
:*Long Retreat - enemy is retreating from Medium Range into Long Range.
:*Long Retreat: enemy is retreating from Medium Range to Long Range.


:Well of course nothing is perfect and in Oni there is a bit of an issue with proper switching between combat ranges, so Long and Medium ranges are used only once at the beginning of enemy approach. Only Short, Medium Retreat and Long Retreat ranges are used on regular basis in a combat. Even when enemy runs into Long Retreat and goes back to to medium range, engine does not switch A.I. behavior range to Medium, but (contrary to its name) to Medium Retreat.
:Well, of course nothing is perfect, and in Oni there is a bit of an issue with proper switching between combat ranges, so Long and Medium ranges are used only once at the beginning of an enemy approach. Only Short, Medium Retreat and Long Retreat ranges are used on a regular basis in combat. Even when an enemy runs into Long Retreat and goes back to to Medium range, the engine does not switch the AI's behavior range to Medium, but (contrary to its name) to Medium Retreat.




OK, we have positioning, now for actual behaviors A.I. character can be set to execute within these ranges. There are fourteen possible combat behaviors (in brackets are xml strings):
OK, we have positioning down; now for the actual behaviors that an AI can be set to execute within these ranges. There are fourteen possible combat behaviors (in parentheses are the XML strings):
:*None (None) - simply nothing
:*None (None): simply nothing.
:*Stare (Stare) - A.I. character stands and stares, does not even rotate to face enemy
:*Stare (Stare): the AI stands and stares; it does not even rotate to face the enemy.
:*Hold and fire (HoldAndFire) - A.I. character stands still and fires a weapon. If this character does not have a weapon, then she/he switches to melee.
:*Hold and fire (HoldAndFire): the AI stands still and fires a weapon. If this character does not have a weapon, then it switches to melee.
:*Firing charge (FiringCharge) - A.I. character runs towards the enemy and fires a weapon. If this character does not have a weapon, then she/he switches to melee.
:*Firing charge (FiringCharge): the AI runs toward the enemy and fires a weapon. If this character does not have a weapon, then it switches to melee.
:*Melee (Melee) - A.I. character always uses melee, even when she/he holds a loaded weapon.
:*Melee (Melee): the AI always uses melee, even when it holds a loaded weapon.
:*Barabbas shoot (BarabasShoot) - A.I. character stands still and fires a weapon with hardcoded three seconds pause between shots. If this character does not have a weapon, then he switches to melee. If this character meets certain conditions, she/he can start health regeneration. More detailed info about regeneration mechanics [[Barabas' regeneration| can be read HERE.]]
:*Barabbas shoot (BarabasShoot): the AI stands still and fires a weapon with hardcoded three-second pauses between shots. If this character does not have a weapon, then it switches to melee. If this character meets certain conditions, it can start regenerating health. More detailed info about regeneration mechanics [[Barabas' regeneration|can be read here.]]
:*Barabbas advance (BarabasAdvance) - A.I. character runs towards the enemy and fires a weapon with '''secondary fire mode''' (as if player pressed right button). If this character does not have a weapon, then she/he switches to melee. If this character meets certain conditions, she/he can start health regeneration. More detailed info about regeneration mechanics [[Barabas' regeneration| can be read HERE.]]
:*Barabbas advance (BarabasAdvance): the AI runs toward the enemy and fires a weapon using the '''secondary trigger''' (as if the player pressed right mouse button). If this character does not have a weapon, then it switches to melee. If this character meets certain conditions, it can start regenerating health. More detailed info about regeneration mechanics [[Barabas' regeneration|can be read here.]]
:*Barabbas melee (BarabasMelee) - A.I. character uses melee, even with loaded weapon in hand. If this character meets certain conditions, she/he can start health regeneration. More detailed info about regeneration mechanics [[Barabas' regeneration| can be read HERE.]]
:*Barabbas melee (BarabasMelee): the AI uses melee, even with a loaded weapon in hand. If this character meets certain conditions, it can start regenerating health. More detailed info about regeneration mechanics [[Barabas' regeneration|can be read here.]]
:*Superninja fireball (SuperNinjaFireball) - Mukade's long range behavior. With this behavior A.I. cannot shoot weapons and cannot use melee, simply runs towards the enemy. However, if weapon is held, character can use melee (probably something from weapon melee override). A.I. character is occasionally teleported into the back of the enemy (AnimType 222 - Teleport In) if distance to enemy is greater than 100. It seems like it should work regularly once distance to enemy exceeds 100, but in reality something screws this teleport mechanics ^_^. Anyway, to add more to this behavior A.I. executes two special TRAM animations:
:*Superninja fireball (SuperNinjaFireball): Mukade's long range behavior. With this behavior, an AI cannot shoot weapons and cannot use melee; it simply runs toward the enemy. However, if a weapon is in hand, the character can use melee (probably something from the weapon melee override). The AI is occasionally teleported behind the enemy (AnimType 222 - Teleport In) if the distance to the enemy is greater than 100 world units (however, something is screwy with this teleportation mechanic). Anyway, to add more to this behavior, the AI executes two special [[TRAM]]s (animations):
:**AnimType 224 - Ninja Fireball, after the use there is 20 seconds pause before then this [[TRAM]] is used again.
:**AnimType 224 - Ninja Fireball (Mukade's heat-seeking Devil Star); after using this, there is a 20-second cool-down before this can be used again.
:**AnimType 225 - Ninja Invisible, grants 10 second cloak, after the use there is 20 seconds pause before this TRAM is used again.
:**AnimType 225 - Ninja Invisible (grants a 10-second cloak); after using this, there is a 20-second cool-down before this can be used again.
::'''IMPORTANT''' There is an annoying problem with this behavior. When it is called, it checks character's position height-wise from the origin of the game world (coordinates 0,0,0) and if the height is below 550, this character is automatically moved to height 550 (which in almost all cases means death by falling).
::'''IMPORTANT''' There is an annoying problem with this behavior, which was coded with the Rooftops boss fight in mind. When it is called, it checks the character's position height-wise from the origin of the game world (coordinates {0, 0, 0}) and if the height is below 550, this character is automatically moved to height 550 (which in almost all cases means death by falling).
:*Superninja advance (SuperNinjaAdvance) - Mukade's medium range behavior. With this behavior A.I. cannot shoot weapons and cannot use melee, simply runs towards the enemy. However, if weapon is held, character can use melee (probably something from weapon melee override). This behavior gives ability to use AnimType 225 - Ninja Invisible which grants 10 seconds invisibility. In order to be able to use this ability, A.I. has to be at least 50 (or 40?) units far from its enemy. Cooldown for this special technique is 20 seconds. Again, annoying '''over 550 height check''' is present.
:*Superninja advance (SuperNinjaAdvance) - Mukade's medium range behavior. With this behavior, an AI cannot shoot weapons and cannot use melee; it simply runs toward the enemy. However, if a weapon is in hand, the character can use melee (probably something from the weapon melee override). This behavior also allows the use of AnimType 225 - Ninja Invisible. In order to be able to use this ability, the AI has to be at least 50 (or 40?) world units away from its enemy. The cool-down for this special technique is 20 seconds. Again, the annoying "over 550" height check is present.
:*Superninja melee (SuperNinjaMelee) - Mukade's short range behavior. With this behavior A.I. cannot shoot weapons but can use melee. This behavior gives ability to use AnimType 225 - Ninja Invisible which grants 10 seconds invisibility. In order to be able to use this ability, A.I. has to be at least 50 (or 40?) units far from its enemy. Cooldown for this special technique is 20 seconds. This behavior also grants ability to teleport away from enemy to certain distance (around 100 units) if any one of these conditions is met:
:*Superninja melee (SuperNinjaMelee): Mukade's short range behavior. With this behavior, the AI cannot shoot weapons, but <u>can</u> use melee. This behavior allows the use of AnimType 225 - Ninja Invisible. In order to be able to use this ability, the AI has to be at least 50 (or 40?) world units away from its enemy. The cool-down for this special technique is 20 seconds. This behavior also grants the ability to teleport away from the enemy to a certain distance (around 100 world units) if any one of these conditions is met:
:**About 35 points of damage dealt to this character in a short time (exact amount of damage and exact timing not known).
:**About 35 points of damage dealt to this character in a short time (exact amount of damage and exact timing not known).
:**This character get thrown by any throw.
:**This character get thrown.
::Again, annoying '''over 550 height check''' is present.
::Again, the annoying "over 550" height check is present.
:*Run for alarm (RunForAlarm) - see section [[#Alarm behavior - "She's everywhere!"|Alarm behavior]].
:*Run for alarm (RunForAlarm): see section [[#Alarm behavior|Alarm behavior]].
:*Mutant Muro melee (MutantMuroMelee) - A.I. character is only allowed to melee, will not fire weapons. This behavior casts chenille (overpower effect) on the user. Of course in order to see visible effect character has to have set <HasDaodanPowers> to 1 in [[ONCC]]. This chenille mode does not grant damage overpower effect, melee attacks deal their usual damage. If ONCC has set both <HasDaodanPowers> and <HasSuperShield> to 1, the chenille mode called by this behavior grants super shield.
:*Mutant Muro melee (MutantMuroMelee): the AI is only allowed to melee, not fire weapons. This behavior places the Daodan aura on the character irrespective of his/her HP as long as the character has <HasDaodanPowers> set to 1 in their [[ONCC]]. This aura effect does ''not'' grant the damage overpower attribute that Konoko has when she overheals. If the ONCC has both <HasDaodanPowers> and <HasSuperShield> set to 1, the chenille mode called by this behavior grants a [[supershield]].
::Chenille mode lasts forever if it is not terminated either via BSL or by A.I. character performing a [[TRAM]] which has a DisableShield flag. After 10 seconds interval, chenille is turned back on. Another specialty of this behavior is automatic backwards evasion move when about 35 points of damage or a throw are applied on the A.I. character. Chenille mode is turned off if this A.I. character switches to some other combat behavior because the enemy moved to some other combat range.
::The supershield lasts forever if it is not terminated either via BSL or by the AI performing a TRAM which has a DisableShield flag. After a DisableShield move removes the supershield there is a 10 second interval and then it is turned back on. Another specialty of this behavior is an automatic backward-evasion move when about 35 points of damage or a throw are inflicted on the AI. The supershield is turned off if this AI switches to some other combat behavior because the enemy moved to another combat range.
:*Mutant Muro thunderbolt (MuroThunderbolt) - Upon initial contact A.I. chracter turns on chenille mode and runs towards enemy. If chenille mode is turned off, then until definite awareness of the enemy is lost this behavior will not cast chenille mode again. This behavior also allows the A.I. character to use special long range attack - chracter turns off chenille, goes into AnimState 69 (Thunderbolt) and loops special TRAM animation of AnimState 69 (Thunderbolt) and AnimType 231 (Muro_Thunderbolt). That lasts for 10 seconds. Then A.I. makes 5 seconds pause during which it runs towards enemy. If after those 5 seconds A.I. character is still executing Mutant Muro thunderbolt behavior, A.I. character starts again looping the TRAM animation which has AnimType 231 and AnimState 69.
:*Mutant Muro thunderbolt (MuroThunderbolt): Upon initial contact, the AI turns on chenille mode and runs toward the enemy. If chenille mode is turned off then, until definite awareness of the enemy is lost, this behavior will not cast chenille mode again. This behavior also allows the AI to use a special long range attack: the character turns off chenille, goes into AnimState 69 - Thunderbolt, and loops a special TRAM animation of AnimState 69 - Thunderbolt and AnimType 231 - Muro_Thunderbolt. That lasts for 10 seconds. Then the AI stops the animation for 5 seconds and runs toward the enemy. If, after those 5 seconds, the AI is still executing Mutant Muro thunderbolt behavior, the AI resumes the looping TRAM between AnimType 231 and 69.
::This behavior's special (looping TRAM animation) lasts even when enemy enters some other combat range with the exception of Short range. If enemy enters Short range while the looped animation is running, the loop is forced to stop and A.I. character starts using Short range behavior.
::This behavior's special looping animation continues even when an enemy enters some another combat range, with the exception of Short range. If the enemy enters Short range while the looped animation is running, the loop is forced to stop and the AI starts using Short range behavior.








Modding hints: Combat behaviors can have severe impact on A.I. performance in a fight but can as well hinder the A.I.
Modding hints: Combat behaviors can have a severe positive or negative impact on AI performance in a fight.
:*Remember: due to a glitch, crucial behaviors for combat are Short, MediumRetreat and LongRetreat. Long And Medium are used only at the beginning of an ecounter.
:*Remember: due to a glitch, the crucial behaviors for combat are Short, MediumRetreat and LongRetreat. Long and Medium are used only at the beginning of an encounter.
:*In general, use common sense. There is little use in setting Firing Charge as Short range behavior.
:*In general, use common sense. There is little use in setting Firing Charge as the Short range behavior.
:*Barabbas Shoot and Barabbas Melee behaviors have access to heal ability which can be a great asset for introducing mutants or stronger enemy units. However, remember that Barabbas Shoot limits rate of fire to one shot per three seconds.
:*Barabbas Shoot and Barabbas Melee behaviors have access to a healing ability which can be a great asset for introducing mutants or stronger enemy units. However, remember that Barabbas Shoot limits rate of fire to one shot per three seconds.
:*Barabbas Advance is the only behavior which allows A.I. to fire a weapon with secondary fire mode. However the behavior is quite glitched (A.I. character often looks away and fires stray shots). Still, with proper gun and proper setup it can be useable for boss fights.
:*Barabbas Advance is the only behavior which allows an AI to fire a weapon in its secondary fire mode. However the behavior is quite glitchy (the AI often looks away and fires stray shots). Still, with the proper gun and proper setup it can be useable for boss fights.
:*Superninja's behaviors sound excellent for cunning enemy units, however annoying check for character's minimal allowed height from world origin and subsequent forced repositions severely impact these behaviors' usefulness. Despite the height limit, with deliberately designed level which is uplifted enough on purpose, the behavior will not cause random A.I. character repositioning. Then it can be used to its fullest.
:*Superninja's behaviors sound excellent for cunning enemy units, however the annoying check for a character's minimum allowed height from the world origin, and subsequent forced re-positioning, severely impact these behaviors' usefulness. With a level which is deliberately raised to the correct height, the behavior will not cause random AI character re-positioning. Then it can be used to its fullest.
::One other important thing about these behaviors - if A.I. character does not have required [[TRAM]]s in her/his [[TRAC]], the A.I. character can get stuck if she/he uses these behaviors.
::One other important thing about these behaviors: if the AI does not have required the TRAMs in its [[TRAC]], the AI can get stuck if it uses these behaviors.
:*If there is no console with ALARM CONOSLE flag within Alarm sarch distance, then behavior "Run For Alarm" will make A.I. enemy just stand and stare. Set this behavior with caution and consider using a workaround where medium and short combat ranges have very close diameters with Run For Alarm being MediumRetreat behavior, so Run For Alarm behavior is executed only for a brief amount of time as A.I. practically immediately switches to LongRetreat. However even one frame is enough because if alarm is found, A.I. character is requested to perform alarm run which can override combat (see section [[#Alarm behavior - "She's everywhere!"|Alarm behavior]] for more info).
:*If there is no console with the ALARM CONSOLE flag within the Alarm search distance, then the behavior "Run For Alarm" will make an AI just stand and stare. Choose this behavior with caution, and consider using a workaround where Medium and Short combat ranges have very close radii, with Run For Alarm being the MediumRetreat behavior, so that the Run For Alarm behavior is executed only for a brief amount of time as the AI almost immediately switches to LongRetreat. Even one frame is enough, because if an alarm is found, the AI is requested to perform an alarm run which can override combat (see section [[#Alarm behavior|Alarm behavior]] for more info).
:*MutantMuro melee can be used to create tricky foes which have to be eliminated from distance because if player comes up close, these enemies will turn on their (super)shield and won't put it away (no TRAM with DisableShield flag). That means player has to put some distance between him and these A.I. characters in order to make them disable the shield.
:*MutantMuro melee behavior can be used to create tricky foes which have to be fought from a distance because if the player comes up close then the AI will turn on its (super)shield and won't put it away (by providing no TRAM with the DisableShield flag). That would make the player put some distance between him and the AI in order to make it disable the shield.
:*MutantMuro thunderbolt should NEVER be assigned to Short range behavior as that will negatively affect its special attack. Set it as LongRetreat or MediumRetreat. This kind of behavior (with proper [[TRAM]]s) can be used to create foes who will perform special long range attack if player tries to keep a distance. This ranged attack does not have to be the same as Muro's tractor thunderbolt. For quick example, A.I. character can be made to fire a sort of aggressive plasma beam.
:*MutantMuro thunderbolt should NEVER be assigned as the Short range behavior, as that will negatively affect its special attack. Set it as LongRetreat or MediumRetreat. This kind of behavior (with proper TRAMs) can be used to create foes who will perform a special long range attack if the player tries to keep his distance. This ranged attack does not have to be the same as Muro's tractor thunderbolt. For example, an AI could be made to fire an aggressive energy-beam type of attack.








==Combat behavior part 2 : "Guns or not, my fists are hot."==
==Extra combat behaviors==
Combat ranges and various A.I. combat behavior was discussed in previous section. Even with combat ranges, there are still other parts of combat to be taken care of - picking up weapons from the ground, melee overrides of weapons, behavior if character is unarmed and of course, firing weapons or using hand to hand combat. Files inspected in this section will be [[CMBT]] profiles and [[ONCC]] files.
Combat ranges and various AI combat behaviors were discussed in the previous section. Even in terms of combat ranges, there are still other aspects of combat to cover: picking up weapons from the ground, melee overrides of weapons, behaviors if the character is unarmed, and, of course, firing weapons or using hand-to-hand combat.


'''"Melee override" ([[CMBT]] profile)''' - similar to [[BSL]] command '''chr_dontaim''', this behavior bids the A.I. character to use hand to hand animation varient (see [[TRAM]]) and to switch from whatsoever other behavior to melee combat. This field was probably added to deal with conflicts when multiple A.I. behaviors are applied on character. Possible values are (xml strings in brackets):
'''"Melee override" ([[CMBT]] profile)''': Similar to the BSL command [[chr_dontaim]], this behavior urges the AI to use its hand-to-hand animation variant (see [[TRAM]]) and to switch from some other behavior to melee combat. This field was probably added to deal with conflicts when multiple AI behaviors are applied on a character. The possible values are (XML strings in parentheses):
:*None (None) - no override is used.
:*None (None): no override is used.
:*If Punched (IfPunched) - melee override applied when A.I. character is melee attacked by its enemy. Does not work when the character is invincible (cheat).
:*If Punched (IfPunched): melee override is applied when the AI is melee-attacked by its enemy. Does not work when the character is invincible.
:*Cancelled - unfinished stuff, does nothing. Remains only the question what it was meant to be...
:*Cancelled: unfinished feature; does nothing. There remains only the question of what it was meant to be....
:*Short (ShortRange) - Melee override is applied when enemy is within Short range.
:*Short (ShortRange): Melee override is applied when the enemy is within Short range.
:*Medium (MediumRange) - Melee override is applied when enemy is within Medium or Short range.
:*Medium (MediumRange): Melee override is applied when the enemy is within Medium or Short range.
:*Always melee (AlwaysMelee) - Melee override is applied withing all combat ranges
:*Always Melee (AlwaysMelee): Melee override is applied within all combat ranges.


:This override can affect:
:This override can affect:
:*Alarm running - It is even required if alarm run is called via "If no gun" alarm run behavior, otherwise glitches will appear.
:*Alarm running: It is actually required if an alarm run is called via the no-gun alarm run behavior, otherwise glitches will appear.
:*Retreating behavior - When "If no gun" is set as "Retreat", unarmed A.I. character will try to run away from its enemy. However, if enemy meets Melee override parameter (for example get into Short range while Melee overrride is set to ShortRange), then this A.I. stops running away and starts attacking the enemy.
:*Retreating behavior - When the no-gun behavior is set as "Retreat", an unarmed AI will try to run away from its enemy. However, if enemy meets the Melee override parameter (for example getting into the Short range while the melee override is set to ShortRange), then this AI stops running away and starts attacking the enemy.
:*Weapon firing - If distance between A.I. character and its enemy is smaller than minimal shooting distance, A.I. tries to run away from its enemy (still facing the enemy) till distance between characters is greater than minimal shooting distance. However, this backpedal behavior can be overriden by "Melee override" if all conditions are met - A.I. character then starts using melee (even with loaded weapon in hand) for at least 10 seconds (hardcoded timer) After ten seconds A.I. tries to restore its previous behavior. If enemy is still too close, Melee override is immediately applied again.  
:*Weapon firing: If the distance between the AI and its enemy is smaller than the minimum shooting distance, the AI tries to backpedal away from its enemy till the distance between characters is greater than the minimum shooting distance. However, this backpedal behavior can be overridden by the melee override if all conditions are met; the AI then starts using melee (even with a loaded weapon in hand) for at least 10 seconds (hardcoded timer). After ten seconds, the AI tries to resume its previous behavior. If the enemy is still too close, the melee override is immediately applied again.
:*Weapon pickup - if A.I. is trying to pick up a weapon and enemy crosses the range specified in MeleeOverride, then weapon pickup behavior is overridden by melee.
:*Weapon pickup: if the AI is trying to pick up a weapon and an enemy crosses the range specified in MeleeOverride, then the weapon pickup behavior is overridden by melee.
:*Maybe some other aspects of A.I. behavior?
:*Maybe some other aspects of AI behavior?






'''"If no gun" behavior ([[CMBT]] profile)''' - this parameter tells A.I. character what kind of action A.I. should do if it is unarmed or has empty weapon and no spare clips. Possibilites are (xml strings in brackets):
'''No-gun behavior ([[CMBT]] profile)''': This parameter tells the AI what kind of action it should take if it is unarmed or has an empty weapon and no spare clips. Possibilities are (XML strings in parentheses):
:*Melee (Melee) - A.I. character attacks enemy with hand to hand combat  
:*Melee (Melee): The AI attacks the enemy with hand-to-hand combat.
:*Retreat (Retreat) - A.I. character runs away from its enemy (a bit glitchy, but works)
:*Retreat (Retreat): The AI runs away from its enemy (a bit glitchy, but works).
:*Run For Alarm (RunForAlarm) - see section [[#Alarm behavior - "She's everywhere!"|Alarm behavior]]. Remainder: this alarm calling behavior requires Melee override set as ShortRange, MediumRange or AlwaysMelee, otherwise alarm behavior gets glitched and A.I. character gets stuck. If no alarm console is found within Alarm search distance, A.I. character resorts to melee.
:*Run For Alarm (RunForAlarm): see section [[#Alarm behavior|Alarm behavior]]. Reminder: this alarm-running behavior requires the melee override to be set in ShortRange, MediumRange or AlwaysMelee, otherwise the alarm behavior gets glitched and the AI gets stuck. If no alarm console is found within the alarm search distance, the AI resorts to melee.




[[File:GoForGun.JPG|thumb|right|alt=Picture showing A.I. moving to a weapon.|A.I. character moving to a weapon.]]
[[Image:GoForGun.jpg|thumb|right|alt=Picture showing AI moving to a weapon.|AI moving towards a weapon.]]
'''Weapon pickup behavior ([[ONCC]] file)''' - when in combat mode, unarmed A.I. character can be told to move to a loaded weapon and pick it up or to switch held empty gun for a loaded gun which is lying on the floor. Overall, A.I. characters only register pickable weapons which are lying around them up to a distance of 60 units (hardcoded). Weapons which are lying further than 60 units from the A.I. character are ignored. In [[ONCC]] file these parameters can be set to alter gun pickup behavior (xml tags in brackets ):
'''Weapon pickup behavior ([[ONCC]] file)''': When in combat mode, an unarmed AI can be told to move to a loaded weapon and pick it up or to swap a held, empty gun for a loaded gun which is lying on the floor. Overall, AIs can only register pickup-able weapons up to a distance of 60 world units (hardcoded). In the ONCC file, these parameters can be set to alter the gun pickup behavior (XML tags in parentheses):
:*Chance for pickup (GoForGunChance) - percentual chance of A.I. being told to go and pick up a weapon. It seems that the weapon closest to the A.I. character is always chosen to be picked up.
:*Chance for pickup (GoForGunChance): percent chance of AI deciding to go and pick up a weapon. It seems that the weapon closest to the AI character is always chosen to be picked up.
:*Running pickup (RunPickupChance) - percentual chance of A.I. picking the weapon by performing an evasion move (melee dodge move).
:*Running pickup (RunPickupChance): percent chance of AI picking up the weapon by performing an evasion (melee dodge) move.






'''Getting up after being knocked down ([[ONCC]] file)''' - if A.I. character is knocked to the ground, it stays on the ground for a while (simulation of concussion) then gets up. In [[ONCC]] file there are two parameters regarding getups (xml tags in brackets):
'''Getting up after being knocked down (ONCC file)''': If an AI is knocked to the ground, it stays on the ground for a while (a simulation of being stunned), then gets up. In the ONCC file there are two parameters regarding getting up (XML tags in parentheses):
:*Knockdown minimal number of frames (DazedMinFrames) - minimal number of frames for which A.I. character stays on the ground.
:*Knockdown minimum number of frames (DazedMinFrames): minimum number of frames that AI stays on the ground.
:*Knockdown maximal number of frames (DazedmaxFrames) - maximal number of frames for which A.I. character stays on the ground.
:*Knockdown maximum number of frames (DazedmaxFrames): maximum number of frames that AI stays on the ground.


:If knockdowned A.I. character gets hit by melee, it gets up immediately after the hit. Being hit by weapons does not make A.I. character instantly get up. Standard getups are simple ones (as if knockdowned player hit some direction key). If A.I. character is in melee combat mode, its MELE profile has getup attacks listed and enemy is within the required range, chance is this A.I. character will use getup attacks or instead of simple getups.
:If a knocked-down AI gets hit by melee, it gets up immediately after the hit. Being hit by weapons does not make AI character instantly get up. Standard get-ups are simple ones (the same result as if the knocked-down player hits a directional key). If the AI is in melee combat mode, its [[MELE]] profile has get-up attacks listed, and the enemy is within the required range, there is a chance that this AI will use a get-up attack instead of a simple get-up animation.






'''Making sure enemy is dead ([[ONCC]] file)''' - yes, even this is a part of Oni combat Artificial Intelligence.
'''Making sure enemy is dead (ONCC file)''': Yes, even this is a part of Oni's combat AI.
:When enemy is defeated in hand to hand fighting, A.I. character stands for a while and "checks" if enemy is dead. During this interval A.I. character can utter a short victory speech if corresponding sound slot in [[ONCC]] is filled and percentual chance roll is successful. Also during "check body" time interval A.I. character can perform a taunt animation if percentual roll is successful. Here are listed all related fields from [[ONCC]] file (xml tags in brackets):
:When the enemy is defeated in hand-to-hand fighting, the AI stands over them for a while to decide if the enemy is dead. During this interval, the AI can utter a short victory speech if the corresponding sound slot in its ONCC is filled and the percent chance roll is successful. Also during the "check body" time interval, the AI can perform a taunt animation if that roll is successful. Here are listed all the related fields from the ONCC file (XML tags in parentheses):
:*Investigate body (InvestigateBodyDelay) - time interval for which A.I. character stands next to its defeated enemy and stares at him.
:*Investigate body (InvestigateBodyDelay): Time period for which AI stands over its defeated enemy and stares at him/her.
:*Dead taunt chance (DeadTauntChance) - percentual chance of performing taunt animation.  
:*Dead taunt chance (DeadTauntChance): Percent chance of performing a taunt animation.  
:*Check body sound probability (CheckBodyProbability) - Percentual chance of playing victory speech.
:*Check body sound probability (CheckBodyProbability): Percent chance of playing a victory speech.
:*Check body sound (CheckBodySound) - link to Oni Ambient sound file ([[OBD:OSBD/OSAm]]).
:*Check body sound (CheckBodySound): A link to an Oni ambient sound file ([[OBD:OSBD/OSAm|OSAm]]).




:If the enemy is defeated by weapon, then A.I. character keeps shooting this dead enemy for some extra time to "make sure" the enemy is dead, then comes close to investigate the body. No taunts, no win phrases. Parameters of this behavior are:
:If the enemy is defeated by weapon, then the AI keeps shooting this dead enemy for some extra time to make sure the enemy is dead, then comes close to investigate the body. No taunts, no win phrases. The parameters of this behavior are:
:*Dead make sure (DeadMakeSureDelay) - time interval for which A.I. character keeps shooting the dead enemy
:*Dead make sure (DeadMakeSureDelay): Time period for which the AI keeps shooting the dead enemy.
:*Investigate body (InvestigateBodyDelay) - it is the same as the one listed above.
:*Investigate body (InvestigateBodyDelay): Same as the one listed above for melee.




Modding hints - behaviors enlisted in this section can be combined to achieve quite impressive results.
Modding hints - the behaviors listed in this section can be combined to achieve quite impressive results.
:*Unfortuantely, Oni does not provide (code-wise) any A.I. routines to deal with dynamic holstering and unholstering of possessed weapons. Thus, melee overrides are the only way how make armed A.I. character somehow defend itself when enemy gets too close.  
:*Unfortunately, Oni does not provide any AI settings that deal with intelligent holstering and unholstering of weapons in their possession. Thus, melee overrides are the only way to make an armed AI somehow defend itself when the enemy gets too close to use its weapon.
::Nevertheless, [[BSL]] provides function to make character holster or unholster a weapon - '''chr_forceholster'''. In order to make a character holster the held weapon, this character has to be using pistol or rifle animation variant (see [[TRAM]]). Since A.I. characters can use walk_noaim and run_noaim movmement modes (which disable weapon variant i.e. aiming with weapon), the weapon variant should be explicitly coerced via BSL function '''chr_dontaim'''. Unholster is easier, simply character has to be be executign some overlay-comaptible animation at the moment when chr_forceholster is executed. That means standing/running/crouching/walking/jumping is OK and function will succeed, but attack animations or animations of getting hit are not OK and function will fail.
::Nevertheless, BSL does provide a function to make a character holster or unholster a weapon: [[chr_forceholster]]. In order to make a character holster a held weapon, this character has to be using a pistol or rifle animation variant (see [[TRAM]]). Since AI can use "walk_noaim" and "run_noaim" movement modes (which disable weapon variants, i.e., aiming with weapons), the weapon variant should be explicitly forced on via the BSL function [[chr_dontaim]]. Unholstering is easier: the character simply has to be be executing some aiming overlay-compatible animation at the moment when chr_forceholster is executed. That means standing, running, crouching, walking, and jumping are OK -- the function will succeed -- but attack animations or animations of getting hit are not OK and the function will fail.
::*IMPORTANT NOTE: The A.I. character must be "active" all the time in order to perform BSL animation checks ('''chr_wait_'''''animation/animtype/animstate'' checks). Remember that Oni was made back in years 2000/2001, so various tricks were used to save memory and enhance performance. One of these feints is making invisible characters (behind wall, behind closed doors etc) go into INACTIVE mode, which means they are only stored in a RAM memory as a structure, but no physics, no checks for collisions and no drawing functions are applied on them in order to save system resources (BTW yes, that means inactive characters can walk in air and pass through walls). On the contrary when character is ACTIVE, it is fully operational, physics working, collisions being checked and character being ready in graphics memory to be drawn anytime. To make sure character stays active means either applying individually "'''chr_lock_active''' ''ai_name''", or (since now is year 2011 ^_^) simply applying "'''chr_all_active=1'''" to make all characters be ready to be drawn anytime.
::*IMPORTANT NOTE: The AI must be "active" all the time in order to perform BSL animation checks ([[chr_wait_animation]]/[[chr_wait_animtype|animtype]]/[[chr_wait_animstate|animstate]] checks). Remember that Oni was developed mostly in the '90s, so various tricks were used to save memory and enhance performance. One technique was to make unseen characters (behind a wall, closed doors, etc.) go into an "inactive" mode, which means they are only stored in RAM as a structure, but no physics, collision checks, or drawing functions are performed on them in order to save system resources (and yes, that means inactive characters can [https://www.youtube.com/watch?v=GC4HLDekxQI walk in mid-air and pass through walls]). On the other hand, when a character is active, it is fully operational, with physics working, collisions being checked, and character being ready in graphics memory to be drawn any time. To make sure a character stays active requires either applying [[chr_lock_active]] to each AI, or (since computers have a lot more memory these days) simply setting [[chr_all_active]] to 1 to force all characters active.
::Here is a simple example of a BSL scripted holster behavior. Character is given a gun, then weapon is holstered. When this A.I. character notices enemy and plays startle animation, then unholster is called. [http://www.youtube.com/watch?v=2WNMh8u5wBI THIS YouTube video] shows the script in action.
::Here is a simple example of a holster behavior scripted in BSL. A character is given a gun, then the weapon is holstered. When this AI notices an enemy and plays its startle animation, then an unholster is called for. [https://www.youtube.com/watch?v=2WNMh8u5wBI This YouTube video] shows the script in action.


   #Setup of A.I. - gets spawned, forced to be always active, weapon gets holstered.
   #Setup of AI - gets spawned, forced to be always active, weapon gets holstered.
   ai2_spawn A_t48
   ai2_spawn A_t48
   chr_giveweapon A_t48 w1_tap
   chr_giveweapon A_t48 w1_tap
Line 381: Line 371:
   chr_forceholster A_t48 1
   chr_forceholster A_t48 1
   sleep 1
   sleep 1
   #Surprise behavior - unholster weapon when A.I. character is startled
   #Surprise behavior - unholster weapon when AI character is startled
   chr_wait_animtype (A_t48, Startle_Forward, Startle_Back, Startle_Left, Startle_Right)
   chr_wait_animtype (A_t48, Startle_Forward, Startle_Back, Startle_Left, Startle_Right)
   chr_forceholster A_t48 0
   chr_forceholster A_t48 0
   #Aftermath - A.I. is usually walking only if it is not in combat mode, so let's use it as a trigger that weapon can be holstered.
   #Aftermath - AI is usually walking only if it is not in combat mode, so let's use it as a trigger that weapon can be holstered.
   chr_wait_animtype (A_t48, Walk, Walk_Backwards)
   chr_wait_animtype (A_t48, Walk, Walk_Backwards)
   chr_dontaim A_t48 0
   chr_dontaim A_t48 0
Line 391: Line 381:




:*Melee override can be used together with "Go For Gun" behavior and properly sized Short combat range to create A.I. characters who jump the gun each time they have a chance yet they are not allowing enemy to land free hits in the process (If enemy gets too close, Short range melee override kicks in).
:*A melee override can be used together with the "Go For Gun" behavior and a properly-set Short combat range to create AIs who go for a gun any time they have a chance, yet they are not allowing an enemy to land free hits in the process (if the enemy gets too close, the Short range melee override kicks in).


:*"If No Gun" behavior "Retreat" works in a rather simple manner - if unarmed, A.I. character is given a desire to run as far away from the enemy as possible. This behavior can look a bit awkward, but is useful for making more life-like civilians. Combined with Melee override at "short range" or "if punched" and a bit of BSL scripting to deliberately switch between "combatant" and "non-combatant", a modder can achieve impressive yet lightweight (on game engine) results. [http://www.youtube.com/watch?v=BTGQTAoU_1E See this YouTube video.]
:*The no-gun behavior "Retreat" works in a rather simple manner: if unarmed, an AI is given a desire to run as far from the enemy as possible. This behavior can look a bit awkward, but is useful for making more life-like civilians. Combined with Melee override at "Short range" or "If punched", and a bit of BSL scripting to deliberately switch between "combatant" and "non-combatant", a modder can achieve impressive results without only a light load on the game engine. [https://www.youtube.com/watch?v=BTGQTAoU_1E See this YouTube video.]


:*Setting short getup times is a good way to make A.I. driven character formidable opponent in hand to hand combat. However, too short getup times can introduce problems. It is a good idea to experiment with getup parameters till the character feels "natural".
:*Setting short get-up times is a good way to make an AI-driven character a formidable opponent in hand-to-hand combat. However, too-short get-up times can introduce problems. It is a good idea to experiment with get-up parameters till the character feels "natural".


:* Don't overextend "Check body" and "Dead make sure" timers. It looks silly and on top of that it makes A.I. characters easy targets of a surprise rear throw.
:*Don't over-extend the "Check body" and "Dead make sure" timers. It looks silly, and on top of that it makes AIs easy targets for a rear throw.








==Combat behavior part 3: "They see me shootin', they hatin'..."==
==Weapon combat behaviors==
Back in 2001 Oni was highly praised for its mixture of shooting and hand to hand combat. Now what could A.I. designers of Oni possibly do to make A.I. characters aim, pull a trigger or to make them avoid being hit by enemy? In this section, [[ONWC]], together with [[ONCC]] and [[PAR3]] will tell the story.
Back in 2001, Oni was highly praised for its mixture of shooting and hand-to-hand combat. Now what could the AI designers for Oni possibly do to make AI characters aim a gun, pull a trigger or avoid being hit by enemy gunfire? In this section, settings found in [[ONWC]], together with [[ONCC]] and [[PAR3]], will tell the story.


:First let's look into [[ONCC]] file. In XML file, under <AIConstants>, there's a tag named <Flags>. In binary file it is a bitset, so more than one flag can be written into it. XML strings for flags are:
:First let's look into the ONCC file. In an XML export of this file, under <AIConstants>, there's a tag named <Flags>. In the original binary data it is a bitset, meaning that more than one flag can be active at a time. The XML strings for the flags are:
:*noStartleAnim - Disables startle animation when A.I. sees the enemy for the first time.
:*noStartleAnim: disables the startle animation that can occur when the AI sees the enemy for the first time.
:*EnableMeleeDodge - Enables firingspread/projectile dodging when A.I. is in pathfinding mode or combat melee mode
:*EnableMeleeDodge: enables firing spread/projectile dodging while the AI is in pathfinding mode or melee combat mode.
:*RunAwayDodge - Enables firingspread/projectile dodging even when A.I. itself is shooting a gun. A.I. character stops shooting and tries to move away from the danger area.  
:*RunAwayDodge: enables firing spread/projectile dodging even while the AI itself is shooting a gun. The AI will stop shooting and try to move away from the danger area.  
:*ShootDodge -  Enables firingspread/projectile dodging even when A.I. itself is shooting a gun. A.I. character keeps shooting its enemy while at the same time attempts to move away from the danger area.  
:*ShootDodge: enables firing spread/projectile dodging even while the AI itself is shooting a gun. The AI will keep shooting at its enemy while at the same time attempting to move away from the danger area.  
:*NotUsed - Some ONCC character have this bit set, however it looks like it does nothing.
:*NotUsed: Some characters have this bit turned on, however it looks like it does nothing.


[[File:Firingspread.PNG|thumb|right|alt=Example of a firingspread.|Example of a firingspread.]]
[[Image:Firingspread.png|thumb|right|alt=Example of a firing spread.|Example of a firing spread.]]
[[File:Projectile.PNG|thumb|right|alt=Example of a particle with A.I. projectile dodge radius.|Example of a projectile with A.I. dodge radius (blue sphere).]]
[[Image:Projectile.png|thumb|right|alt=Example of a particle with an AI projectile-dodge radius.|Example of a projectile with AI dodge radius (blue sphere).]]
'''Gunfire dodging mechanics'''. Gunfire dodging mechanics is a quite interesting part of Oni A.I. system. Interesting because the retail version features little to no such a behavior displayed which is sad because it gives a feeling of challenge to a gunplay. In order to make A.I. character perform dodge mechanics, this A.I. must be in combat mode with some enemy. Without combat mode and some enemy, A.I. character won't dodge. Next, A.I. characters perform dodge when the character intersects with:
'''Gunfire dodging mechanics'''. Gunfire dodging mechanics are quite an interesting part of Oni's AI system -- interesting because the retail version displays little to no such behavior, which is sad because it adds challenge to the gunplay. In order to make an AI perform gunfire dodging, this AI must be in combat mode with an enemy. Without combat mode and some enemy, AI character won't dodge. Additionally, an AI will only perform a dodge when the character senses one of these two things:
:*Firingspread - can be seen by '''ai2_showfiringspreads=1'''. Firing spread is an invisible prism (dimensions set in [[ONWC]]) which can be created when a weapon is fired. Not every gun has a firingspread as for some guns firingspread is useless (SCRAM cannon, SuperBall gun). If A.I. character can dodge gunfire and intersects with a firingspread, this A.I. character starts gunfire dodging mechanics.
:*Firing spread. This can be seen by using [[ai2_showfiringspreads]]. The firing spread has the shape of a prism (its dimensions set in ONWC) which can be created when a weapon is fired. Not every gun has a firing spread, as for some guns a firing spread is useless (e.g. the Scram Cannon and Super Ball Gun). If an AI can dodge gunfire and intersects with a firing spread, this AI character starts its gunfire dodging behavior.
:*Projectile - epic win of Oni modders, can be seen with '''ai2_showprojectiles=1'''. In retail version of Oni, projectile dodging '''is defunct''' due to a couple of bugs in a projectile dodging code. Since the engine hackers/modders '''fixed this issue''', A.I. characters can execute gunfire dodge mechanics versus [[PAR3]] particle, if these A.I.s are in combat mode with some enemy and the particle has set <AIDodgeRadius> to a positive non-zero value.
:*Projectile. The epic win of Oni modders. In the retail version of Oni, projectile dodging is basically broken due to a couple of bugs in the code. Since the engine hackers/modders fixed this issue, AIs can now dodge projectiles properly. Visualize this feature with [[ai2_showprojectiles]]. AIs will dodge particles themselves if they are in combat mode with some enemy and the particle (e.g. the Screaming Cell Cannon's projectile) has <AIDodgeRadius> set to a positive non-zero value.




:A.I. parameters regarding gunfire dodging are set in [[ONCC]] (xml tags in brackets):
:AI parameters regarding gunfire dodging are set in ONCC (XML tags in parentheses):
:*Dodge reaction delay (DodgeReactFrames) - a delay in number of frames. This delay makes A.I character wait a bit inside danger zone before this A.I. character starts its reaction on firingspred/projectile.
:*Dodge reaction delay (DodgeReactFrames): a delay, in number of frames, which makes an AI wait a bit inside a danger zone before starting its reaction to the firing spread/projectile.
:*Dodge timescale (DodgeTimeScale) - how long should the A.I. character's gunfire dodge reaction last.
:*Dodge timescale (DodgeTimeScale): how long the AI's gunfire dodging behavior should last.
:*Dodge weight (DodgeWeightScale) - how strong is the desire (???length of vector???) of this A.I. character to dodge a gunfire. Dodge can add together with other "vector" movements and a sum of all vectors is the direction in which A.I. character will try to move.
:*Dodge weight (DodgeWeightScale): how strong the desire (as a length of vector???) is for this AI character to dodge gunfire. The dodge weight can add together with other "vector" movements, and a sum of all vectors is the direction in which the AI will try to move.




:Parameters of firingspread in [[ONWC]] are (xml tags in brakets):
:Parameters of firing spread in ONWC are (XML tags in brakets):
:*Firingspread length (FireSpreadLength)
:*Firing spread length (FireSpreadLength)
:*Firingspread width (FireSpreadWidth)
:*Firing spread width (FireSpreadWidth)
:*Firingspread skew (FireSpreadSkew)
:*Firing spread skew (FireSpreadSkew)


:Parameter of projectile dodging in particle system [[PAR3]] is A.I. dodge radius (AIDodgeRadius).
:The parameter for projectile dodging in the particle system (PAR3) is the AI dodge radius (AIDodgeRadius).






'''A.I. character's prowess with guns'''. Still in [[ONCC]], there are data how "skillful" this A.I. character should be with each weapon in the game. Weapons are indexed (starting from zero) as follows:
'''AI character's prowess with guns'''. Still in the ONCC, there are settings for how skillful this AI should be with [[Quotes/Weapons|each weapon in the game]]. Weapons are indexed (starting from zero) as follows:
:*w0_sec (0) - Only Bungie West empl-yees know what this weapon was supposed to be.
:*0: w0_sec - only Bungie West employees know what this weapon was supposed to be.
:*w1_tap (1) - TCTF automatic pistol
:*1: w1_tap - TCTF Automatic Pistol
:*w2_sap (2) - Syndicate sub-machine gun
:*2: w2_sap - Syndicate Automatic Pistol (the SMG)
:*w3_phr (3) - plasma rifle
:*3: w3_phr - Plasma Rifle
:*w4_psm (4) - phase stream projector
:*4: w4_psm - Phase Stream Projector
:*w5_sbg (5) - grenade launcher alias SuperBall Gun
:*5: w5_sbg - Super Ball Gun
:*w6_vdg (6) - stun gun ('''V'''an '''D'''e '''G'''raaf gun)
:*6: w6_vdg - Van de Graaff Gun
:*w7_scc (7) - scram cannon (swarm of small homing rockets)
:*7: w7_scc - Scram Cannon
:*w8_mbo (8) - mercury bow
:*8: w8_mbo - Mercury Bow
:*w9_scr (9) - screaming cannon
:*9: w9_scr - Screaming Cell Cannon
:*w10_sni (10) - Mukade's Devil star (annoying red ball) as a holdable weapon; probably a relic from game development  
:*10: w10_sni - Mukade's Devil Star (heat-seeking red ball) as an invisible weapon; probably a relic from game development.
:*w10_ba1 (11) - Barabas' gun
:*11: w10_ba1 - Barabas' gun, the Wave Motion Cannon.
:*w11_ba2 (12) - Barabas' gun; this one cannot be shot and is probably just a development relic.
:*12: w11_ba2 - Barabas' gun; this one cannot be shot and is probably a development relic.




:For each one of these weapons, there are in ONCC defined these parameters (xml tag in brackets):
:For each weapon, the ONCC defines these parameters (XML tag in parentheses):
:*Recoil compensation (RecoilCompensation) - How much the A.I. cahracter compensates the recoil of the weapon. Setting this to 0.0 mean no compensation, setting this to 1.0 means full compensation.
:*Recoil compensation (RecoilCompensation): how much the AI character compensates for the recoil (vertical stray) of the weapon. Setting this to 0.0 means no compensation, and setting this to 1.0 means full compensation.
:*Best aiming angle (BestAimingAngle) - In radians, but question is whether it really affects aiming.
:*Best aiming angle (BestAimingAngle): in radians, but the question is whether it really affects aiming.
:*Shoot group error (ShotGroupError) - Random deviation of A.I.'s aim within the target spot. Incorporated to simulate human inaccuracy. Can be set more than 1.0.  
:*Shoot group error (ShotGroupError): the random deviation of the AI's aim from the target spot. Incorporated to simulate human inaccuracy. Can be set higher than 1.0.  
:*Shoot droup decay (ShotGroupDecay) - Random deviation of the target spot. Target spot is always loosely based on enemy's position. Can be set more than 1.0.
:*Shoot group decay (ShotGroupDecay): the random deviation of the target spot itself. The target spot is naturally based on the enemy's position. Can be set higher than 1.0.
:*Shooting inaccuracy multiplier (ShootingInaccuracyMultiplier) - How much can A.I. stray with its aim from the target. Not clear how much it really affects aiming.
:*Shooting inaccuracy multiplier (ShootingInaccuracyMultiplier): also controls the degree that the AI's aim strays from the target, but it's not clear how much it really affects aiming.
:*Minimal shooting delay (MinShotDelay) - Minimal pause between reload and the beginning of a gunfire for this A.I. character.
:*Minimum shooting delay (MinShotDelay): minimum pause between reloading and resuming firing.
:*Maximal hooting delay (MaxShotDelay)- Minimal pause between reload and the beginning of a gunfire for this A.I. character.
:*Maximum shooting delay (MaxShotDelay): maximum pause between reloading and resuming firing.








'''Targeting and prediction''' of enemy's movement. Apart from majority of other games, Oni A.I. does not "cheat" by being 100% accurate and then having some kind of additive error (even tough additive error is present in Oni, see above). It is a bit inverse - there's a bit of a problem making A.I. being a reasonably precise marksman ^_^. A.I. character is given input parameters such as distance between characters, present velocity of its enemy (vector) and velocity of held gun's projectile (number, not a vector). From this data, A.I. logic computes a prediction of enemy's location and ideal aiming direction in order to hit the enemy.
'''Targeting and prediction''' of the enemy's movement. Unlike the majority of other games, Oni's AI does not "cheat" by starting from 100% accuracy and then adding some degree of error (even though additive error is also present in Oni; see above). To the contrary, there's a bit of a problem making the AI a precise marksman ^_^. The AI is given input parameters such as the distance between itself and the enemy, the present velocity of its enemy (as a vector), and the velocity of their gun's projectile (as a number, not a vector). From this data, the AI logic computes a prediction of the enemy's location and the ideal aiming vector for hitting the enemy.
:[[ONCC]] parameters for targeting and prediction (xml tags in brackets):
:The ONCC parameters for targeting and prediction are (XML tags in parentheses):
:*Predict amount (PredictAmount)- Some sort of multiplier for prediction mechanics.  
:*Predict amount (PredictAmount): some sort of multiplier for prediction mechanics.  
:*Predict position delay (PredictPositionDelay) - In frames, delay before prediction is applied, so A.I. characters always uses a bit outdated prediction result.
:*Predict position delay (PredictPositionDelay): in frames, the delay before prediction is applied, so that the AI always somewhat-outdated prediction.
:*Predict delay frames (PredictDelayFrames) - In frames, delay before prediction is computed. Must be set at least to 1.0.
:*Predict delay frames (PredictDelayFrames): in frames, the delay before prediction is computed. Must be set to at least 1.0.
:*Predict velocity frames (PredictVelocityFrames) - Number of frames interval but meaning not 100% sure. Maybe enemy's velocity data are obtained and used for prediction algorithm during the interval? Must be set at least to 2.0.
:*Predict velocity frames (PredictVelocityFrames): this is a period of time in number of frames, but the meaning is not 100% clear. Maybe the enemy's velocity data is obtained and used for prediction algorithm during this period of time? Must be set to at least 2.0.
:*Predict trend frames (PredictTrendFrames) - Number of frames interval but meaning not 100% sure. Maybe a trend (sort of extrapolation of enemy's movement) is computed with data from this interval? Must be set at least to 2.0.
:*Predict trend frames (PredictTrendFrames): another period of time in number of frames that is not 100% clear. Maybe the distance ahead that extrapolation of the enemy's movement takes place? Must be set to at least 2.0.


:[[ONWC]] parameters for targeting and prediction (xml tags in brackets):
:The ONWC parameters for targeting and prediction are (XML tags in parentheses):
:*Prediction speed (PredictionSpeed) - More precisely "projectile prediction speed". This value is taken by prediction algorithm as a speed of a projectile fired with the corresponding fire mode of the [[ONWC]] weapon. Thus when actual [[PAR3]] projectile's speed is changed, prediction behavior produces misleading values (A.I. is unable to hit moving targets).
:*Prediction speed (PredictionSpeed): more precisely "projectile prediction speed". This value is taken by the prediction algorithm as the speed of a projectile fired with the corresponding fire mode of the ONWC weapon. Thus, when the actual PAR3 projectile's speed is changed, this prediction behavior produces misleading results (i.e., the AI is unable to hit moving targets).
:*Maximal inaccuracy angle (MaxInaccuracyAngle) - Maximal allowed deviation of aim from the enemy's character pelvis in order to keep firing the weapon. If exceeded, A.I. ceases fire and corrects aiming, the resumes fire. Pelvis is taken as a root point of the character, so without any extra chages done to targeting origin and targeting vector (see [[ONWC]]) A.I. characters always target pelvis of the enemy.
:*Maximum inaccuracy angle (MaxInaccuracyAngle): maximum allowed deviation of aim from the enemy's pelvis while firing the weapon. If exceeded, the AI ceases fire and corrects its aiming, then resumes fire. The pelvis is considered to be the root point of the character, so without any modifications made to the targeting origin and vector (see ONWC), AIs always target the pelvis of the enemy.
:*Aim radius (AimRadius) - no idea what it does.
:*Aim radius (AimRadius): no idea what this does.
:*Ballistic projectile speed (ProjectileSpeed) - special prediction can be used if weapon is meant to fire relatively slow but gravity affected projectiles (grenades). A.I. then adjusts aiming in order to hit enemy with the projectile according to the ideal (parabolic) ballistic curve. This is a horizontal speed component.
:*Ballistic projectile speed (ProjectileSpeed): a separate prediction method can be used if the weapon fires gravity-affected projectiles (e.g. grenades). The AI then adjusts its aiming in order to hit the enemy using the ideal (parabolic) ballistic curve. This is a horizontal speed component.
:*Ballistic projectile gravity (ProjectileGravity) - vertical gravity attraction for the projectile.
:*Ballistic projectile gravity (ProjectileGravity): the vertical gravity component of the same projectile.


:*Targeting direction (Direction) - Vector with three components (x, y, z) which gives orientation of a firingspread. When set to wrong values, firingspread will not cover area where the weapon shoots, but will be pointing in some other direction ( can even point backwards ^_^). Friendly advice: do not alter unless needed.
:*Targeting direction (Direction): a vector with three components (x, y, z) which gives the orientation of a firing spread. When set to wrong values, the firing spread will not cover the area where the weapon actually shoots (it can even point backwards ^_^). Friendly advice: do not alter unless needed.


:*Targeting origin (Origin) - Vector with three components (x, y, z) which tells A.I. where to fire according to enemy's pelvis position. When armed A.I. is in combat mode with the enemy and shoots him, the A.I. searches for pelvis (see [[TRIA]]) as the pelvis is the only bone recognized by A.I. system. For A.I., pelvis is a representation of a whole character. Now when A.I. fires at its enemy, the A.I. aims for pelvis. The vector described in this parameter tells A.I. where and how much to deviate from enemy's pelvis position.
:*Targeting origin (Origin): a vector with three components (x, y, z) which tells the AI where to fire in relation to the enemy's pelvis. When an armed AI is firing at an enemy, the AI searches for his/her pelvis (see [[TRIA]]), as the pelvis is the representation of the whole character in the AI system. The vector described in this parameter tells the AI how much and in which direction to deviate from the enemy's pelvis position.
::So when the vector is set as (0, 0, -2), A.I. will aim and fire at enemy's pelvis position + two units above. That means A.I. will fire ABOVE the pelvis position. Here is described effect of setting "x,y,z" from SHOOTER's point of view. First to positive, then to neative value:
::So when the vector is set as (0, 0, -2), the AI will aim two world units above the enemy's pelvis position. Here is the effect of setting each component positive and then negative, from the shooter's point of view:
::*x - deviate forward/backward (does not have much of an effect)
::*x - deviate forward/backward (does not have much of an effect when firing at someone on the same floor, as you would expect)
::*y - deviate right/left
::*y - deviate right/left
::*z - deviate down/up (headshots, anyone?)
::*z - deviate down/up (headshots, anyone?)




'''Miscellaneous [[ONWC]] A.I. setup''' - there are a few more parameters in ONWC which affect A.I. behavior with the weapon. They are (xml tags in brackets):
'''Miscellaneous ONWC AI setup''' - there are a few more parameters in ONWC which affect AI behavior with a weapon. They are (XML tags in parentheses):
:*Minimal shooting distance (MinShootingDistance) - defines how close can enemy be to the armed shooting A.I. character. If enemy comes closer than this distance, A.I. stops shooting and tends to move back a bit (vector type of movement, see [[#Pathfinding and movement - "I think I will consult a map for a while..."|HERE]]) until the distance is again equal or greater than Minimal shooting distance. Then A.I. opens fire again. To witness the effect, see some A.I. operating an SBG when its enemy is close to it.
:*Minimum shooting distance (MinShootingDistance): defines how close the enemy can be to the AI that is firing. If the enemy comes closer than this distance, the AI stops shooting and tends to move backward (a vector-based movement; see [[#Pathfinding and movement|HERE]]) until the distance is again equal to or greater than the minimum shooting distance. Then the AI opens fire again. To witness this effect, watch an AI operating an SBG when its enemy is close to it.
::'''IMPORTANT''' - for some unknown reason, value from this field is '''divided by 2'''. So when 100 is set, ingame A.I. starts backing when its enemy is 50 units close to it.
::'''IMPORTANT''': for some unknown reason, the value from this field is '''divided by 2'''. So when set to 100, the AI starts backing up when its enemy is 50 units away.
:*Maximal shooting distance (MaxShootingDistance) - contrary to the parameter described above, this limits how far can enemy be till the A.I. stops shooting and tends to come closer. See some A.I. character shooting with w2_sap at distant enemy.
:*Maximum shooting distance (MaxShootingDistance): The opposite of the parameter described above, this limits how far away an enemy can be before the AI stops shooting and starts moving closer. Watch an AI shooting with the SMG at a distant enemy.
:*Fight timer (FightTimer) - a bit similar to timer-based BSL command '''chr_dontaim'''. Defines in frames for how long should A.I. switch from a weapon varient (shooting) to a melee varient (hand to hand combat) if this firing mode was used (don't forget, weapon can has two firing modes) and certain conditions were met. See below for ''KnockdownSwitcher'' and ''StunSwitcher'' flags explanations.
:*Fight timer (FightTimer): a bit similar to thetimer-based BSL command chr_dontaim. Defines in frames for how long should AI switch from a weapon variant (shooting) to a melee variant (hand-to-hand combat) if this firing mode was used (don't forget, a weapon can have two firing modes) and certain conditions were met. See below for ''KnockdownSwitcher'' and ''StunSwitcher'' flag explanations.




:*basic parameters of a weapon (pistol or rifle type, type of ammunition etc.) can be set as a various flags in [[ONWC]] flags field (<Flags> in xml). These three flags from them affect A.I. behavior (xml tags in brackets):
:*The basic parameters of a weapon (pistol or rifle, type of ammunition, etc.) can be set using various flags in the ONWC (<Flags> in XML). These three flags from among those affect AI behavior (XML tags in parentheses):
:**NoHolster - apart from holster disabled, this flag also makes A.I. character ignore this weapon on the ground. One exception is w10_ba1 when A.I. character has set Superammo flag (InfiniteAmmo in xml) in its [[CHAR]] profile, then this A.I. character can pick up WMC cannon. If A.I. character is given the weapon it will fire it, but if the weapon is lying on the ground and A.I. character does not have superammo flag, this A.I. character will never pick it up.
:**NoHolster: apart from disabling the ability to holster the weapon, this flag also makes the AI ignore this weapon when lying on the ground. One exception is w10_ba1 when the AI has the Superammo flag (InfiniteAmmo in XML) set in its CHAR profile; then this AI character can pick up the WMC cannon. If an AI is given the weapon, it will still fire it.
:**Stun switcher (StunSwitcher) - if the enemy is within armed A.I. character's shooting distance and was knockdowned, stunned or blownupped, the A.I. character switches to a melee for a time specified in the weapon's Fight timer (see above). The flag was designed specially for w6_vdg weapon.
:**Stun switcher (StunSwitcher): if the enemy is within an armed AI's shooting range and was knocked down, stunned or blown up, the AI switches to melee for a time specified in the weapon's Fight timer (see above). This flag was designed specially for w6_vdg.
:**Knockdown switcher (KnockdownSwitcher) - Similar to Stun switcher, but only knockdown or blownup makes A.I. switch to melee. Tailored for w4_psm, probably to avoid A.I. abuse of an unfair advantage the w4_psm weapon grants (enemy cannot get up as long as she/he is shot).
:**Knockdown switcher (KnockdownSwitcher): similar to Stun switcher, but only a knockdown or a blownup makes the AI switch to melee. Tailored for w4_psm, probably to avoid AI abuse of an unfair advantage that the PSP grants (the enemy cannot get up as long as she/he is being shot).








Modding hints: Phew, what a long section. Described material has plenty of modding possiblities. Still, modders should be aware of a few things:
Modding hints: Phew, what a long section. The described material has plenty of modding possibilities. Still, modders should be aware of a few things:
:*Don't set too strong dodge vector (DodgeWeightScale) and don't overdo it with dodge timer (DodgeTimeScale, the smallest possible value is 0.4; lower is not registered). Delay before gunfire dodging (DodgeReactFrames) should be minimal, otherwise it can happen A.I. won't start dodging till shooter's weapon is empty.
:*Don't set too high of a dodge vector (DodgeWeightScale), and don't overdo it with the dodge timer (DodgeTimeScale) -- the smallest possible value is 0.4; lower is not registered. The delay before gunfire dodging (DodgeReactFrames) should be minimal, otherwise it can happen that the AI won't start dodging till the shooter's weapon is empty.
::As a side note, there is a glitch in gunfire dodging. It is not a coding bug, but simple limitation of a "vector" type of movement. When A.I. starts gunfire dodge, it tries to get away from the source of danger (be it firingspread or projectile). And because vector movement works as a "desire" to go to some direction, it can happen A.I. will express a "desire" to go into wall. In such a case, character stops until the desire to move into a wall stops (in other words, until enemy stops shooting the A.I. character). When A.I. character is unarmed, she/he will try to switch between pathfinding movement (to go to enemy and attack him with melee) and vector projectile dodge movement, so it kind of looks like the A.I. still tries to dodge the gunfire. If weight of a gunfire dodge is set to be smaller than standard vector movement type weight, then A.I. even does not have to get stuck as it will run in zig-zag pattern towards the armed enemy.
::As a side note, there is a glitch in gunfire dodging. It is not a coding bug, but a limitation of the simple vector-based movement. When the AI starts its gunfire dodge, it tries to get away from the source of danger (be it a firing spread or projectile). And because vector-based movement works as a "desire" to go in some direction, it can happen that the AI will express a "desire" to go into a wall. In such a case, the character stops until the desire to move into a wall stops -- in other words, until the enemy stops shooting at the AI. When an AI character is unarmed, it will try to switch between pathfinding movement (go towards the enemy and attacking him with melee) and vector-based projectile dodging movement, so it kind of looks like the AI is still trying to dodge the gunfire. If the weight of gunfire dodging is set to be smaller than the standard vector-based movement weight, then the AI does not even have to get stuck, as it will run in a zigzag pattern towards the armed enemy.
::In case A.I. is armed with a loaded weapon, there is no point in A.I. running towards enemy. That means if the A.I. character starts dodging and meets a wall, this A.I. character gets "stuck" until enemy's gunfire stops. In case this character has set "ShootDodge" in [[ONCC]], it will at least fire back at the enemy shooter. But in case the character has set "RunAwayDodge", then it simply stands near the wall and stares and waits till enemy's gunfire ceases.
::If the AI is armed with a loaded weapon, there is no point in the AI running towards enemy. That means if the AI starts dodging and meets a wall, this AI gets "stuck" until the enemy's gunfire stops. If this character has "ShootDodge" set in their ONCC, it will at least fire back at the enemy shooter. But in case the character has "RunAwayDodge" set, then it simply stands near the wall and stares and waits till the enemy's gunfire ceases.


::From the text above it can be seen that gunfire dodge parameters should be set to make A.I. dodge but to not make dodge vector outweight the vector for moving towards the enemy.
::From this explanation, it can be seen that the gunfire dodge parameters should be set to make the AI dodge, but to not make the dodge vector outweigh the vector for moving towards the enemy.


:*A.I.'s skills with weapons (in [[ONCC]]) can be used greatly to create sharpshooters or rookies who cannot hold a gun properly. For example by setting "ShootGroupError = 10.0" for w1_tap, we create a total amateur who's hand shakes all over the place when he fires Campbell equalizer.
:*An AI's skills with weapons (in ONCC) can be used to create anything from sharpshooters to rookies who cannot hold a gun properly. For example, by setting "ShootGroupError" to 10.0 for w1_tap, we create a total amateur whose hand shakes all over the place when he fires the Campbell Equalizer. You can experiment with different settings in realtime using the ai2_skill* functions on the dev console line. See [https://www.youtube.com/watch?v=cxTz30YOPhc this video] where ai2_skill_error is used to override a character's original grouping error setting with new values.


:*Unless really needed, do NOT alter [[ONCC]] prediction parameters. Bungie set them quite reasonably and if they are messed, A.I. character loses the ability of prediction.
:*Unless really necessary, do NOT alter the ONCC prediction parameters. Bungie set them quite reasonably, and if they are messed with, the AI loses accurate predictive abilities.


:*In [[ONWC]], Prediction speed is used for a calculation of A.I.'s aim. The value should be exactly the same as the value of this weapon's projectile. Projectile's velocity is usually set in a emitter of a projectile particle ([[PAR3]]). That means Prediction speed and actual speed of a particle used as weapon's projectile may differ, the most significant case being w3_phr (plasma balls accelerate rapidly).
:*In ONWC, Prediction speed is used for a calculation of the AI's aim. This speed should be exactly the same as the speed of this weapon's projectile. A projectile's velocity is usually set in the emitter of the projectile particle (PAR3). The separate values means that the predicted speed and actual speed of a weapon's projectile may differ, the most significant case being w3_phr (plasma balls accelerate rapidly).
::If Prediction speed is set lower than the speed of a projectile is, A.I. will tend to shoot too much in front of the moving enemy since it will assume projectile is slower than it really is. On the other side, setting this value higher means A.I. will shoot more directly at the moving enemy (and probably miss) as the A.I. will assume projectiles are fast enough to hit the target.  
::If Prediction speed is set lower than the speed of a projectile, the AI will tend to shoot too far in front of an enemy moving left/right since it will assume the projectile is slower than it really is. On the other hand, setting this value higher means that the AI will shoot too directly at the moving enemy (probably missing), as the AI will think the projectiles are fast enough to hit the target.


:*Similar to Prediction speed, there are Ballistic projectile speed and Ballistic projectile gravity. When these two are set non-zero, A.I. assumes ballistic projectiles (grenades) and tries to shoot projectiles according to an ideal parabole (the solution with shorter fly time is always chosen). In order to make A.I. sucesfully hit enemy's pelvis, these two must again corespond with [[PAR3]] particles's speed and particles's gravity attraction, but they can be used for modding purposes as well. For example if projectiles's gravity attaction is 0.5 but in [[ONWC]] Ballistic projectile gravity is set as 0.3, A.I. will shoot projectiles at enemy's feet as it will assume that gravity attraction of the projectile is lower thus it does not have to aim so high in order to hit the pelvis (credits to [[user:Gumby|Gumby]]). Remember: for A.I. system, pelvis is a representation of a whole character.
:*Similar to Prediction speed, there are Ballistic projectile speed and Ballistic projectile gravity. When these two fields are set to non-zero values, the AI assumes that the projectiles are ballistic (e.g. grenades), and tries to shoot along a parabolic arc (the solution with shortest travel time is always chosen). In order to make AI successfully hit an enemy's pelvis, these values again must correspond with the particle's (PAR3) speed and gravity attraction, but they can be used for modding purposes as well. For example, if a projectile's gravity attraction is 0.5, but in the ONWC, the Ballistic projectile gravity is set as 0.3, the AI will shoot projectiles at the enemy's feet as it will assume that the gravity attraction of the projectile is lower and it does not have to aim so high in order to hit the pelvis (credit to [[User:Gumby|Gumby]]). Remember: for the AI system, the pelvis is a representation of a whole character.


:*Targeting origin vector ([[ONWC]]) can be utilized to make A.I. fire not directly at pelvis, but for example higher (negative "z" component), so A.I. can score headshots. So far such a change does not have any purpose as characters don't have damage multipliers for bodyparts. But maybe in future...or with Paradox's headshot mod / material dependent damage mod ideas (see [[XML:BINA/ONIE#Extra_damage_for_head_hits|HERE]]).
:*The targeting origin vector (ONWC) can be utilized to make the AI fire higher than the pelvis (with a negative "z" component), so the AI can score headshots. Currently, such a change does not have any purpose, as characters don't have separate damage coefficients for different body parts. But maybe in the future... or with Paradox's headshot mod... (see [[XML:BINA/ONIE#Extra_damage_for_head_hits|HERE]] for his material-dependent damage mod ideas).


:*One thing purposefully left out in main talk about weapons is that there is an option for A.I. chracters to make "startle" misses - when startled, A.I. fires at some random direction. Parameters for this behavior are in [[ONCC]] and [[ONWC]], but overall this feature is so subtle it does not need any special modding attention.
:*One thing purposely left out in our main discussion of weapons is that there is an option for AIs to perform "startle" misses -- when startled, the AI can fire in some random direction. The parameters for this behavior are in ONCC and ONWC, but overall this feature is so minor that it does not need any special modding attention.


:*Remember: in [[ONWC]], Minimal shooting distance is '''divided by 2'''. Reason is unknown, maybe some bug in a code.
:*Remember: in the ONWC, Minimum shooting distance is '''divided by 2'''. The reason is unknown (maybe some bug in the code).


:*Through modification of Minimal shooting distance in conjunction with BSL scripting, a modder can achieve pseudo-dynamic holster behavior. If enemy gets too close, A.I. start moving away, facing the enemy. Since simply backing away is almost never used by armed A.I. (it usually move to the side), it can be detected via BSL function '''chr_wait_animation''' and subsequent script makes A.I. character holster held weapon. To unholster, different animation check has to be used, for example a check for a taunt animation. In [[MELE]], modder can set up approppriate melee profile which makes A.I. character taunt only at safe distance.  
:*Through modification of Minimum shooting distance in conjunction with BSL scripting, a modder can achieve pseudo-intelligent holstering behavior. If an enemy gets too close, the AI will start backing away. Since this backing away motion is almost never used by an armed AI (it usually moves side-to-side), it can be watched for using the BSL function chr_wait_animation, and used as a trigger for scripting code to make the AI holster his weapon. To unholster, a different animation has to be watched for, such as a taunt animation. In [[MELE]], a modder can set up a melee profile which makes the AI taunt only at a safe distance.  
::Drawback of this modification is is that enemy ''will not fire the weapon at point blank range'' and also it limits Melee override in [[CMBT]] to be only None or IfPunched, otherwise instead of backing away, A.I. character goes directly into melee.
::A drawback of this modification is that the enemy ''will not fire his weapon at point blank range'', and also it limits the Melee override in [[CMBT]] to be only None or IfPunched; otherwise, instead of backing away, the AI goes directly into melee.








==Combat behavior part 4 : "Everybody was kung fu fighting..."==
==Melee combat behaviors==
Ah yes. After all those OTHER things, we finally got to how A.I. system handles the core gameplay feature of this game, hand to hand combat.
Ah yes. After all those OTHER things, we finally get to how the AI system handles the core gameplay feature of this game, hand-to-hand combat. First things first. As usual, a player can see her/his enemy trying to perform some move and react to it. An AI, however, cannot see a thing because it does not have eyes, nor a human brain. Thus the first question is, How does the AI learn about incoming attacks?
First things first. As usual, player can see her/his enemy trying to perform some move, so player can then react. A.I. character cannot see a thing beacuse it does not have human eyes nor human brain. Thus the first question is how the A.I. knows about incoming attacks?
[[Image:Melee zones.jpg|thumb|right|alt=Melee zones around a character|A rough illustration of melee zones.]]
[[File:Melee zones.JPG|thumb|right|alt=Melee zones around a character|Rough idea of melee zones.]]
:The answer lies within the [[TRAM]] files. Each animation which can hurt somebody should have "extents". Extents are invisible boundaries which tell the AI about the range of enemy attacks. There are two types, horizontal and vertical, but the more important thing AI-wise is that, without extents, attack TRAMs will not be registered by AI characters as attacks, so AI will not try to block or dodge them. As long as the attack has extents data, then the AI will have the needed knowledge of the path of the attacking character's body parts (see attack part of [[TRAM]]).
:Answer lies within [[TRAM]] files. Each animation which can hurt somebody should have EXTENTS. Extents are invisible marks which tell A.I. character how the attack's ''trajectory'' looks. There are two types, horizontal and vertical, but more important thing A.I. wise is that without extents attack TRAMs will not be registered by A.I. characters as attacks, so A.I. will not try to block them or dodge or attack with the [[TRAM]] animation properly. But if the attack has extents, then A.I. gets a complete knowledge of a whole path of attacking bodyparts of this enemy's attack (see attack part of [[TRAM]]).
:This info is used by the melee part of AI for defensive purposes (deciding what kind of evasive move to use, and whether to crouch or not) as well as for offensive purposes -- an AI will not execute an attack move unless it sees that the enemy falls within its attack move's extents.
:This info is used by melee part of A.I. for defense purposes (deciding what kind of dodge move to choose and whether to crouch or not) and for attack purposes - position move in melee techniques are used to give general info about the melee technique's positioning, but A.I. character will not execute the attack move of the technique till enemy is within chosen attack move's extent range.




:Also, for hand to hand purposes engine recognizes roughly four zones around a character, see picture on right. These zones are then corresponding with position moves, so when melee techique has for example CloseBack, then the only time this melee techique is listed for possible execution is when enemy is in the back of the A.I. character. In all other cases (enemy in left, right or front zone), this techique is NOT listed for use. Exception is a technique with GenerousDir flag, see below for more info.
:Also, for hand-to-hand purposes, the engine recognizes roughly four zones around a character (see picture on right). These zones correspond to positioning moves, so when a melee technique has, for example, CloseBack, then the only time this melee technique is listed for possible execution is when the enemy is in back of the AI. In all other cases (enemy in the left, right or front zone), this technique is NOT listed for use. The exception is when a technique has the GenerousDir flag set; see below for more info.




Fistfighting A.I. mode is handled via [[MELE]] profiles. MELE profile is assigned to the spawnable character in its [[CHAR]] profile. When in melee mode, A.I. character uses vector type of movement. Unless specified otherwise, A.I. character is made to run towards its enemy.
Melee mode AI combat is handled via [[MELE]] profiles. A MELE profile is assigned to a spawnable character in its [[CHAR]] profile. When in melee mode, an AI uses vector-based movement. Unless otherwise specified, the AI is inclined to run towards its enemy.
:[[MELE]] profile always contains these parameters (xml tags in brackets):
:A MELE profile always contains these parameters (XML tags in parentheses):
:*Character class (CharacterClass) - Link to an [[ONCC]] class. Level of importance of this parameter not known, but maybe it is neccessary in order to allow for performance of some attack moves (engine checks referenced [[ONCC]] class and its [[TRAC]]).
:*Character class (CharacterClass): link to an [[ONCC]]. The importance of this parameter not known, but maybe it is necessary in order to allow for some attacks to be performed (engine checks being performed through the ONCC and its [[TRAC]]).
:*Notice (Notice) - percentual chance that A.I. will register incoming attack. In retail profiles it is always set 100.
:*Notice (Notice): percent chance that AI will notice an incoming attack. In retail profiles, it is always set to 100.
:*Dodge base (Base inside Dodge) - percentual chance A.I. will try to use one of '''evade''' moves (if it has any in evade section of MELE profile) to avoid getting hurt.
:*Dodge base (Base inside Dodge): percent chance that AI will try to use an evasion moves (if it has any in the evade section of its MELE profile) to avoid getting hurt.
:*Dodge extra (Extra inside Dodge) - extra chance to dodge
:*Dodge extra (Extra inside Dodge): extra chance to dodge.
:*Dodge extra damage (ExtraDamageThreshold inside Dodge) - amount of damage for activation of extra dodge
:*Dodge extra damage (ExtraDamageThreshold inside Dodge): amount of damage needed to activate the extra chance of dodging.
:*Single block skill - (Single inside BlockSkill) - percentual chance of attempt to block incoming enemy's attack
:*Single block skill (Single inside BlockSkill): percent chance of an attempt to block an incoming attack.
:*Group block skill - (Group inside BlockSkill) - percentual chance of ???. Not sure, maybe of blocking more attackers?
:*Group block skill (Group inside BlockSkill): percent chance of maybe of blocking more attackers???


:*Not blocked (NotBlocked) - Multiplier which affects weight of techniques which will not be blocked by the enemy under current circuumstances (punch combo against opponent who is running forward).
:*Not blocked (NotBlocked): a multiplier which affects the weight of techniques which will not be blocked by the enemy under the current circumstances (such as a punch combo against an opponent who is running forward).
:*Must change stance (MustChangeStance) - Multiplier which affects weight of techniques which force enemy to change stance (standing, crouching) in order to block it under current circuumstances (leg sweep against standing opponent).
:*Must change stance (MustChangeStance): a multiplier which affects the weight of techniques which force the enemy to change stance (standing vs. crouching) in order to block them under the current circumstances (such as a leg sweep against a standing opponent).
:*Blocked but unblockable (BlockedButUnblockable) - Multiplier which affects weight of techniques that have "unblockable" flag in its attack part, see [[OBD:TRAM/raw0x14|TRAM-attack part]].
:*Blocked but unblockable (BlockedButUnblockable): a multiplier which affects the weight of techniques that have the "unblockable" flag set in their attack part (see [[OBD:TRAM/raw0x14|TRAM attack part settings]]).
:*Blocked but has stagger (BlockedButHasStagger) - Multiplier which affects weight of techniques that makes enemy stagger if the enemy blocks the technique. Depends on TRAM attack part settings (BlockStagger), see [[OBD:TRAM/raw0x14|TRAM-attack part]].
:*Blocked but has stagger (BlockedButHasStagger): a multiplier which affects the weight of techniques that would make the enemy stagger if the enemy does block them, that is, they have the "stagger" flag set in their attack part (see TRAM attack part settings).
:*Blocked but has blockstun (BlockedButHasBlockStun) - Multiplier which affects weight of techniques that lock enemy in a blocking animation for longer than 20 frames. Depends on TRAM attack part settings (BlockStun), see [[OBD:TRAM/raw0x14|TRAM-attack part]].  
:*Blocked but has block stun (BlockedButHasBlockStun): a multiplier which affects the weight of techniques that would trap the enemy in a blocking animation for longer than 20 frames, that is, they have the "block stun" flag set in their attack part settings (see TRAM attack part settings).
:*Blocked (Blocked) - Multiplier which affects weight of techniques that will be certainly blocked by the enemy under current circuumstances and will not stagger nor stun the enemy.
:*Blocked (Blocked): a multiplier which affects the weight of techniques that will definitely be blocked by the enemy under the current circumstances and will not stagger or stun the enemy.
:*Throw Danger (ThrowDanger) - Something with throws, but only Bungie West knows what's the meaning of this field.
:*Throw Danger (ThrowDanger): something to do with throws, but only Bungie West knows the meaning of this field.


:*DazedMinFrames, DazedMaxFrames - documented by Neo. Question is - do these two parameters actually have effect, since getup time is controlled from ONCC?
:*DazedMinFrames, DazedMaxFrames: These were documented by Neo, but the question is, Do these two parameters actually have any effect, since the get-up time is controlled from the ONCC?




Basic melee setup is done. Now the profile branches into '''attack''' part, '''evade''' part and '''maneouver''' part. Each part has a certain number of "melee techniques". Melee technique is a compound of one or more melee moves. ''Melee move'' is a simple element of hand to hand combat - attack, throw, positioning command or some maneuver. Maximal amount of techniques in one melee profile is 32. If this limit is exceeded, Oni crashes. Let's have detailed look at all three mentioned parts of [[MELE]] profile:
Our basic melee setup is done. Now the profile branches into an '''attack''' part, an '''evade''' part, and a '''maneuver''' part. Each part has a certain number of "melee technique" slots. A melee technique is a set of one or more melee moves. A melee move is any single element of hand-to-hand combat -- an attack, a throw, a positioning command, or some maneuver. The maximum number of techniques in one melee profile is 32. If this limit is exceeded, Oni crashes. Let's take a detailed look at all three parts of the MELE profile:
:*Attack branch - Techniques from this branch are executed when A.I. is trying to attack and hurt it enemy. Attack branch contains not only attack techniques, but also maneuver techniques as well (more about this later).
:*Attack branch: techniques from this branch are executed when the AI is trying to attack and hurt its enemy. The attack branch contains not only attack techniques, but also maneuver techniques (more about this later).
:*Evade branch - Techniques contain moves which are used to evade attack. That means escape moves (SHIFT + some direction) and/or various jumps/slides. These techniques are picked only when A.I. character reacts on incoming enemy's attack.
:*Evade branch: techniques containing moves which are used to evade an attack -- escape moves (as when the player presses crouch + some directional key) and/or various jumps/slides. These techniques are picked only when an AI is reacting to an incoming attack.
:*Maneuver branch - Techniques from this branch should be used by A.I. to maneuver around, in order to move not only in a straightforward fashion towards the enemy, but also circle around, retreat or advance. Unfortunately, this branch is probably a development relic. In order to see these techniques performed, global [[BSL]] variable '''ai2_spacing_cookies''' has to be set zero (0). That means A.I. cannot execute attacks. Only then A.I. starts performing techniques from this maneuver branch.
:*Maneuver branch: techniques from this branch should be used by the AI to maneuver around, so as to not just move in a straight line towards the enemy, but also circle around him, retreat, or advance. Unfortunately, this branch is probably a development relic. The AI only starts performing techniques from this maneuver branch when the global BSL variable [[ai2_spacing_cookies]] it set to zero, but that means that the AI cannot execute attacks.
::The idea was probably to make the A.I. execute a certain number of attacks (each attack "eats" a cookie), then make the A.I. maneuver a bit and so on and so on. But somehow this setup was abandoned (question is whether MELE was really planned that way ^_^ ) and techniques from this branch are de-facto never used. That means all maneouvring is done via Attack branch.
::The idea was probably that when the AI had run out of attacks to execute (each attack "eats" a cookie), the AI would use the maneuver branch for a bit until it got a new cookie, and so on and so on. But somehow this setup was abandoned (the question is whether MELE was really planned that way ^_^ ), and techniques from this branch are ''de facto'' never used. This means that all maneuvering is done via the Attack branch.




Structure of a melee technique:
Structure of a melee technique:
:*'''Name''' (debugging purposes only)
:*'''Name''' (for debugging purposes only)
:*'''Flags''' - possibilities are:
:*'''Flags''': the possibilities are:
::*Interruptible - This technique can "home" to some extent and if enemy gets away from its reach, technique is ended prematurely.
::*Interruptible: this technique can "home in" on the enemy to some extent, and if the enemy gets out of its reach, the technique is ended prematurely.
::*GenerousDir - This technique is enlisted for possible execution even when facing of the A.I. does not match position move of this technique (technique uses CloseLeft, enemy is directly in front). If technique is used, A.I. character positions itself in order to perform the techique (in our example case, A.I. chracter turns left side towards enemy and perform the technique).
::*GenerousDir: this technique is listed for possible execution even when the AI's facing does not match the position move of this technique (e.g. the technique uses CloseLeft but the enemy is directly in front). If the technique is used, the AI positions itself in order to perform the technique (in our example, the AI would turn his left side to the enemy and perform the technique).
::*Fearless - does this flag actually do something?
::*Fearless: does this flag actually do something?
:*'''Weight''' - Basic weight of the technique. Techniques are chosen randomly but with "weight" of the technique taken into account. Techniques with higher "weight" are used more often than those with lower "weight".
:*'''Weight''': the basic weight of the technique. Techniques are chosen randomly, but with the "weight" of the technique taken into account. Techniques with higher "weight" are used more often than those with lower "weight".
::Also, there are more factors which affect final weight of the technique. ''Basic weight'' of the technique is according to combat situation (position of the enemy, effect of moves in the technique) multiplied by one of MELE profile setup multipliers (NotBlocked, BlockedButHasStagger etc.), then it is also multiplied by some dimnishing value which decreases weight of the technique if it is used consencutively. And finally, weight of the technique is multiplied by some special "orange tiles" mutiplier, which downweights techniques that would make the A.I. "fall over the edge", aka dive into orange tiled area.
::Also, there are more factors which affect the final weight of the technique. The ''basic weight'' of the technique is, according to the combat situation (position of the enemy, effect of moves in the technique), multiplied by one of the MELE profile's multipliers (NotBlocked, BlockedButHasStagger, etc.), then it is also multiplied by some diminishing value which decreases the weight of the technique if it is used consecutively. And finally, the weight of the technique is multiplied by a special "orange tiles" multiplier, which weighs down techniques that would make the AI fall over an edge, that is, dive into a part of the pathfinding grid that would be visualized as an orange-tiled area.
:::The equation is PROBABLY very roughy something like this:
:::The equation is PROBABLY very roughly something like this:
:::Final weight = Basic weight * corresponding MELE profile setup multiplier * dimnish multiplier * "orange tiles" multiplier
:::Final weight = basic weight * corresponding MELE profile setup multiplier * diminish multiplier * "orange tiles" multiplier
:*'''"Importance"''' - documented by Neo. Does it have any effect?
:*'''"Importance"''': documented by Neo, but does it have any effect?
:*'''RepeatDelay''' - in frames, how long should be the technique unavailable after its use (to prevent from predictability). For this time the technique is not enlisted in a list of performable techniques.
:*'''RepeatDelay''': in frames, how long should the technique be unavailable after its use (to avoid predictability).
:*'''Moves''', possible types of moves are:
:*'''Moves''': the possible types of moves are:
::*Position - usually takes three parameters: minimal distance, maximal distance, tolerance range. Meaning of Minimal/Maximal distances is clear, tolerance range specifies extra distance (beyond chosen TRAM attack's extents) where A.I. chases the enemy till the enemy gets inside the extent range of the [[TRAM]] attack this A.I. charater wants to use. Then A.I. uses the TRAM attack ^_^.
::*Position: usually takes three parameters -- minimum distance, maximum distance, and tolerance range. The meaning of minimum/maximum distances is clear; the tolerance range specifies an extra distance (beyond the chosen TRAM's attack extents) over which the AI will chase the enemy till the enemy gets inside the extent range of the attack this AI wants to use.
:::Some position moves don't have any parameters (Crouch, StartToCrouch) and are used strictly for stance purposes - to make A.I. perform crouched or special attacks. Position moves are used to give the A.I. general sorting of available attacks, so based on the melee zone the enemy is in (see picture at the beginning of this section) only corresponding techniques are taken into account as "possible to be used" and the rest is ignored. [[OBD:BINA/OBJC/MELE/MoveList/Position|HERE is a list]] of all available position melee moves.
:::Some positioning moves don't have any parameters (Crouch, StartToCrouch) and are used strictly for stance purposes -- to make the AI perform crouched or special attacks. Positioning moves are used to give the AI variety in their available attacks, as techniques are chosen based on the melee zone the enemy is in (see picture at the beginning of this section). [[OBD:BINA/OBJC/MELE/MoveList/Position|HERE is a list]] of all available positioning moves in melee combat.
::*Attack - no parameter, simply some kind of attack action. [[OBD:BINA/OBJC/MELE/MoveList/Attack|HERE is a list]] of all available attack melee moves.
::*Attack: no parameter, just an attack action. [[OBD:BINA/OBJC/MELE/MoveList/Attack|HERE is a list]] of all available attack moves in melee combat.
:::Attack move can be the only move of a techique (no position move). If that is the case, then this techique is put into a list of possibly used techniques only when its prerequisities (positioning and stance) are met via other means. For example Kick_forward can be used without a Position move, but then it is evaluated only when the A.I. character gets within the extent range of its Kick_forward [[TRAM]] move. Then the A.I. chracter has to somehow get into correct position within extent range of the Kick_forward's TRAM (maybe via other melee techniques), otherwise the technique with Kick_forward is labeled as MISSBOUNDS. When all that is OK, this a melee technique is listed for possible use.
:::An attack move can be the only move in a technique (no positioning move). If that is the case, then this technique is put into a list of possibly techniques only when its prerequisites (positioning and stance) are met via other means. For example, Kick_forward can be used without a Position move, but since a move is evaluated only when the AI sees an enemy within its extents, the AI will have to get into the correct position for the attack by some other means (maybe another melee technique), otherwise the technique with Kick_forward will be labeled as MISSBOUNDS.
::*Throw - no parameter, simply some throw. [[OBD:BINA/OBJC/MELE/MoveList/Throw|HERE is a list]] of all available throw melee moves. Again can be standalone, under circuumstances described above.
::*Throw: no parameter, just a throw move. [[OBD:BINA/OBJC/MELE/MoveList/Throw|HERE is a list]] of all available throw moves in melee combat. As with an Attack, a Throw can be standalone, to be used under the circumstances described above.
::*Evade - no parameter, simply some evasive action. [[OBD:BINA/OBJC/MELE/MoveList/Evade|HERE is a list]] of all available evasion melee moves.
::*Evade: no parameter, just an evasive action. [[OBD:BINA/OBJC/MELE/MoveList/Evade|HERE is a list]] of all available evasion moves in melee combat.
::*Maneouver - up to three parameters, these moves are used to make A.I. character move around somehow (advance, retreat, circle left/right) or perform various movements (crouch, jump, taunt, use uncommon getup moves etc.) [[OBD:BINA/OBJC/MELE/MoveList/Attack|HERE is a list]] of all available maneuver melee moves. Almost all maneouver moves have a Duration ('''in seconds''') as a first parameter.
::*Maneuver: taking up to three parameters, these moves are used to make the AI move around (advance, retreat, circle left/right) or perform various movements (crouch, jump, taunt, use uncommon get-up moves etc.). [[OBD:BINA/OBJC/MELE/MoveList/Attack|HERE is a list]] of all available maneuver moves in melee combat. Almost all maneuver moves have a Duration ('''in seconds''') as a first parameter.
:In melee techniques there can be a mixture of melee moves. Very first move (shuold be position or maneouver) is evaluated to make sure if the technique can be performed under current positioning of the A.I. character and its enemy. However, throws and maneuvers are checked as well even if they are not the first tehnique, so if technique contains Throw_punch_behind, it will be listed for use only if the A.I. is in theback of its enemy. Surprisingly enough, pairing Kick_forward and Kick_back makes A.I. character kick forward when position is correct for kick forward move, then it kicks back even tough there is nothing to hit ^_^. Same with other directional attacks.
:Melee techniques can be a mixture of melee moves. The very first move (which should be positioning or maneuvering) is evaluated to make sure if the technique can be performed with the current positioning of the AI and its enemy. However, throws and maneuvers are checked as well even if they are not the first technique, so if a technique contains Throw_punch_behind, for example, it will be listed for use only if the AI is behind its enemy. Surprisingly enough, pairing Kick_forward and Kick_back makes the AI kick forward when the position is correct for a forward kick, and then kick backward even though there is nothing to hit ^_^. The same goes for other directional attacks.




Also there is one special condition to executing melee techniques. When there is an edge of a platform nearby it is usually covered in pathfinding grid as a seires of special tiles from blue (border) to orange (danger). Engine seems to check if [[TRAM]] attack's extent extends into orange pathfinding tiles and according to it it decreases weight of such techniques which would make A.I. character end in orange field (i.e. going over the edge and falling down). Techniques which utilize jump position moves are excluded from weight decrease, so there is some very limited and random possibility for A.I. characters to jump aross gaps in order to reach the enemy.
Also, there is one special condition to executing melee techniques. When there is a ledge in a level, it is usually covered in pathfinding grid by a series of special tiles going from blue (border) to orange (danger). As mentioned earlier, the engine seems to check if an attack TRAM's extents run into an area of orange pathfinding tiles and, if so, it decreases the weight of techniques which would make the AI end up in an orange field (which would mean going over the edge). Techniques which utilize jump positioning moves are excluded from this weight decrease, so there is a very limited and random possibility for AIs to jump across gaps in order to reach the enemy.
:Code behind all this must be pretty complex, hands down before Oni developers who managed to pull this off.
:The code behind all this must be pretty complex; hats off to the Oni developers who managed to pull this off.




Modding hints: Creating custom MELE profiles can be fun, but beware of a few pitfalls:
Modding hints: Creating custom MELE profiles can be fun, but beware of a few pitfalls:
:*Position moves can be followed by some certain other position moves, but generally after position move an attack or throw move is expected. If attack or throw is not present, this melee technique will be albeled as NOATTACKNOTHROW and will be unused.
:*Positioning moves can be followed by some other positioning moves, but generally after a positioning move an attack or throw move is expected. If an attack or throw is not present, this melee technique will be labeled as NOATTACKNOTHROW and will be unused.
 
:*Jump position moves can be used to make A.I. at least "somehow" jump across gaps. Oni registers special pathfinding grid tiles (edge tiles and danger tiles) which are registered by A.I. character even she/he is in melee mode. And orange tiles upweight jumping moves a lot. Just don't forget to follow jump position move with some jump attack move.
 
:*Special attack (Rising fury, Devil spin kick) use StartToCrouch position move as a starter.


:*Any combo techique (for example three punch combo) without Interruptible flag makes A.I. character too vulnerable.
:*Jump positioning moves can be used to make the AI sometimes jump across gaps. As explained above, the presence of orange tiles nearby will up-weight jumping moves a lot. Just don't forget to follow up the jump positioning move with some jumping attack move.


:*Rear throw techniques and side attack techniques should have high weight to ensure they will be chosen and used the moment there is a chance.
:*Special attacks (e.g. Rising Fury, Devil Spin Kick) use the StartToCrouch positioning move as a starter.


:*Set distances in position moves reasonably so A.I. character doesn't attempt to perform jump attack techniques or run attack techniques at close distance.
:*Any combo technique (for example, a three-punch combo) without the Interruptible flag will make the AI too vulnerable.


:*Always try to utilize given class's strength - Fury is fast, so upweight combos. Tanker is slower, upweight throws and run attacks. Ninja is a beast, set whatever you want and it will be annoying to deal with anyway.
:*Rear throw techniques and side attack techniques should have a high weight to ensure they will be chosen and used the moment there is a chance.


:*Set the distances in positioning moves reasonably so that the AI doesn't attempt to perform jumping or running attack moves at close distance.


<div style="text-align: center;">[http://www.youtube.com/watch?v=XeymFlbQuNg|'''THE END...''']</div>
:*Always try to utilize a given class' strength. The Fury is fast, so give weight to combos. The Tanker is slower, so give weight to throws and running attacks. The Ninja is a beast; set whatever you want and it will be annoying to deal with anyway.


[[Category:Modding information]]
[[Category:Engine docs]]

Latest revision as of 19:32, 29 February 2024

An action game like Oni needs artificial intelligence-driven characters ("AIs" or "bots") and some sort of interaction amongst these characters and between them and the world. The goal is to make an AI act at least a bit like a human being. That means giving the AI abilities such as moving in the game world believably, and seeing, hearing, and reacting to events in the game world. Different games deal with these problems in various ways, but in this article, we will take a look at Oni and its AI.

This page serves two purposes: to give an overview of Oni's AI and to help modders with AI tweaking.

Pathfinding and movement

Example of a pathfinding grid.
An example of a pathfinding grid.
Example of an A*.
An example of the A* algorithm's work: nodes chosen as a path for AI are highlighted.

Oni has two ways to make an AI move in a game world - pathfinding, and what could be called vector-based.

Pathfinding is used when AI-driven character needs to travel from one place to another. Examples of pathfinding movement are:

  • patrol paths - AI-driven character moves in a pre-designed fashion (see PATR)
  • alarm running - AI character is requested to go to given console and use it, see section Alarm behavior
  • pursuit of target - AI character loses direct sight of the enemy, see section Pursuit
  • running to weapons in order to pick them up, see Extra combat behaviors
Pathfinding utilizes an A* (A-star) algorithm to design routes for AI within the game world.
Human players see walls and obstacles placed between their current location and their desired location, thus they can plan their route thanks to the best computer so far known to man -- the human brain. The AI, on the other hand, has to be told where it can go and where it cannot (a wall, a pit, an obstacle, etc.). Since the A* is a chart-searching algorithm, there is a need to have some sort of chart, conveniently mapping the environment for AI purposes. And that is a pathfinding grid, which can be seen in-game by entering ai2_showgrids = 1 (see picture on right).
If an AI has to travel through the level by pathfinding, then a "mark" is set at the final destination and the "chart" mentioned above is consulted to get the shortest available route. After this process, the AI is continually fed with "traversal nodes" -- temporary marks placed in the part of the pathfinding grid which the AI is currently running through. An AI will simply run directly towards each mark, so when an AI needs to turn a corner, a number of these nodes have to be generated in order to make the AI run around the corner.
Pathfinding grids are tied to AKVAs and are loaded into memory only for the period of time that they serve some purpose (i.e., when the character is inside the AKVA volume). More detailed info about various types of pathfinding grid tiles and their effects on pathfinding can be found here.
There was a short-lived modding initiative to alter pathfinding grids manually, but it failed due to the extreme amount of labor required. These days, OniSplit can import levels and generate pathfinding grids.


Modding hints: if an AI has to turn a sharp corner, the pathfinding still picks the shortest route possible. This usually results in the AI having problems turning corners at full running/sprinting speed -- the AI stops at the corner, turns, runs past the corner, turns again to finish the path, and continues on its way. This is caused by the limited rotation speed assigned to the character in his ONCC.
In an ONCC XML file there is a <RotationSpeed> under <AIConstants>. The default is 1, but 1.5 works way better without causing any visible negative influence on the game. A rotation speed of 2.0 is the maximum recommended because the pathfinding in the game is designed for a speed of 1.0, so with a much higher rotation rate comes the paradox that new problems in pathfinding may appear, instead of issues being erased (mainly the AI colliding with obstacles).


Vector-based movement is used when an AI-driven character:

  • enters close combat state and begins to use melee
  • is dodging gunfire, be it firing spreads or projectiles
  • is asked to run away from an enemy by a special setting in their CMBT profile
In this mode, an AI is not given an exact destination. Instead it is given a "desire" to go in some direction. This mode still uses the pathfinding grid, however in a bit of a different way than pathfinding does, so glitches occur, mainly unexpected collisions and ignored tiles (e.g., an AI runs off a ledge and falls to its death).


Unexpected Collision movement happens when an AI runs on its own towards some destination and suddenly hits an obstacle. Ideally that should never happen, as the pathfinding grid is designed to prevent it, but still... when a collision happens, the game decides what to do according to which method is being used to move the character:

  • Pathfinding: the game makes the AI take a few steps back, rotate a bit, and lets the AI continue its journey. There is a limit to how many unexpected collisions an AI can undergo before it gives up on its destination as unreachable.
  • Vector-based: according to the angle at which the AI is facing the obstacle, the game decides either to let the character slide along the obstacle or to stop the character completely until the angle of the AI's vector of movement changes.

Vision and hearing

Visualization of vision fields.
An example of a blue Striker's central and peripheral vision.
Visualization of sound spheres.
Three examples of sound spheres.

When emulating humans with AI, senses have to be taken into an account: sight, hearing, taste, smell, touch. Unfortunately, Oni emulates only sight and hearing.

Sight is important. Without it, the only option for AI to recognize an enemy would be getting attacked by the enemy first. Unlike the majority of action games, Oni AIs have two kinds of vision:

  • Central: an enemy seen by central vision will be recognized and attacked
  • Peripheral: an enemy seen by peripheral vision will raise the AI's alert level to low and the AI will go into pursuit of the enemy; see Pursuit section
Modding hints: the parameters of the vision fields are stored in ONCC, under <VisionConstants>. The central vision field distance has to be greater than the peripheral vision field distance, otherwise peripheral vision detection will somehow be broken (it will not detect). Since peripheral vision makes the AI pursue the enemy but not attack it, it can be set quite large in order to surprise lousy stealth players. But be warned: nobody likes cheating AI ^_^.


Hearing is crucial in Oni. The majority of AI character interaction is done via the sound system. Oni recognizes these types of sound (colors in parentheses are used for sound visualization when ai2_showsounds is set to 1):

  • Unimportant (blue) - is ignored to some extent if alert level of AI is "lull", but after some period of time, the AI will register it.
  • Interesting (green) - raises alert level to "low"
  • Danger (yellow) - raises alert level to "medium"
  • Melee (orange) - raises alert level to "medium", but the AI reacts a bit differently than to a Danger sound
  • Gunfire (red) - raises alert level to "high"
For more info about AI alert levels, see section Reactions and awareness. These sound types are used by impact effects (ONIE), and a danger sound type can be set in a particle's as part of its "danger radius".
For a video illustration of AI hearing, see this video.
Modding hints: The sound system and ONIE are mighty tools if a modder knows how to use them. Even doors can have attached to them a sound sphere of one of the types listed above, so a modder can create doors which draw the attention (sound type Interesting) of nearby AIs when those doors are used.
Another example is a workaround for AIs to get alerted by dead bodies: set the death particle in the ONCC to emit a custom impact effect. That impact effect will have no sound or effect attached, but will be set to be heard by AIs as gunfire within a large radius (say, 200 units).

Reactions and awareness

In real life, each human being is unique in its reactions. But even then, reactions differ with mood; when calm or when nervous or when suspicious, a man does not always react the same way. And what about Oni?

In Oni, reaction to a stimulus is based on the type of stimulus (see previous section) and on the alert level of the AI. Oni AIs have these alert levels:

  • Lull
  • Low
  • Medium
  • High
  • Combat
The level of alert for an AI can be set via BSL using ai2_setalert. Alert levels play the role of "behavior modifier" in how an AI reacts to seeing or hearing allies and enemies. Alert levels can be increased in the following ways:
  • hearing a sound which raises alert level (for detailed info, read previous section)
  • a special rise from Lull to Low can come from an enemy being seen by peripheral vision or by an enemy causing too many Unimportant sounds
  • a special rise to Combat level will come from being hit by the enemy or by an alarm being triggered (see OBD:BINA/OBJC/CONS), or by the scripting functions ai2_tripalarm, ai2_makeaware or ai2_attack.
Alert level also affects the movement mode of AI-driven characters. There are six movement modes: "creep", "walk", "walk_noaim", "run", "run_noaim", and "by_alert_level". The "*_noaim" movement modes tell the AI that, if it is armed, it should walk or run with the gun in hand but not aim with it. Movement mode can be forced via the BSL command ai2_setmovementmode. Alert level affects movement mode only if movement mode is set as "by_alert_level". In that case:
  • Lull and Low alerts use "walk_noaim"
  • Medium, High and Combat use "run"
If a patrol path (PATR) is assigned to a character, it can force a Lull-alerted character to run with an aimed weapon. However, when the AI becomes aware of and starts its pursuit of an ally/enemy, the movement mode is then dictated by its alert level (if the movement mode is set as by_alert_level).
An alert level can be decreased via BSL's ai2_setalert or with the passage of time (the location of the timer settings is unknown, maybe hardcoded).


The next component of the AI's reaction logic is its awareness of the ally/enemy. Oni distinguishes between allies ("friendlythreat") and enemies ("hostilethreat"). Oni's AIs always know whether a disturbance was caused by an ally or enemy. That means that if player is playing as Konoko and shoots, alerting some Striker, the Striker knows which character (from CHAR) shot and which team the character belongs to, and reacts accordingly (but more about that later). Oni defines four levels of awareness:

friendlythreat
  • Definite: the AI is 100% sure where the ally is located and ignores him. Is achieved by seeing the ally with the central vision field, being hit by his gun by accident, or being told of the ally's presence by the BSL function ai2_makeaware, ai2_tripalarm or ai2_attack.
  • Strong: the AI has a strong awareness of an ally's presence, but cannot pinpoint the exact location of the ally. Is caused by all sound types, which are described in previous section. If the ally is outside the central vision field and <FriendlyThreatDefiniteTimer> runs out, the AI decreases its level of awareness from Definite to Strong.
  • Weak: the AI has a weak awareness of the ally's presence. It is caused either by seeing an ally with peripheral vision or by <FriendlyThreatStrongTimer> running out.
  • Forgotten: the AI encountered some ally, but over time forgot about its presence (<FriendlyThreatWeakTimer> ran out).
hostilethreat
  • Definite: the AI is 100% sure where the enemy is located, and will go attack her/him. Is achieved by seeing the enemy with its central vision field, being hit by her/him (or her/his gun), or being told of the enemy's presence by the BSL function ai2_makeaware, ai2_tripalarm or ai2_attack.
  • Strong: the AI has a strong awareness of an enemy's presence, but cannot pinpoint the exact location of the enemy. Is caused by all sound types, which are described in previous section. If enemy manages to out of an AI's central vision field and <HostileThreatDefiniteTimer> runs out, the AI decreases its level of awareness from Definite to Strong. If the AI is allowed to investigate, the corresponding pursuit behavior is executed (more about this later).
  • Weak: the AI has a weak awareness of an enemy's presence. It is caused either by seeing an enemy with peripheral vision or by <HostileThreatStrongTimer> running out. If the AI is allowed to investigate, the corresponding pursuit behavior is executed (more about this later)
  • Forgotten: the AI encountered an enemy, but over time forgot about its presence (<EnemyThreatWeakTimer> ran out).
When an AI character is freshly spawned, it does not have any record of contact with other characters (a tabula rasa). Through hearing and vision, an AI learns about the presence of other characters and reacts to them according to team affiliation, alert level, and awareness level. Even when an AI character ceases to be aware of an ally/enemy, it does not completely forget them. For example, the startle behavior when an AI sees an enemy is played only once for this particular enemy; it won't play the startle animation the next time it sees him, but will go directly to attacking him.
Friendly warning: the awareness level "Forgotten" IS NOT equivalent to the result of the ai2_forget command. "Ai2_forget" actually sets the AI's memory back to tabula rasa status.


Pursuit

Now that alert and awareness levels have been covered, let's take a look at pursuit behavior. Pursuit behavior in Oni emulates the situation when a person knows "somebody is here", but does not see anybody. In Oni there are following types of pursuit behavior:

  • None: No pursuit taking place
  • Forget: the AI drops to the Forgotten level of awareness of this enemy
  • GoTo: the AI moves to the source of the disturbance and performs 600 frames (10 seconds) of Look behavior
  • Wait: the AI simply stands and waits to see/hear something more
  • Look: the AI turns in place, looking all around
  • Move: unimplemented; probably was meant to be similar to Look, but with character randomly moving around
  • Hunt: unimplemented; probably was meant to make AI purposefully hunt around for the enemy
  • Glance: the AI does not rotate its whole body, but only turns its head

Plus there are three types of lost behavior (when an AI had definite contact with the enemy but the enemy managed to get away):

  • ReturnTo Job: the AI returns to its job
  • KeepLooking: the AI does not return to its job, and keeps using the last used pursuit behavior
  • FindAlarm: the AI tries to switch to alarm behavior (see section Alarm behavior); if it does not succeed, then it returns to its job.


In Oni, a character is spawned in the level from a character profile (a CHAR file). This CHAR profile contains links to:

  • ONCC file, for character class, eg. Konoko or Comguy_1
  • CMBT file, for the combat profile for this character
  • MELE file, for the melee profile for this character
  • PATR file (OPTIONAL), for the patrol path
  • NEUT file (OPTIONAL), for neutral behavior (e.g., a civilian giving the player a powerup)
Pursuit behavior is executed only within the Pursuit range, which is the parameter <PursuitDistance> in the CMBT profile attached to the AI. If anything suspicious happens outside of this range, the AI only looks in the direction of the disturbance for a short time, then ignores it and returns to its job.
Pursuit behavior greatly depends on the AI's level of alert. There are four parameters regarding alert levels in the CHAR profile:
  • Initial: the AI is spawned with the specified level of alert
  • Minimal: the minimum alert level this AI can have
  • JobStart: the alert level of the AI when it starts some job (typically a patrol)
  • Investigate: From the alert level specified here, and all greater alert levels, the AI will tend to pursue any suspicious sound it hears or any hostile peripheral contact it makes


Also in CHAR are five fields regarding pursuit behavior:
  • Lull/Low alert level and strong awareness behavior: in XML labeled as <StrongUnseen>
  • Lull/Low alert level and weak awareness behavior: in XML labeled as <WeakUnseen>
  • Medium/High/Combat alert level and strong awareness behavior: in XML labeled as <StrongSeen>
  • Medium/High/Combat alert level and weak awareness behavior: in XML labeled as <WeakSeen>
  • Lost (when an AI had a definite contact but lost it): in XML labeled as <Lost>


If an AI registers any sound or peripheral vision contact inside its pursuit range while its alert level is below the alert level set in its Investigate parameter, then this AI will only look in the direction of the disturbance for a short time, then ignore it and return to its job. However, if the alert level of the AI is high enough, the AI goes into pursuit mode. That means that the AI will get a strong awareness of the enemy (or only weak in the case of peripheral contact), go to the source of the disturbance (the center of the sound sphere in the case of a sound, or the spot where the enemy stood in the case of peripheral eye contact), and will perform the pursuit behavior Look for 10 seconds. After this initial Look mode expires, the AI will perform the pursuit behavior prescribed in its CHAR profile.
The length of each pursuit behavior's execution depends on the HostileThreat timers (ONCC file), as described in the section above.



Modding hints: Pursuit mode complications and weird glitches

Watch this YouTube video. Pursuit mode is quite buggy, so when setting pursuit behaviors, there are several important things a modder has to have in mind.
  • The pursuit distance parameter in CMBT is important in deciding whether the character should be more of a pursuer or more of a guard.
  • Within the pursuit distance, peripheral vision pursuit follows its own rules. When an AI sees an enemy with its peripheral vision, this AI always goes into weak awareness mode and either just glances in the direction of this enemy (alert level was below Investigate level) or moves to the spot and performs weak investigation pursuit behavior (alert level was at Investigate on higher).
  • Remember that there are TWO sets of pursuit behavior:
    • strong and weak pursuit for lull/low alert levels. In XML these are called <StrongUnseen> and <WeakUnseen>, however those names simply reflect how many changes were made to this part of the game.
    • strong and weak pursuit for medium/high/combat levels, in XML called <StrongSeen> and <WeakSeen>.
  • From all the available pursuit behaviors, only GoTo, Look, Glance, Forget and Wait can be effectively used as CHAR pursuit behavior parameters. Hunt and Move are not finished code-wise.
  • Remember that general pursuit behavior is simply glitched, and the parameters from CHAR are more often ignored than actually used. The glitchiness is somehow connected with vision. When AI vision is turned off via ai2_blind=1, pursuit mechanics work as they should. However, the moment that AIs are allowed to see, then when pursuit should be performed, it results in:
    • pursuit values from CHAR being ignored if pursuit mode was called while the character was idle or moving along a patrol path. The AI character performs basic GoTo + timer-based Look for the whole period of pursuit behavior, for both strong and weak awareness. Looks so-so but definitely is a glitch.
    • one GoTo + timer based Look being called, but the timer for Look fails to decrement, so the AI simply stands and stares forever. This happens when pursuit mode is called while an AI stands at a job location on a patrol path. And, well... it looks really bad.
    • correct behavior roughly 10% of the time. It is quite random, but it looks like the AI has to be somehow disturbed while going for the source of a previous disturbance. And then Oni writes to the developer console "pursuit mode Hunt not yet implemented" ^_^.
  • The best way how to deal with the pursuit/vision issue is to either ignore it (so the character often gets glitched) or use a BSL script to create a small looping function where ai2_blind is set to 1 for at least one second (60 frames), then set to 0 again. It can cause funny moments of an AI completely ignoring an enemy right in front of it, but it silently fixes these pursuit problems.


Alarm behavior

CONTROL CONSOLE.png
ALARM CONSOLE.png
DATA CONSOLE.png
Control Alarm Data

In order to make the AI look more human, it is a good idea to grant it the ability to interact with the world the same way that the player does. In Oni, for example, that means giving the AI the ability to use consoles.

Watch this YouTube video.
BSL scripting provides a command to make an AI go and use a console: ai2_doalarm. This way, an AI can be told to use any console. But there is a method to make an AI use a console completely on it own.
In order to utilize this mechanic, there is a need for a console which has the ALARM CONSOLE flag set (see OBD:BINA/OBJC/CONS). In XML this flag is called IsAlarm. Such a console then can be used by AI characters without scripting.
Next, there are Alarm parameters in CMBT profiles which define an AI's alarm behavior:
  • Search distance: a radius around the AI where the engine checks for any console with the ALARM CONSOLE flag. In XML it is named <SearchDistance>.
  • Ignore distance: a radius around the AI where this AI character (which is currently executing alarm behavior) acknowledges enemies. Enemies outside of this radius are ignored by the AI character. In XML it is named <EnemyIgnoreDistance>.
  • Attack distance: a range within which the AI (which is currently executing alarm behavior) will temporarily stop its run for the console and attack enemies if the AI sees them with its central vision field. In XML it is named <EnemyAttackDistance>.
  • Damage threshold: The time interval for which an AI stays aware of an enemy who attacked it. If this enemy enters the Attack distance, the AI temporarily stops its run for alarm and immediately attacks this enemy (it does not have to see him with central vision field). In XML it is named <DamageThreshold>.
  • Fight timer: The number of frames for which the AI should fight with the enemy before it attempts to resume its run for the alarm. In XML it is called <FightTimer>.


So the settings for alarm-running behavior are set; now how to trip it? There are three ways to make a character run and use a console without BSL (but the console must have the ALARM CONSOLE flag set and must lie within Search distance):
  • using CMBT profile: Set the no-gun behavior to "Run For Alarm" (in XML, use the string "RunForAlarm" inside <NoGunBehavior>). By setting this parameter, an AI will attempt to run and use a console when it does not have a loaded weapon or any spare clips in its inventory. If there is no alarm console nearby, the AI will switch to Melee.
  • also in CMBT: The Behaviors (Long, Medium, Short, MediumRetreat, LongRetreat) can be set to "Run for Alarm". DO NOT confuse this with the "Run For Alarm" no-gun behavior! This behavior is never used in retail Oni, the reason probably being that if there is no useable console within Alarm search distance radius, then the AI simply stands and stares even when an enemy is visible within its central vision field.
  • In CHAR: Use the "Lost" behavior "FindAlarm". When an AI makes definite contact with an enemy and then the enemy manages to escape, the AI executes this "Lost" behavior (see Pursuit of enemy section). This behavior is typically set as ReturnToJob, but FindAlarm works well with no known issues. If an alarm console is not found within Search distance, the AI simply returns to its job.


A couple of notes regarding AIs:
  • in order to register an enemy and attack her/him pre-emptively, the AI must have the "HostileThreatDefinite" timer in its ONCC file set to some value over 60 (Oni internal clock runs at 60 frames per second).
  • The no-gun behavior "Run For Alarm" can get glitchy. Say that "Alarm enemy attack distance" is set to 100; now when an AI runs for an alarm and an enemy attacks it, then if in the AI's CMBT profile the melee override is not set to a range of at least 100 (via melee override or by having "Melee" set in its corresponding combat ranges, see section Basic combat behaviors), chances are that the AI will get stuck in a loop trying to reach both the enemy and the console at the same time.
  • A similar issue can happen with the combat behavior "Run For Alarm" as well, but this time problems arise when this combat behavior "Run For Alarm" is set as the Short-range behavior.
A couple of notes regarding the target console:
  • It must be in "activated" mode. If the console is in a deactivated or "used" mode, the alarm behavior will not be executed.
  • It must be directly accessible. Oni's AI cannot use consoles in order to open up a path to get to the point of interest (a target console in this case). But the target console can be across the whole level as long as it is not behind any locked doors.


As already mentioned, Alarm behavior can be tripped by the BSL command "ai2_doalarm". In that case, alarm behavior is executed but this time the console is being set by a command instead of being looked for within the Search distance. Also, with "ai2_doalarm" the AI can be made to use any console, not just those with the ALARM CONSOLE flag.


Modding hints: the ability of the AI to use consoles is an excellent tool for increasing the challenge.

  • Beware of setting the "Run For Alarm" combat behavior as the close-range one. Such a setup causes glitches.
  • On the other hand, "Run For Alarm" can be deliberately used to add an element of surprise to fights. In the CMBT profile, set "Run For Alarm" as either the Medium or MediumRetreat behavior, then shorten the interval between the <MediumRange> and <ShortRange> values (for example, set "Medium Range" to 60 and "Short Range" to 59). Thanks to this setup, an AI can attempt to find an alarm console while still being capable of fighting when no alarm is nearby.
  • In BSL, a modder can easily determine if a console was used by the player or an AI thanks to the chr_is_player function. All that's required is a BSL function being triggered when the console is used. Here is an example where a console triggers a function called "console1_used":
func void console1_used(string ai_name)
{
  if (chr_is_player(ai_name))
  {
    *Some code in case player used the console*
  }
  else
  {
    *Some code in case AI used the console*
  }
}
  • Another way of using alarm mechanics is to create a feeling of cooperation -- in order for the player to achieve something, an AI-driven sidekick must use a console.
  • In extreme cases, an AI can be even made to move through the level on it own, from one console to another. That can be used to create "chase" missions -- an AI wants to activate a certain number of consoles, while the player is required to stop it from doing so. Thanks to Alarm behaviors, the task of tripping consoles can be fully completed by the AI, no scripting needed. Such a setup is on the one hand prone to possible AI glitches, but on the other hand can add an element of randomness and increase replayability. A demonstration of alarm behavior being used by an AI to complete all of Chapter 1 can be found HERE.

Basic combat behaviors

Example of combat ranges.
Combat ranges of an AI character.

Of course, an action game like Oni is not complete without guns blazing and fists flying through the air. But combat in real life is usually very fickle and everything has to be considered. How can Oni's AI possibly deal with such a complex task?

An AI in Oni has to have a definite awareness of the enemy in order to actively attack him. The alert level of an AI when in combat mode is Combat (duh). Definite awareness can be achieved by these ways:
  • The enemy is seen in this AI's central vision field.
  • The AI is made to attack the enemy by the BSL function ai2_attack.
  • The AI is hurt by the enemy, be it melee or gun damage.

Once combat mode is entered, then as long as the HostileThreatDefinite timer for this enemy does not reach zero, an AI will always know the exact location of this enemy and will attempt to attack it. The moment HostileThreatDefinite timer is depleted, the AI loses the privilege of knowing the enemy's exact location, its awareness decreases from definite to strong, and the AI either switches from combat mode to pursuit mode with this enemy (see section Pursuit of enemy) or, in case of another enemy being present in its central vision field, picks this new enemy as a target to attack and keeps the old enemy in strong (and later weak, then forgotten) awareness.

Since the means of combat depends on the distance between the participants, some sort of spacing is needed. Oni uses a system of three radii around the AI, called combat ranges. See picture on right. The size of these radii can be set in the CMBT profile.
These ranges work as "triggers" to make the AI character execute various behaviors based on the enemy's proximity. Moreover, Oni can distinguish between an enemy entering a specified range or exiting a specified range. All the range possibilities in Oni which can be assigned some combat behavior are:
  • Short: enemy is close to the AI.
  • Medium: enemy is approaching the AI and crossed from Long Range into Medium Range.
  • Long: enemy is approaching the AI starting at the Long Range.
  • Medium Retreat: enemy is retreating from Short Range to Medium Range.
  • Long Retreat: enemy is retreating from Medium Range to Long Range.
Well, of course nothing is perfect, and in Oni there is a bit of an issue with proper switching between combat ranges, so Long and Medium ranges are used only once at the beginning of an enemy approach. Only Short, Medium Retreat and Long Retreat ranges are used on a regular basis in combat. Even when an enemy runs into Long Retreat and goes back to to Medium range, the engine does not switch the AI's behavior range to Medium, but (contrary to its name) to Medium Retreat.


OK, we have positioning down; now for the actual behaviors that an AI can be set to execute within these ranges. There are fourteen possible combat behaviors (in parentheses are the XML strings):

  • None (None): simply nothing.
  • Stare (Stare): the AI stands and stares; it does not even rotate to face the enemy.
  • Hold and fire (HoldAndFire): the AI stands still and fires a weapon. If this character does not have a weapon, then it switches to melee.
  • Firing charge (FiringCharge): the AI runs toward the enemy and fires a weapon. If this character does not have a weapon, then it switches to melee.
  • Melee (Melee): the AI always uses melee, even when it holds a loaded weapon.
  • Barabbas shoot (BarabasShoot): the AI stands still and fires a weapon with hardcoded three-second pauses between shots. If this character does not have a weapon, then it switches to melee. If this character meets certain conditions, it can start regenerating health. More detailed info about regeneration mechanics can be read here.
  • Barabbas advance (BarabasAdvance): the AI runs toward the enemy and fires a weapon using the secondary trigger (as if the player pressed right mouse button). If this character does not have a weapon, then it switches to melee. If this character meets certain conditions, it can start regenerating health. More detailed info about regeneration mechanics can be read here.
  • Barabbas melee (BarabasMelee): the AI uses melee, even with a loaded weapon in hand. If this character meets certain conditions, it can start regenerating health. More detailed info about regeneration mechanics can be read here.
  • Superninja fireball (SuperNinjaFireball): Mukade's long range behavior. With this behavior, an AI cannot shoot weapons and cannot use melee; it simply runs toward the enemy. However, if a weapon is in hand, the character can use melee (probably something from the weapon melee override). The AI is occasionally teleported behind the enemy (AnimType 222 - Teleport In) if the distance to the enemy is greater than 100 world units (however, something is screwy with this teleportation mechanic). Anyway, to add more to this behavior, the AI executes two special TRAMs (animations):
    • AnimType 224 - Ninja Fireball (Mukade's heat-seeking Devil Star); after using this, there is a 20-second cool-down before this can be used again.
    • AnimType 225 - Ninja Invisible (grants a 10-second cloak); after using this, there is a 20-second cool-down before this can be used again.
IMPORTANT There is an annoying problem with this behavior, which was coded with the Rooftops boss fight in mind. When it is called, it checks the character's position height-wise from the origin of the game world (coordinates {0, 0, 0}) and if the height is below 550, this character is automatically moved to height 550 (which in almost all cases means death by falling).
  • Superninja advance (SuperNinjaAdvance) - Mukade's medium range behavior. With this behavior, an AI cannot shoot weapons and cannot use melee; it simply runs toward the enemy. However, if a weapon is in hand, the character can use melee (probably something from the weapon melee override). This behavior also allows the use of AnimType 225 - Ninja Invisible. In order to be able to use this ability, the AI has to be at least 50 (or 40?) world units away from its enemy. The cool-down for this special technique is 20 seconds. Again, the annoying "over 550" height check is present.
  • Superninja melee (SuperNinjaMelee): Mukade's short range behavior. With this behavior, the AI cannot shoot weapons, but can use melee. This behavior allows the use of AnimType 225 - Ninja Invisible. In order to be able to use this ability, the AI has to be at least 50 (or 40?) world units away from its enemy. The cool-down for this special technique is 20 seconds. This behavior also grants the ability to teleport away from the enemy to a certain distance (around 100 world units) if any one of these conditions is met:
    • About 35 points of damage dealt to this character in a short time (exact amount of damage and exact timing not known).
    • This character get thrown.
Again, the annoying "over 550" height check is present.
  • Run for alarm (RunForAlarm): see section Alarm behavior.
  • Mutant Muro melee (MutantMuroMelee): the AI is only allowed to melee, not fire weapons. This behavior places the Daodan aura on the character irrespective of his/her HP as long as the character has <HasDaodanPowers> set to 1 in their ONCC. This aura effect does not grant the damage overpower attribute that Konoko has when she overheals. If the ONCC has both <HasDaodanPowers> and <HasSuperShield> set to 1, the chenille mode called by this behavior grants a supershield.
The supershield lasts forever if it is not terminated either via BSL or by the AI performing a TRAM which has a DisableShield flag. After a DisableShield move removes the supershield there is a 10 second interval and then it is turned back on. Another specialty of this behavior is an automatic backward-evasion move when about 35 points of damage or a throw are inflicted on the AI. The supershield is turned off if this AI switches to some other combat behavior because the enemy moved to another combat range.
  • Mutant Muro thunderbolt (MuroThunderbolt): Upon initial contact, the AI turns on chenille mode and runs toward the enemy. If chenille mode is turned off then, until definite awareness of the enemy is lost, this behavior will not cast chenille mode again. This behavior also allows the AI to use a special long range attack: the character turns off chenille, goes into AnimState 69 - Thunderbolt, and loops a special TRAM animation of AnimState 69 - Thunderbolt and AnimType 231 - Muro_Thunderbolt. That lasts for 10 seconds. Then the AI stops the animation for 5 seconds and runs toward the enemy. If, after those 5 seconds, the AI is still executing Mutant Muro thunderbolt behavior, the AI resumes the looping TRAM between AnimType 231 and 69.
This behavior's special looping animation continues even when an enemy enters some another combat range, with the exception of Short range. If the enemy enters Short range while the looped animation is running, the loop is forced to stop and the AI starts using Short range behavior.



Modding hints: Combat behaviors can have a severe positive or negative impact on AI performance in a fight.

  • Remember: due to a glitch, the crucial behaviors for combat are Short, MediumRetreat and LongRetreat. Long and Medium are used only at the beginning of an encounter.
  • In general, use common sense. There is little use in setting Firing Charge as the Short range behavior.
  • Barabbas Shoot and Barabbas Melee behaviors have access to a healing ability which can be a great asset for introducing mutants or stronger enemy units. However, remember that Barabbas Shoot limits rate of fire to one shot per three seconds.
  • Barabbas Advance is the only behavior which allows an AI to fire a weapon in its secondary fire mode. However the behavior is quite glitchy (the AI often looks away and fires stray shots). Still, with the proper gun and proper setup it can be useable for boss fights.
  • Superninja's behaviors sound excellent for cunning enemy units, however the annoying check for a character's minimum allowed height from the world origin, and subsequent forced re-positioning, severely impact these behaviors' usefulness. With a level which is deliberately raised to the correct height, the behavior will not cause random AI character re-positioning. Then it can be used to its fullest.
One other important thing about these behaviors: if the AI does not have required the TRAMs in its TRAC, the AI can get stuck if it uses these behaviors.
  • If there is no console with the ALARM CONSOLE flag within the Alarm search distance, then the behavior "Run For Alarm" will make an AI just stand and stare. Choose this behavior with caution, and consider using a workaround where Medium and Short combat ranges have very close radii, with Run For Alarm being the MediumRetreat behavior, so that the Run For Alarm behavior is executed only for a brief amount of time as the AI almost immediately switches to LongRetreat. Even one frame is enough, because if an alarm is found, the AI is requested to perform an alarm run which can override combat (see section Alarm behavior for more info).
  • MutantMuro melee behavior can be used to create tricky foes which have to be fought from a distance because if the player comes up close then the AI will turn on its (super)shield and won't put it away (by providing no TRAM with the DisableShield flag). That would make the player put some distance between him and the AI in order to make it disable the shield.
  • MutantMuro thunderbolt should NEVER be assigned as the Short range behavior, as that will negatively affect its special attack. Set it as LongRetreat or MediumRetreat. This kind of behavior (with proper TRAMs) can be used to create foes who will perform a special long range attack if the player tries to keep his distance. This ranged attack does not have to be the same as Muro's tractor thunderbolt. For example, an AI could be made to fire an aggressive energy-beam type of attack.



Extra combat behaviors

Combat ranges and various AI combat behaviors were discussed in the previous section. Even in terms of combat ranges, there are still other aspects of combat to cover: picking up weapons from the ground, melee overrides of weapons, behaviors if the character is unarmed, and, of course, firing weapons or using hand-to-hand combat.

"Melee override" (CMBT profile): Similar to the BSL command chr_dontaim, this behavior urges the AI to use its hand-to-hand animation variant (see TRAM) and to switch from some other behavior to melee combat. This field was probably added to deal with conflicts when multiple AI behaviors are applied on a character. The possible values are (XML strings in parentheses):

  • None (None): no override is used.
  • If Punched (IfPunched): melee override is applied when the AI is melee-attacked by its enemy. Does not work when the character is invincible.
  • Cancelled: unfinished feature; does nothing. There remains only the question of what it was meant to be....
  • Short (ShortRange): Melee override is applied when the enemy is within Short range.
  • Medium (MediumRange): Melee override is applied when the enemy is within Medium or Short range.
  • Always Melee (AlwaysMelee): Melee override is applied within all combat ranges.
This override can affect:
  • Alarm running: It is actually required if an alarm run is called via the no-gun alarm run behavior, otherwise glitches will appear.
  • Retreating behavior - When the no-gun behavior is set as "Retreat", an unarmed AI will try to run away from its enemy. However, if enemy meets the Melee override parameter (for example getting into the Short range while the melee override is set to ShortRange), then this AI stops running away and starts attacking the enemy.
  • Weapon firing: If the distance between the AI and its enemy is smaller than the minimum shooting distance, the AI tries to backpedal away from its enemy till the distance between characters is greater than the minimum shooting distance. However, this backpedal behavior can be overridden by the melee override if all conditions are met; the AI then starts using melee (even with a loaded weapon in hand) for at least 10 seconds (hardcoded timer). After ten seconds, the AI tries to resume its previous behavior. If the enemy is still too close, the melee override is immediately applied again.
  • Weapon pickup: if the AI is trying to pick up a weapon and an enemy crosses the range specified in MeleeOverride, then the weapon pickup behavior is overridden by melee.
  • Maybe some other aspects of AI behavior?


No-gun behavior (CMBT profile): This parameter tells the AI what kind of action it should take if it is unarmed or has an empty weapon and no spare clips. Possibilities are (XML strings in parentheses):

  • Melee (Melee): The AI attacks the enemy with hand-to-hand combat.
  • Retreat (Retreat): The AI runs away from its enemy (a bit glitchy, but works).
  • Run For Alarm (RunForAlarm): see section Alarm behavior. Reminder: this alarm-running behavior requires the melee override to be set in ShortRange, MediumRange or AlwaysMelee, otherwise the alarm behavior gets glitched and the AI gets stuck. If no alarm console is found within the alarm search distance, the AI resorts to melee.


Picture showing AI moving to a weapon.
AI moving towards a weapon.

Weapon pickup behavior (ONCC file): When in combat mode, an unarmed AI can be told to move to a loaded weapon and pick it up or to swap a held, empty gun for a loaded gun which is lying on the floor. Overall, AIs can only register pickup-able weapons up to a distance of 60 world units (hardcoded). In the ONCC file, these parameters can be set to alter the gun pickup behavior (XML tags in parentheses):

  • Chance for pickup (GoForGunChance): percent chance of AI deciding to go and pick up a weapon. It seems that the weapon closest to the AI character is always chosen to be picked up.
  • Running pickup (RunPickupChance): percent chance of AI picking up the weapon by performing an evasion (melee dodge) move.


Getting up after being knocked down (ONCC file): If an AI is knocked to the ground, it stays on the ground for a while (a simulation of being stunned), then gets up. In the ONCC file there are two parameters regarding getting up (XML tags in parentheses):

  • Knockdown minimum number of frames (DazedMinFrames): minimum number of frames that AI stays on the ground.
  • Knockdown maximum number of frames (DazedmaxFrames): maximum number of frames that AI stays on the ground.
If a knocked-down AI gets hit by melee, it gets up immediately after the hit. Being hit by weapons does not make AI character instantly get up. Standard get-ups are simple ones (the same result as if the knocked-down player hits a directional key). If the AI is in melee combat mode, its MELE profile has get-up attacks listed, and the enemy is within the required range, there is a chance that this AI will use a get-up attack instead of a simple get-up animation.


Making sure enemy is dead (ONCC file): Yes, even this is a part of Oni's combat AI.

When the enemy is defeated in hand-to-hand fighting, the AI stands over them for a while to decide if the enemy is dead. During this interval, the AI can utter a short victory speech if the corresponding sound slot in its ONCC is filled and the percent chance roll is successful. Also during the "check body" time interval, the AI can perform a taunt animation if that roll is successful. Here are listed all the related fields from the ONCC file (XML tags in parentheses):
  • Investigate body (InvestigateBodyDelay): Time period for which AI stands over its defeated enemy and stares at him/her.
  • Dead taunt chance (DeadTauntChance): Percent chance of performing a taunt animation.
  • Check body sound probability (CheckBodyProbability): Percent chance of playing a victory speech.
  • Check body sound (CheckBodySound): A link to an Oni ambient sound file (OSAm).


If the enemy is defeated by weapon, then the AI keeps shooting this dead enemy for some extra time to make sure the enemy is dead, then comes close to investigate the body. No taunts, no win phrases. The parameters of this behavior are:
  • Dead make sure (DeadMakeSureDelay): Time period for which the AI keeps shooting the dead enemy.
  • Investigate body (InvestigateBodyDelay): Same as the one listed above for melee.


Modding hints - the behaviors listed in this section can be combined to achieve quite impressive results.

  • Unfortunately, Oni does not provide any AI settings that deal with intelligent holstering and unholstering of weapons in their possession. Thus, melee overrides are the only way to make an armed AI somehow defend itself when the enemy gets too close to use its weapon.
Nevertheless, BSL does provide a function to make a character holster or unholster a weapon: chr_forceholster. In order to make a character holster a held weapon, this character has to be using a pistol or rifle animation variant (see TRAM). Since AI can use "walk_noaim" and "run_noaim" movement modes (which disable weapon variants, i.e., aiming with weapons), the weapon variant should be explicitly forced on via the BSL function chr_dontaim. Unholstering is easier: the character simply has to be be executing some aiming overlay-compatible animation at the moment when chr_forceholster is executed. That means standing, running, crouching, walking, and jumping are OK -- the function will succeed -- but attack animations or animations of getting hit are not OK and the function will fail.
  • IMPORTANT NOTE: The AI must be "active" all the time in order to perform BSL animation checks (chr_wait_animation/animtype/animstate checks). Remember that Oni was developed mostly in the '90s, so various tricks were used to save memory and enhance performance. One technique was to make unseen characters (behind a wall, closed doors, etc.) go into an "inactive" mode, which means they are only stored in RAM as a structure, but no physics, collision checks, or drawing functions are performed on them in order to save system resources (and yes, that means inactive characters can walk in mid-air and pass through walls). On the other hand, when a character is active, it is fully operational, with physics working, collisions being checked, and character being ready in graphics memory to be drawn any time. To make sure a character stays active requires either applying chr_lock_active to each AI, or (since computers have a lot more memory these days) simply setting chr_all_active to 1 to force all characters active.
Here is a simple example of a holster behavior scripted in BSL. A character is given a gun, then the weapon is holstered. When this AI notices an enemy and plays its startle animation, then an unholster is called for. This YouTube video shows the script in action.
 #Setup of AI - gets spawned, forced to be always active, weapon gets holstered.
 ai2_spawn A_t48
 chr_giveweapon A_t48 w1_tap
 chr_lock_active A_t48
 sleep 1
 chr_dontaim A_t48 0
 chr_forceholster A_t48 1
 sleep 1
 #Surprise behavior - unholster weapon when AI character is startled
 chr_wait_animtype (A_t48, Startle_Forward, Startle_Back, Startle_Left, Startle_Right)
 chr_forceholster A_t48 0
 #Aftermath - AI is usually walking only if it is not in combat mode, so let's use it as a trigger that weapon can be holstered.
 chr_wait_animtype (A_t48, Walk, Walk_Backwards)
 chr_dontaim A_t48 0
 chr_forceholster A_t48 1


  • A melee override can be used together with the "Go For Gun" behavior and a properly-set Short combat range to create AIs who go for a gun any time they have a chance, yet they are not allowing an enemy to land free hits in the process (if the enemy gets too close, the Short range melee override kicks in).
  • The no-gun behavior "Retreat" works in a rather simple manner: if unarmed, an AI is given a desire to run as far from the enemy as possible. This behavior can look a bit awkward, but is useful for making more life-like civilians. Combined with Melee override at "Short range" or "If punched", and a bit of BSL scripting to deliberately switch between "combatant" and "non-combatant", a modder can achieve impressive results without only a light load on the game engine. See this YouTube video.
  • Setting short get-up times is a good way to make an AI-driven character a formidable opponent in hand-to-hand combat. However, too-short get-up times can introduce problems. It is a good idea to experiment with get-up parameters till the character feels "natural".
  • Don't over-extend the "Check body" and "Dead make sure" timers. It looks silly, and on top of that it makes AIs easy targets for a rear throw.



Weapon combat behaviors

Back in 2001, Oni was highly praised for its mixture of shooting and hand-to-hand combat. Now what could the AI designers for Oni possibly do to make AI characters aim a gun, pull a trigger or avoid being hit by enemy gunfire? In this section, settings found in ONWC, together with ONCC and PAR3, will tell the story.

First let's look into the ONCC file. In an XML export of this file, under <AIConstants>, there's a tag named <Flags>. In the original binary data it is a bitset, meaning that more than one flag can be active at a time. The XML strings for the flags are:
  • noStartleAnim: disables the startle animation that can occur when the AI sees the enemy for the first time.
  • EnableMeleeDodge: enables firing spread/projectile dodging while the AI is in pathfinding mode or melee combat mode.
  • RunAwayDodge: enables firing spread/projectile dodging even while the AI itself is shooting a gun. The AI will stop shooting and try to move away from the danger area.
  • ShootDodge: enables firing spread/projectile dodging even while the AI itself is shooting a gun. The AI will keep shooting at its enemy while at the same time attempting to move away from the danger area.
  • NotUsed: Some characters have this bit turned on, however it looks like it does nothing.
Example of a firing spread.
Example of a firing spread.
Example of a particle with an AI projectile-dodge radius.
Example of a projectile with AI dodge radius (blue sphere).

Gunfire dodging mechanics. Gunfire dodging mechanics are quite an interesting part of Oni's AI system -- interesting because the retail version displays little to no such behavior, which is sad because it adds challenge to the gunplay. In order to make an AI perform gunfire dodging, this AI must be in combat mode with an enemy. Without combat mode and some enemy, AI character won't dodge. Additionally, an AI will only perform a dodge when the character senses one of these two things:

  • Firing spread. This can be seen by using ai2_showfiringspreads. The firing spread has the shape of a prism (its dimensions set in ONWC) which can be created when a weapon is fired. Not every gun has a firing spread, as for some guns a firing spread is useless (e.g. the Scram Cannon and Super Ball Gun). If an AI can dodge gunfire and intersects with a firing spread, this AI character starts its gunfire dodging behavior.
  • Projectile. The epic win of Oni modders. In the retail version of Oni, projectile dodging is basically broken due to a couple of bugs in the code. Since the engine hackers/modders fixed this issue, AIs can now dodge projectiles properly. Visualize this feature with ai2_showprojectiles. AIs will dodge particles themselves if they are in combat mode with some enemy and the particle (e.g. the Screaming Cell Cannon's projectile) has <AIDodgeRadius> set to a positive non-zero value.


AI parameters regarding gunfire dodging are set in ONCC (XML tags in parentheses):
  • Dodge reaction delay (DodgeReactFrames): a delay, in number of frames, which makes an AI wait a bit inside a danger zone before starting its reaction to the firing spread/projectile.
  • Dodge timescale (DodgeTimeScale): how long the AI's gunfire dodging behavior should last.
  • Dodge weight (DodgeWeightScale): how strong the desire (as a length of vector???) is for this AI character to dodge gunfire. The dodge weight can add together with other "vector" movements, and a sum of all vectors is the direction in which the AI will try to move.


Parameters of firing spread in ONWC are (XML tags in brakets):
  • Firing spread length (FireSpreadLength)
  • Firing spread width (FireSpreadWidth)
  • Firing spread skew (FireSpreadSkew)
The parameter for projectile dodging in the particle system (PAR3) is the AI dodge radius (AIDodgeRadius).


AI character's prowess with guns. Still in the ONCC, there are settings for how skillful this AI should be with each weapon in the game. Weapons are indexed (starting from zero) as follows:

  • 0: w0_sec - only Bungie West employees know what this weapon was supposed to be.
  • 1: w1_tap - TCTF Automatic Pistol
  • 2: w2_sap - Syndicate Automatic Pistol (the SMG)
  • 3: w3_phr - Plasma Rifle
  • 4: w4_psm - Phase Stream Projector
  • 5: w5_sbg - Super Ball Gun
  • 6: w6_vdg - Van de Graaff Gun
  • 7: w7_scc - Scram Cannon
  • 8: w8_mbo - Mercury Bow
  • 9: w9_scr - Screaming Cell Cannon
  • 10: w10_sni - Mukade's Devil Star (heat-seeking red ball) as an invisible weapon; probably a relic from game development.
  • 11: w10_ba1 - Barabas' gun, the Wave Motion Cannon.
  • 12: w11_ba2 - Barabas' gun; this one cannot be shot and is probably a development relic.


For each weapon, the ONCC defines these parameters (XML tag in parentheses):
  • Recoil compensation (RecoilCompensation): how much the AI character compensates for the recoil (vertical stray) of the weapon. Setting this to 0.0 means no compensation, and setting this to 1.0 means full compensation.
  • Best aiming angle (BestAimingAngle): in radians, but the question is whether it really affects aiming.
  • Shoot group error (ShotGroupError): the random deviation of the AI's aim from the target spot. Incorporated to simulate human inaccuracy. Can be set higher than 1.0.
  • Shoot group decay (ShotGroupDecay): the random deviation of the target spot itself. The target spot is naturally based on the enemy's position. Can be set higher than 1.0.
  • Shooting inaccuracy multiplier (ShootingInaccuracyMultiplier): also controls the degree that the AI's aim strays from the target, but it's not clear how much it really affects aiming.
  • Minimum shooting delay (MinShotDelay): minimum pause between reloading and resuming firing.
  • Maximum shooting delay (MaxShotDelay): maximum pause between reloading and resuming firing.



Targeting and prediction of the enemy's movement. Unlike the majority of other games, Oni's AI does not "cheat" by starting from 100% accuracy and then adding some degree of error (even though additive error is also present in Oni; see above). To the contrary, there's a bit of a problem making the AI a precise marksman ^_^. The AI is given input parameters such as the distance between itself and the enemy, the present velocity of its enemy (as a vector), and the velocity of their gun's projectile (as a number, not a vector). From this data, the AI logic computes a prediction of the enemy's location and the ideal aiming vector for hitting the enemy.

The ONCC parameters for targeting and prediction are (XML tags in parentheses):
  • Predict amount (PredictAmount): some sort of multiplier for prediction mechanics.
  • Predict position delay (PredictPositionDelay): in frames, the delay before prediction is applied, so that the AI always somewhat-outdated prediction.
  • Predict delay frames (PredictDelayFrames): in frames, the delay before prediction is computed. Must be set to at least 1.0.
  • Predict velocity frames (PredictVelocityFrames): this is a period of time in number of frames, but the meaning is not 100% clear. Maybe the enemy's velocity data is obtained and used for prediction algorithm during this period of time? Must be set to at least 2.0.
  • Predict trend frames (PredictTrendFrames): another period of time in number of frames that is not 100% clear. Maybe the distance ahead that extrapolation of the enemy's movement takes place? Must be set to at least 2.0.
The ONWC parameters for targeting and prediction are (XML tags in parentheses):
  • Prediction speed (PredictionSpeed): more precisely "projectile prediction speed". This value is taken by the prediction algorithm as the speed of a projectile fired with the corresponding fire mode of the ONWC weapon. Thus, when the actual PAR3 projectile's speed is changed, this prediction behavior produces misleading results (i.e., the AI is unable to hit moving targets).
  • Maximum inaccuracy angle (MaxInaccuracyAngle): maximum allowed deviation of aim from the enemy's pelvis while firing the weapon. If exceeded, the AI ceases fire and corrects its aiming, then resumes fire. The pelvis is considered to be the root point of the character, so without any modifications made to the targeting origin and vector (see ONWC), AIs always target the pelvis of the enemy.
  • Aim radius (AimRadius): no idea what this does.
  • Ballistic projectile speed (ProjectileSpeed): a separate prediction method can be used if the weapon fires gravity-affected projectiles (e.g. grenades). The AI then adjusts its aiming in order to hit the enemy using the ideal (parabolic) ballistic curve. This is a horizontal speed component.
  • Ballistic projectile gravity (ProjectileGravity): the vertical gravity component of the same projectile.
  • Targeting direction (Direction): a vector with three components (x, y, z) which gives the orientation of a firing spread. When set to wrong values, the firing spread will not cover the area where the weapon actually shoots (it can even point backwards ^_^). Friendly advice: do not alter unless needed.
  • Targeting origin (Origin): a vector with three components (x, y, z) which tells the AI where to fire in relation to the enemy's pelvis. When an armed AI is firing at an enemy, the AI searches for his/her pelvis (see TRIA), as the pelvis is the representation of the whole character in the AI system. The vector described in this parameter tells the AI how much and in which direction to deviate from the enemy's pelvis position.
So when the vector is set as (0, 0, -2), the AI will aim two world units above the enemy's pelvis position. Here is the effect of setting each component positive and then negative, from the shooter's point of view:
  • x - deviate forward/backward (does not have much of an effect when firing at someone on the same floor, as you would expect)
  • y - deviate right/left
  • z - deviate down/up (headshots, anyone?)


Miscellaneous ONWC AI setup - there are a few more parameters in ONWC which affect AI behavior with a weapon. They are (XML tags in parentheses):

  • Minimum shooting distance (MinShootingDistance): defines how close the enemy can be to the AI that is firing. If the enemy comes closer than this distance, the AI stops shooting and tends to move backward (a vector-based movement; see HERE) until the distance is again equal to or greater than the minimum shooting distance. Then the AI opens fire again. To witness this effect, watch an AI operating an SBG when its enemy is close to it.
IMPORTANT: for some unknown reason, the value from this field is divided by 2. So when set to 100, the AI starts backing up when its enemy is 50 units away.
  • Maximum shooting distance (MaxShootingDistance): The opposite of the parameter described above, this limits how far away an enemy can be before the AI stops shooting and starts moving closer. Watch an AI shooting with the SMG at a distant enemy.
  • Fight timer (FightTimer): a bit similar to thetimer-based BSL command chr_dontaim. Defines in frames for how long should AI switch from a weapon variant (shooting) to a melee variant (hand-to-hand combat) if this firing mode was used (don't forget, a weapon can have two firing modes) and certain conditions were met. See below for KnockdownSwitcher and StunSwitcher flag explanations.


  • The basic parameters of a weapon (pistol or rifle, type of ammunition, etc.) can be set using various flags in the ONWC (<Flags> in XML). These three flags from among those affect AI behavior (XML tags in parentheses):
    • NoHolster: apart from disabling the ability to holster the weapon, this flag also makes the AI ignore this weapon when lying on the ground. One exception is w10_ba1 when the AI has the Superammo flag (InfiniteAmmo in XML) set in its CHAR profile; then this AI character can pick up the WMC cannon. If an AI is given the weapon, it will still fire it.
    • Stun switcher (StunSwitcher): if the enemy is within an armed AI's shooting range and was knocked down, stunned or blown up, the AI switches to melee for a time specified in the weapon's Fight timer (see above). This flag was designed specially for w6_vdg.
    • Knockdown switcher (KnockdownSwitcher): similar to Stun switcher, but only a knockdown or a blownup makes the AI switch to melee. Tailored for w4_psm, probably to avoid AI abuse of an unfair advantage that the PSP grants (the enemy cannot get up as long as she/he is being shot).



Modding hints: Phew, what a long section. The described material has plenty of modding possibilities. Still, modders should be aware of a few things:

  • Don't set too high of a dodge vector (DodgeWeightScale), and don't overdo it with the dodge timer (DodgeTimeScale) -- the smallest possible value is 0.4; lower is not registered. The delay before gunfire dodging (DodgeReactFrames) should be minimal, otherwise it can happen that the AI won't start dodging till the shooter's weapon is empty.
As a side note, there is a glitch in gunfire dodging. It is not a coding bug, but a limitation of the simple vector-based movement. When the AI starts its gunfire dodge, it tries to get away from the source of danger (be it a firing spread or projectile). And because vector-based movement works as a "desire" to go in some direction, it can happen that the AI will express a "desire" to go into a wall. In such a case, the character stops until the desire to move into a wall stops -- in other words, until the enemy stops shooting at the AI. When an AI character is unarmed, it will try to switch between pathfinding movement (go towards the enemy and attacking him with melee) and vector-based projectile dodging movement, so it kind of looks like the AI is still trying to dodge the gunfire. If the weight of gunfire dodging is set to be smaller than the standard vector-based movement weight, then the AI does not even have to get stuck, as it will run in a zigzag pattern towards the armed enemy.
If the AI is armed with a loaded weapon, there is no point in the AI running towards enemy. That means if the AI starts dodging and meets a wall, this AI gets "stuck" until the enemy's gunfire stops. If this character has "ShootDodge" set in their ONCC, it will at least fire back at the enemy shooter. But in case the character has "RunAwayDodge" set, then it simply stands near the wall and stares and waits till the enemy's gunfire ceases.
From this explanation, it can be seen that the gunfire dodge parameters should be set to make the AI dodge, but to not make the dodge vector outweigh the vector for moving towards the enemy.
  • An AI's skills with weapons (in ONCC) can be used to create anything from sharpshooters to rookies who cannot hold a gun properly. For example, by setting "ShootGroupError" to 10.0 for w1_tap, we create a total amateur whose hand shakes all over the place when he fires the Campbell Equalizer. You can experiment with different settings in realtime using the ai2_skill* functions on the dev console line. See this video where ai2_skill_error is used to override a character's original grouping error setting with new values.
  • Unless really necessary, do NOT alter the ONCC prediction parameters. Bungie set them quite reasonably, and if they are messed with, the AI loses accurate predictive abilities.
  • In ONWC, Prediction speed is used for a calculation of the AI's aim. This speed should be exactly the same as the speed of this weapon's projectile. A projectile's velocity is usually set in the emitter of the projectile particle (PAR3). The separate values means that the predicted speed and actual speed of a weapon's projectile may differ, the most significant case being w3_phr (plasma balls accelerate rapidly).
If Prediction speed is set lower than the speed of a projectile, the AI will tend to shoot too far in front of an enemy moving left/right since it will assume the projectile is slower than it really is. On the other hand, setting this value higher means that the AI will shoot too directly at the moving enemy (probably missing), as the AI will think the projectiles are fast enough to hit the target.
  • Similar to Prediction speed, there are Ballistic projectile speed and Ballistic projectile gravity. When these two fields are set to non-zero values, the AI assumes that the projectiles are ballistic (e.g. grenades), and tries to shoot along a parabolic arc (the solution with shortest travel time is always chosen). In order to make AI successfully hit an enemy's pelvis, these values again must correspond with the particle's (PAR3) speed and gravity attraction, but they can be used for modding purposes as well. For example, if a projectile's gravity attraction is 0.5, but in the ONWC, the Ballistic projectile gravity is set as 0.3, the AI will shoot projectiles at the enemy's feet as it will assume that the gravity attraction of the projectile is lower and it does not have to aim so high in order to hit the pelvis (credit to Gumby). Remember: for the AI system, the pelvis is a representation of a whole character.
  • The targeting origin vector (ONWC) can be utilized to make the AI fire higher than the pelvis (with a negative "z" component), so the AI can score headshots. Currently, such a change does not have any purpose, as characters don't have separate damage coefficients for different body parts. But maybe in the future... or with Paradox's headshot mod... (see HERE for his material-dependent damage mod ideas).
  • One thing purposely left out in our main discussion of weapons is that there is an option for AIs to perform "startle" misses -- when startled, the AI can fire in some random direction. The parameters for this behavior are in ONCC and ONWC, but overall this feature is so minor that it does not need any special modding attention.
  • Remember: in the ONWC, Minimum shooting distance is divided by 2. The reason is unknown (maybe some bug in the code).
  • Through modification of Minimum shooting distance in conjunction with BSL scripting, a modder can achieve pseudo-intelligent holstering behavior. If an enemy gets too close, the AI will start backing away. Since this backing away motion is almost never used by an armed AI (it usually moves side-to-side), it can be watched for using the BSL function chr_wait_animation, and used as a trigger for scripting code to make the AI holster his weapon. To unholster, a different animation has to be watched for, such as a taunt animation. In MELE, a modder can set up a melee profile which makes the AI taunt only at a safe distance.
A drawback of this modification is that the enemy will not fire his weapon at point blank range, and also it limits the Melee override in CMBT to be only None or IfPunched; otherwise, instead of backing away, the AI goes directly into melee.



Melee combat behaviors

Ah yes. After all those OTHER things, we finally get to how the AI system handles the core gameplay feature of this game, hand-to-hand combat. First things first. As usual, a player can see her/his enemy trying to perform some move and react to it. An AI, however, cannot see a thing because it does not have eyes, nor a human brain. Thus the first question is, How does the AI learn about incoming attacks?

Melee zones around a character
A rough illustration of melee zones.
The answer lies within the TRAM files. Each animation which can hurt somebody should have "extents". Extents are invisible boundaries which tell the AI about the range of enemy attacks. There are two types, horizontal and vertical, but the more important thing AI-wise is that, without extents, attack TRAMs will not be registered by AI characters as attacks, so AI will not try to block or dodge them. As long as the attack has extents data, then the AI will have the needed knowledge of the path of the attacking character's body parts (see attack part of TRAM).
This info is used by the melee part of AI for defensive purposes (deciding what kind of evasive move to use, and whether to crouch or not) as well as for offensive purposes -- an AI will not execute an attack move unless it sees that the enemy falls within its attack move's extents.


Also, for hand-to-hand purposes, the engine recognizes roughly four zones around a character (see picture on right). These zones correspond to positioning moves, so when a melee technique has, for example, CloseBack, then the only time this melee technique is listed for possible execution is when the enemy is in back of the AI. In all other cases (enemy in the left, right or front zone), this technique is NOT listed for use. The exception is when a technique has the GenerousDir flag set; see below for more info.


Melee mode AI combat is handled via MELE profiles. A MELE profile is assigned to a spawnable character in its CHAR profile. When in melee mode, an AI uses vector-based movement. Unless otherwise specified, the AI is inclined to run towards its enemy.

A MELE profile always contains these parameters (XML tags in parentheses):
  • Character class (CharacterClass): link to an ONCC. The importance of this parameter not known, but maybe it is necessary in order to allow for some attacks to be performed (engine checks being performed through the ONCC and its TRAC).
  • Notice (Notice): percent chance that AI will notice an incoming attack. In retail profiles, it is always set to 100.
  • Dodge base (Base inside Dodge): percent chance that AI will try to use an evasion moves (if it has any in the evade section of its MELE profile) to avoid getting hurt.
  • Dodge extra (Extra inside Dodge): extra chance to dodge.
  • Dodge extra damage (ExtraDamageThreshold inside Dodge): amount of damage needed to activate the extra chance of dodging.
  • Single block skill (Single inside BlockSkill): percent chance of an attempt to block an incoming attack.
  • Group block skill (Group inside BlockSkill): percent chance of maybe of blocking more attackers???
  • Not blocked (NotBlocked): a multiplier which affects the weight of techniques which will not be blocked by the enemy under the current circumstances (such as a punch combo against an opponent who is running forward).
  • Must change stance (MustChangeStance): a multiplier which affects the weight of techniques which force the enemy to change stance (standing vs. crouching) in order to block them under the current circumstances (such as a leg sweep against a standing opponent).
  • Blocked but unblockable (BlockedButUnblockable): a multiplier which affects the weight of techniques that have the "unblockable" flag set in their attack part (see TRAM attack part settings).
  • Blocked but has stagger (BlockedButHasStagger): a multiplier which affects the weight of techniques that would make the enemy stagger if the enemy does block them, that is, they have the "stagger" flag set in their attack part (see TRAM attack part settings).
  • Blocked but has block stun (BlockedButHasBlockStun): a multiplier which affects the weight of techniques that would trap the enemy in a blocking animation for longer than 20 frames, that is, they have the "block stun" flag set in their attack part settings (see TRAM attack part settings).
  • Blocked (Blocked): a multiplier which affects the weight of techniques that will definitely be blocked by the enemy under the current circumstances and will not stagger or stun the enemy.
  • Throw Danger (ThrowDanger): something to do with throws, but only Bungie West knows the meaning of this field.
  • DazedMinFrames, DazedMaxFrames: These were documented by Neo, but the question is, Do these two parameters actually have any effect, since the get-up time is controlled from the ONCC?


Our basic melee setup is done. Now the profile branches into an attack part, an evade part, and a maneuver part. Each part has a certain number of "melee technique" slots. A melee technique is a set of one or more melee moves. A melee move is any single element of hand-to-hand combat -- an attack, a throw, a positioning command, or some maneuver. The maximum number of techniques in one melee profile is 32. If this limit is exceeded, Oni crashes. Let's take a detailed look at all three parts of the MELE profile:

  • Attack branch: techniques from this branch are executed when the AI is trying to attack and hurt its enemy. The attack branch contains not only attack techniques, but also maneuver techniques (more about this later).
  • Evade branch: techniques containing moves which are used to evade an attack -- escape moves (as when the player presses crouch + some directional key) and/or various jumps/slides. These techniques are picked only when an AI is reacting to an incoming attack.
  • Maneuver branch: techniques from this branch should be used by the AI to maneuver around, so as to not just move in a straight line towards the enemy, but also circle around him, retreat, or advance. Unfortunately, this branch is probably a development relic. The AI only starts performing techniques from this maneuver branch when the global BSL variable ai2_spacing_cookies it set to zero, but that means that the AI cannot execute attacks.
The idea was probably that when the AI had run out of attacks to execute (each attack "eats" a cookie), the AI would use the maneuver branch for a bit until it got a new cookie, and so on and so on. But somehow this setup was abandoned (the question is whether MELE was really planned that way ^_^ ), and techniques from this branch are de facto never used. This means that all maneuvering is done via the Attack branch.


Structure of a melee technique:

  • Name (for debugging purposes only)
  • Flags: the possibilities are:
  • Interruptible: this technique can "home in" on the enemy to some extent, and if the enemy gets out of its reach, the technique is ended prematurely.
  • GenerousDir: this technique is listed for possible execution even when the AI's facing does not match the position move of this technique (e.g. the technique uses CloseLeft but the enemy is directly in front). If the technique is used, the AI positions itself in order to perform the technique (in our example, the AI would turn his left side to the enemy and perform the technique).
  • Fearless: does this flag actually do something?
  • Weight: the basic weight of the technique. Techniques are chosen randomly, but with the "weight" of the technique taken into account. Techniques with higher "weight" are used more often than those with lower "weight".
Also, there are more factors which affect the final weight of the technique. The basic weight of the technique is, according to the combat situation (position of the enemy, effect of moves in the technique), multiplied by one of the MELE profile's multipliers (NotBlocked, BlockedButHasStagger, etc.), then it is also multiplied by some diminishing value which decreases the weight of the technique if it is used consecutively. And finally, the weight of the technique is multiplied by a special "orange tiles" multiplier, which weighs down techniques that would make the AI fall over an edge, that is, dive into a part of the pathfinding grid that would be visualized as an orange-tiled area.
The equation is PROBABLY very roughly something like this:
Final weight = basic weight * corresponding MELE profile setup multiplier * diminish multiplier * "orange tiles" multiplier
  • "Importance": documented by Neo, but does it have any effect?
  • RepeatDelay: in frames, how long should the technique be unavailable after its use (to avoid predictability).
  • Moves: the possible types of moves are:
  • Position: usually takes three parameters -- minimum distance, maximum distance, and tolerance range. The meaning of minimum/maximum distances is clear; the tolerance range specifies an extra distance (beyond the chosen TRAM's attack extents) over which the AI will chase the enemy till the enemy gets inside the extent range of the attack this AI wants to use.
Some positioning moves don't have any parameters (Crouch, StartToCrouch) and are used strictly for stance purposes -- to make the AI perform crouched or special attacks. Positioning moves are used to give the AI variety in their available attacks, as techniques are chosen based on the melee zone the enemy is in (see picture at the beginning of this section). HERE is a list of all available positioning moves in melee combat.
  • Attack: no parameter, just an attack action. HERE is a list of all available attack moves in melee combat.
An attack move can be the only move in a technique (no positioning move). If that is the case, then this technique is put into a list of possibly techniques only when its prerequisites (positioning and stance) are met via other means. For example, Kick_forward can be used without a Position move, but since a move is evaluated only when the AI sees an enemy within its extents, the AI will have to get into the correct position for the attack by some other means (maybe another melee technique), otherwise the technique with Kick_forward will be labeled as MISSBOUNDS.
  • Throw: no parameter, just a throw move. HERE is a list of all available throw moves in melee combat. As with an Attack, a Throw can be standalone, to be used under the circumstances described above.
  • Evade: no parameter, just an evasive action. HERE is a list of all available evasion moves in melee combat.
  • Maneuver: taking up to three parameters, these moves are used to make the AI move around (advance, retreat, circle left/right) or perform various movements (crouch, jump, taunt, use uncommon get-up moves etc.). HERE is a list of all available maneuver moves in melee combat. Almost all maneuver moves have a Duration (in seconds) as a first parameter.
Melee techniques can be a mixture of melee moves. The very first move (which should be positioning or maneuvering) is evaluated to make sure if the technique can be performed with the current positioning of the AI and its enemy. However, throws and maneuvers are checked as well even if they are not the first technique, so if a technique contains Throw_punch_behind, for example, it will be listed for use only if the AI is behind its enemy. Surprisingly enough, pairing Kick_forward and Kick_back makes the AI kick forward when the position is correct for a forward kick, and then kick backward even though there is nothing to hit ^_^. The same goes for other directional attacks.


Also, there is one special condition to executing melee techniques. When there is a ledge in a level, it is usually covered in pathfinding grid by a series of special tiles going from blue (border) to orange (danger). As mentioned earlier, the engine seems to check if an attack TRAM's extents run into an area of orange pathfinding tiles and, if so, it decreases the weight of techniques which would make the AI end up in an orange field (which would mean going over the edge). Techniques which utilize jump positioning moves are excluded from this weight decrease, so there is a very limited and random possibility for AIs to jump across gaps in order to reach the enemy.

The code behind all this must be pretty complex; hats off to the Oni developers who managed to pull this off.


Modding hints: Creating custom MELE profiles can be fun, but beware of a few pitfalls:

  • Positioning moves can be followed by some other positioning moves, but generally after a positioning move an attack or throw move is expected. If an attack or throw is not present, this melee technique will be labeled as NOATTACKNOTHROW and will be unused.
  • Jump positioning moves can be used to make the AI sometimes jump across gaps. As explained above, the presence of orange tiles nearby will up-weight jumping moves a lot. Just don't forget to follow up the jump positioning move with some jumping attack move.
  • Special attacks (e.g. Rising Fury, Devil Spin Kick) use the StartToCrouch positioning move as a starter.
  • Any combo technique (for example, a three-punch combo) without the Interruptible flag will make the AI too vulnerable.
  • Rear throw techniques and side attack techniques should have a high weight to ensure they will be chosen and used the moment there is a chance.
  • Set the distances in positioning moves reasonably so that the AI doesn't attempt to perform jumping or running attack moves at close distance.
  • Always try to utilize a given class' strength. The Fury is fast, so give weight to combos. The Tanker is slower, so give weight to throws and running attacks. The Ninja is a beast; set whatever you want and it will be annoying to deal with anyway.