Select a topic:

PauseTime vs. HitTime Coding AI: Balance Coding AI: How I Do It


Discussion about MUGEN Works

This part of the site is by and large dedicated to talking about things that converters in MUGEN might be interested in learning about, or things that I've picked up in the course of being a MUGEN converter. I was inspired to start this when I began to notice, in part pointed out by my beta-testers for my King conversion, that I had become noticeably better at this whole thing. It was at that point that I felt that I wanted to try giving back a little bit to help out other people the way I was helped out (and still am being helped out).

By no means is this a perfect or complete guide to doing everything MUGEN related, and it will focus mostly on specific character creation issues and challenges. If you find any mistakes or have any suggestions, contact me at zerosenfanmail@gmail.com.

Special thanks goes out to the following people for making this possible via giving me feedback, being a role model or example to follow, and/or giving me coding help, disproving the notion that all people in the MUGEN community are massive pricks.

Vans
Jango/WaruiGouki
Jesuszilla
Orochi Gill
Shwa
Rajaa
Cybaster
Cyanide
2OS
Phantom.of.the.Server, a.k.a. PotS
KoopaKoot


My commonly used references:

It's best to use these in conjunction with what I discuss, especially the "greatest hits" thread. I'm not going to go over anything from it in more detail than I have to here--it's best to read both the docs and the thread yourself to get an idea of those things. Alternatively, if you don't think the question merits its own discussion, take it up with me over email and I'll see what I can do to answer that question.

The greatest hits of character feedback
The MUGEN documentation files, located in the docs folder of any fresh MUGEN installation. Of special note are the state controller reference (sctrls.html) and the trigger reference (trigger.html).


PauseTime vs. HitTime

Orignally published: 3/21/2011
Edited 3/24/2011: Pausetime guide adjusted downwards on all values.
Edited 4/4/2011: Pausetime guide adjusted downwards on all values.
Edited 12/15/2011: Hit and pausetime guide values adjusted.

One of the things I came to understand by working on King was how to utilize the "hittime" (ground.hittime = some number here, as well as guard.hittime = some number here and air.hittime = some number here) parameter in a HitDef controller, in conjunction with the "pausetime" parameter (pausetime = some number here), to make comboing easier. One of the most common mistakes, one that I have made quite a bit myself, is to use pausetime exclusively as the way to set up combos or chains, without editing the hittime.

The primary issue with this is that using pausetime alone, especially high values of pausetime, will just make characters that are hit shake in place for a while before snapping back to normal very abruptly, or be forced to stay in a guard state for a long period of time. This is because the pausetime parameter tells the engine how long the attacker should stay on the their current frame/element of animation, and how long the defender will be shaking from taking the hit. The hittime parameter tells the engine how long the defender is in a hit (or if they block the move, how long they are in a guard) state, and the actual amount of the hit animation that is shown increases as the hittime is increased. What's most critical about hittime is that it also works as one of the many ways to establish combos. If you hit an opponent that is still being affected by a ground.hittime or air.hittime parameter, the hit counter will go up.

To see what I mean by this, go into Kung Fu Man's kfm.cns file and edit the hittime of his stand heavy punch in state 210 to something preposterous, like 120. Hit an opponent with this modified attack, and when they're done shaking, they'll reel backwards, then play their recovery animation. However, when that recovery animation reaches the last frame (and hopefully stops there, as it's supposed to—if it doesn't, that's a coding error in that character's AIR file), they'll stay on that frame for some time before going back to normal. If you hit them with another attack, the hit counter should register another hit and appear on the screen. If you do this with the pausetime instead, and leave the hittime at its very high value, you'll see that the recovery animation will not play until the opponent stops shaking.

