Mugen Artificial Intelligence short tutorialBy O Ilusionista - 2020.07.13Note: There are more ways to control this, different triggers to use, etc. This is one of the methods and the method I use on my characters, with some extra things here and there.AI got easier in Mugen 1.0 and beyond, since now we have a trigger to identify that the character is being controlled by the CPU
(AiLevel)AI is all about to tell the engine to do what you want - in other words, you just set the desired triggers and it will execute it.
To make it non-cheap is what makes it hard to do.
For example, take a look at those block of codes from RMM, for to make the character to block:
;--|-AI Defense-|-----------------------------------------------------------
[State -1, AI Defense]
type = ChangeState
triggerall = (roundstate = 2) && (AiLevel)
triggerall = (Ctrl) && (p2movetype = A) && (statetype = S)
trigger1 = (p2bodydist X <= 250) && random <= (800 * (AiLevel ** 2 / 64.0))
value = 130
[State -1, AI Defense]
type = ChangeState
triggerall = (roundstate = 2) && (AiLevel)
triggerall = (Ctrl) && (p2movetype = A) && (statetype = C)
trigger1 = (p2bodydist X <= 250) && random <= (800 * (AiLevel ** 2 / 64.0))
value = 131
[State -1, AI Defense]
type = ChangeState
triggerall = (roundstate = 2) && (AiLevel)
triggerall = (Ctrl) && (p2movetype = A) && (statetype = A)
trigger1 = (p2bodydist X <= 250) && random <= (800 * (AiLevel ** 2 / 64.0))
value = 132
Let me break down the code:
The first line is what triggers the AI
triggerall = (roundstate = 2) && (AiLevel)
Roundstate = 2 means "while the fight is going on" (read the manual about
Roundstate)
AiLevel is what tells you that the character is being controlled by the AI.
You will see that I use the codes between "()", this is to help the engine to check then faster/easily, since all the code between () must be valid.
So if AiLevel is great than 0, (AiLevel) will be TRUE. Its the same than writing "AiLevel >0", but instead of integer numbers, we are using boolean logic (1 = True, 0 FALSE) - which is faster than integer.
triggerall = (Ctrl) && (p2movetype = A) && (statetype = S)
(Ctrl) = The character must have control
AND (&&)(p2movetype = A) = P2movetype (the enemy who is attacking) should be an ATTACK
(statetype = S) = the character should be in STANDING state
trigger1 = (p2bodydist X <= 250) && (random <= 800)
(p2bodydist X <= 250) = P2 body (not only the axis) X distance needs do be equal or less than 250 (We could use "inguarddist" here too)
"random <= 800" (so the random change should be less than 800 - the engine will calculate it from 0 to 1000)
We can make it more complex if we add the AiLevel check / modifier
trigger1 = (p2bodydist X <= 250) && random <= (800 * (AiLevel ** 2 / 64.0))
random <= (800 * (AiLevel ** 2 / 64.0)) = This line looks more complicated, but we are using POTS method to calculate the AiLevel.
It would be the same of writing "random <= 800" (so the random change should be less than 800 - the engine will calculate it from 0 to 1000, and remember Mugen will only use positive values) but we are adding a multiplier for to make it scalable, so it will take the game AiLevel setting in count
value = 130
In this line, I am telling the engine to change the character randomly to Mugen Default Standing Guard Start state.
NOTE 2: Pay attention that the first two lines are TRIGGERALL, while the third one is a TRIGGER1.
Everything in TRIGGERALL is mandatory to be valid. If it's not, Mugen will skip* all other triggers
(it will still reads it for synthax errors, but won't parse it)
Read more about it
here NOTE 3: we have a bad habit of making the triggers to look more compact, as it would be faster to read by the engine, like this:
triggerall = (roundstate = 2) && (AiLevel) && (Ctrl) && (p2movetype = A) && (statetype = S)
But that is
not true, because the engine will read the first block and calculate if its valid (roundstate=2 is TRUE or FALSE), then proceeds to the next condition (AiLevel), and all others until the end of the line and ONLY WHEN IT FINISHES the line, it will check if ALL conditions are true (and all needs to be true). If not, the engine will skip it.
But we should use a less elegant (graphic wise) but faster (coding wise) solution: each trigger in one line
triggerall = (roundstate = 2)
triggerall = (AiLevel)
triggerall = (Ctrl)
triggerall = (p2movetype = A)
triggerall = (statetype = A)
And why? Because if the first triggerall is false (roundstate is not 2), the engine will stop doing logic checks for the rest of this block code.
Remember that TRIGGERLALL needs to be valid, so if just one line is false, the rest doesn't care.
The other blocks are the same, just changing the check (and the state change) for C (crouching) and A (air) states.