Setting up pausetimes incorrectly will lock the opponent in hit or even block stun, basically letting the attacker abuse the fact that one piddly light punch will keep their opponent unable to act for two seconds. If the attacker is hit out of the attack right as it connects, high pausetime will again cause the issue of shaking in place for a while. Depending on the speed of the attack, not using hittime might mean that MUGEN's hit counter doesn't count your combos correctly, which can really mess up combos or damage dampening. The key to making a good HitDef is to give enough hittime and pausetime to give the attacker a chance to press their attack, and the defender a chance to fight back when possible.

That said, it's fairly obvious that if the attack you're making is a small jab, then a large amount of pausetime or hittime for the opponent is not an option. The general standard I initially used was partially based on and established in the "greatest hits" thread, but has been revised since.

In most situations, it's best to keep the attacker and defender's pausetime at the same value, with some exceptions. If coding an attack where it's integral to have a lot of hitpause prior to the opponent's reaction, I prefer to add the guard.hitpause parameter and set it up so that the attacker's guard.hitpause is the same as it is in the normal hitpause, but that the defender's is at around half of the normal hitpause, or barring that, no more than three ticks higher than the attacker's hitpause. My hittime standard is a little looser than that, mostly because I tweak them on an individual basis, but I would give the following as a working guideline.
Using hittime,guard.hittime, and air.hittime in conjunction with setting the pausetime to something reasonable will usually give your opponent control of themselves again right as your move is ending. If you want even more specific control of when the opponent regains the ability to attack, you can use the guard.ctrltime parameter. Make sure that the animtype parameter is set accordingly before you set up these pausetimes and hittimes, as well. The exact timing of hit animations is different for every character, yes, but if the animtype parameter isn't set properly, the hit and recovery animations of the defender won't mesh very well with the hit and paustime parameters. Kung Fu Man is one of the characters that works well to test against; he doesn't represent every case of MUGEN character, but if he reacts to your hits properly, then more or less anyone else will.

Important to note is that projectile attacks usually have their pausetime parameters set to 0,0, and will have moderately high hittimes (in my case, on the level ofna heavy attack, or a bit higher if the projectile is very strong). They also have a higher ground.slidetime parameter, which will force the defender backwards for longer periods of time if the parameter is increased. The result is an attack that causes both an instant reaction and creates some distance between the attacker and the defender.


Coding AI: Balance

Originally published: 6/12/2011

AI can be a real dealmaker or dealbreaker in both commercial fighting games and in MUGEN. It's usually a point of contention in both places when a character's AI is so amped up that no one feasibly stands a chance against beating it. Having just begun to really get into AI coding for MUGEN, I know there are still a lot of things I canstand to learn, but I'll share what I've thought over and come up with here, as far as the development of a challenging, not unfair, opponent goes.

In terms of what makes a good AI, the goal itself is simple to state--the AI opponent should be strong, capable of holding its own, but not impossible to defeat. This is difficult to achieve because the AI has one clear advantage over the human player--timing. The AI on its own is not intelligent enough to know how to respond to attacks, but once you give it the ability to "read" situations somewhat, it can become an opponent to be reckoned with. This is good, and expected of most AI--it should react to the opponent's mistakes and use the moves best suited to the situation.

What is NOT good? Things like this:

I still have more to add to this list, but this covers the basic ideals that I keep in mind while making a character's AI. The next piece will likely cover how I determine how the AI uses specific skills, and when it uses them.


Coding AI: How I Do It

Originally published: 8/8/2011

Now that we've discussed the matter of balancing an AI we can talk about how to start writing one. Please note that the method I describe here works only in MUGEN 1.0. I find that the Winane method that was most popular and effective in WinMUGEN is extremely complex and not suited for people that want to get into AI coding without a lot of annoyances in their way.

[State -1, LP Twist Gear]
type = ChangeState
value = 1005
triggerall = statetype != A
triggerall = ctrl || stateno = 40 || Anim = 47 || (stateno = [100,101]) || ((stateno=[200,430])&&MoveContact)
trigger1 = IfElse((Anim!=[5,6]),command = "DP_x",command="RDP_x")
trigger1 = AILevel=0
;==
trigger2 = AILevel!=0&&RoundState = 2&&(EnemyNear,StateNo!=[120,160])&&EnemyNear,MoveType!=A
trigger2 = (random<180*(AILevel**2/64.0))
trigger2 = abs(P2Bodydist X)<=40
trigger2 = abs(P2Bodydist Y)=[75,125]
trigger2 = EnemyNear,HitFall=0
trigger2 = (EnemyNear,StateNo!=[800,899])&&(EnemyNear,StateNo!=[5070,5120])&&(EnemyNear,StateType!=L)
;==
trigger3 = AILevel!=0&&RoundState = 2&&(EnemyNear,StateNo!=[120,160])&&EnemyNear,MoveType!=A
trigger3 = (random<180*(AILevel**2/32.0))
trigger3 = abs(P2Bodydist X)<=40
trigger3 = abs(P2Bodydist Y)=[75,125]
trigger3 = EnemyNear,StateType=A
trigger3 = EnemyNear,HitFall=0
trigger3 = (EnemyNear,StateNo!=[800,899])&&(EnemyNear,StateNo!=[5070,5120])&&(EnemyNear,StateType!=L)
This code, used in the CMD, is an edited combination of something Seravy wrote for me a long time ago (what he started me with exists to some extent in Haruhi) and a trigger that Cybaster came up with for making randomized values scale according to the AI level.

The triggeralls are used to make rules that the AI and the human player have to hold to. For attacks with special limitations, such as projectiles that can only be fired one at a time (which fits all projectiles to be honest), a trigger such as triggerall=NumProjectile(****)=0 or triggerall=NumHelper(****)=0 is key. If you use a variable to keep track of some condition and you want that to be a requirement for using the move, you would include the var(**) trigger in the triggerall section.

trigger1s are used specifically for the human player. The only two things that need to go here are AILevel = 0 and the command that the player needs to use to make the move work. The IfElse you see up there is a special fix that Jesuszilla introduced me to. It allows the player to input the reversed version of a command when in a turning state in order to execute the move. The simple explanation as to why this is important is that when you land from a jump over an opponent, MUGEN will not properly reverse the commands, meaning that jumping over your opponent from the left side of the screen and landing on the right side of the screen will turn your forward dash command into a backward dash. Using this fix means that you have to have reversed versions of every special and super command in your CMD, but it's worth it.

trigger2 is the "default" AI action for a specific move. Basically, whatever you want the AI to do under normal circumstances, you define it here. The key to controlling how often the AI does something is in the random< trigger. If you're going to use AILevel!=0, that random< trigger, the randomization factor, has to be included. If you want to lower the frequency, make the number next to the < sign smaller and make the divisor (64.0, in the example above) a larger number. If you want to increase it, make the divisor smaller and make the number next to the < sign larger. Though I tweak it on an individual basis, all of the standing, crouching, and air "normals" (not special attacks, just the good old punches and kicks) for my characters using this system in its current form have a divisor of 32.0 and are multiplied by about 250 (as opposed to 180, as you see above).

In this case, Twist Gear is an anti-air attack, so I used the trigger3s to create an "anti-air" routine, again, for the AI only. As you can see, it uses most of the same triggers as the trigger2s, but also includes things like StateType=A so that it is used specifically as an anti-air. Additionally, the move has a higher frequency to occur than the "default" AI actions, so it's more likely to come out, but because all the trigger3s have to be true in order to use this form of the move, the opponent must be in the air and not in a falling state in order to trigger the higher chance to use the move.

You can create more situations in which the AI uses a move more frequently by using a set of trigger4s, or 5s, or whatever, but for the sake of not complicating things you may want to stick to the trigger2/"default" and trigger3/"special occasion" way of doing things. If you prefer to dissect this sort of thing in a more hands-on way, you can look at King and Leona's CMD files to see what I did and how I did it.


Select a topic:

PauseTime vs. HitTime Coding AI: Balance Coding AI: How I Do It