.[B] MUGEN Study Files
Download Offline version HERE by Byakko

Top What's MUGEN Basic structure Process Elements Coding Format Ethic Links

Coding


Show / hide all
 
CONSTANTS (Show/hide)
Something you do once and then easily forget. At the top of the first CNS file, you'll find parameters that define your character : life, attack, defense, power, width, height, walk / run / jump velocities, position of the head and of the middle that are useful when someone tries to grab you for them to display you at the right position... It wouldn't hurt to remember checking them up once in a while.
 
MOST COMMON SCTRLS (Show/hide)
When coding a character, there will be SCTRLs you will be using significantly more often than the others. It's nice to take a look at the complete list to see if there isn't something you can make use of, but here is a quick sum-up of the most commmon ones. If this is your first time, a simple look at these will let you get used to them.
  • Type = ChangeState : sends your character to another state. There's only one thing to note (beside the obvious), as soon as a ChangeState is triggered, Mugen stops reading the state you were just in, so make sure your ChangeStates are at the end of the state.

  • [State 1000, end]
    type = ChangeState
    trigger1 = !AnimTime ; when AnimTime reaches 0, i.e. at the end of the animation
    value = 0

  • Type = PosAdd and Type = PosSet : what makes your character shift position by a fixed amount, either horizontally, or vertically, or both. It's better to use PosAdd in a punctual fashion, rather than over a range of time, as you will want to change the velocity for that. Beside PosAdd, there's also PosSet, but this sets the position relatively to the center of the screen. PosSet can be useful if you set the position with some expression that makes use of the position of another element - such as helpers or parents.

  • [State 1000, pos]
    Type = PosAdd
    trigger1 = !AnimElemNo(2)
    x = 8 ; moves 8 pixels forward
    y = -2 ; also moves 2 pixels upward

    [State 1000, pos]
    Type = PosSet
    trigger1 = !Time
    y = 0 ; instantly places you on the ground no matter how high you are in the air

  • Type = VelSet and Type = VelAdd : to change the velocity. You'll be using it a lot, the only thing you need to keep in mind is the Physics and StateType parameters, since those affect the evolution of your velocity, as described in earlier sections. The important thing to always keep in mind is that Mugen does what you tell it to do, and that your character moves around because he is coded that way ; if weird things happen (this can be frequent if you are not quite used to it yet), try to keep track of your velocity to always know what it is (we'll have a word on the debug mode for that in a moment) and know what can influence it. Physics are probably going to be your usual suspect.

  • [State 1100, VSet]
    type = Velset
    trigger1 = Anim = 1100 || Anim = 1102
    trigger1 = AnimElem = 4
    x = 1.5 ; starts moving you forward at the rate of 1.5 pixels per tick until further notice
    y = -8 ; starts moving you upward at the rate of 8 pixels per tick

    [State 1200, Velocity2]
    type = veladd
    trigger1 = Anim = 1200
    trigger1 = AnimElem = 2,>= 0
    trigger2 = Anim = 640
    y = .29 ; starts decreasing your Y velocity by the noted amount every tick

    With velocities, something else also easy to overlook and thus important to note is that the SCTRL keeps being applied as long as the triggers are true. Hence, if you see an odd behavior in your velocities, make sure you are not constantly triggering a VelSet, VelAdd or VelMul when it shouldn't.

  • Type = HitDef : what allows you to hit the opponent.
    First, for a HitDef to work, you need to have a MoveType of A ; if you don't have it, the hit will not occur (this may be used as a trick to activate or deactivate an attack based on various kinds of triggers). This is something easy to overlook when you aren't quite used to Mugen coding, so look there if a hit misses for some reason. Second, you also need a Clsn1 to be able to hit.
    After all that, there are a lot of parameters that can be specified for a HitDef - but not all of them are required, or even important. Only a few are absolutely needed and require attention. Among those parameters, you specify anything related to the hit : the statetype the target needs to be in for you to hit them (something important to look at if a hit misses for no apparent reason), how they can be guarded, the type of hit that will determine what standard gethit animation the target will play, how far they will be pushed back...
    Last thing about HitDefs is that you trigger them at one point, and then they stay active during the whole statedef, or until you trigger another HitDef, or until it hits - you can specify how many times it can hit, but once one hitdef runs out of hits, you'll have to trigger another one for more. You can only use one HitDef at a time (but you can use a Helper with its own HitDef if needed), and you don't need to keep triggering the HitDef for the whole duration of the hit : just trigger it once at the start of your attack (of the state, even) and let it be. If you trigger another HitDef, it will replace any active HitDef.

  • [State 200, 1]
    type = HitDef
    trigger1 = 1
    attr = S, NA ; a standing, normal attack (here, a light punch)
    damage = ceil(FVar(13) * 21),floor(21*8/100) ; a formula to change the damage according to specific parameters
    animtype = Light ; whoever gets hit will display their "light" and...
    ground.type = Low ; ... "low" gethit animation (you need to know both height and depth of the attack to know the animation)
    air.animtype = Back
    guardflag = MA ; can be guarded on the ground and in the air
    hitflag = MAF ; can hit someone on the ground, in the air, or falling after getting hit
    getpower = 40,20
    givepower = 20,20
    pausetime = 4,5
    sparkno = S(7010+random%8) ; some randomizer to vary the hitspark
    guard.sparkno = S7000
    sparkxy = -5, -85
    hitsound = S5,0
    guardsound = S6,0
    ground.slidetime = 10
    ground.hittime = 12
    air.hittime = 12
    ground.velocity = -6 ; whoever gets hit gets a backward velocity of 6 pixels per tick, then friction does the rest
    guard.velocity = -5.5
    air.velocity = -4, -5.25
    ground.cornerpush.veloff = -8.8
    persistent = 0

    There are a number of optional parameters for the HitDef, not all are needed, but it doesn't hurt to make sure you're not forgetting one.

  • Type = Explod : the one controller to display a graphic effect of any sort beside the character. The explods are visual effects that are just there and do nothing, they cannot interact with the other objects on the stage. However, there are a number of parameters and other SCTRLs that can be used to change the behavior of the explod - its size, its movements...

  • [State 105, Dust1]
    type = Explod
    trigger1 = Anim = 370
    trigger1 = AnimElem = 5
    anim = 7100
    sprpriority = 5
    Ownpal = 1
    scale = .5,.5
    ID = 7500 ; will serve for the upcoming ModifyExplod

    [State 7500, shrink]
    type = ModifyExplod
    trigger1 = Var(1) = 1 ; the trigger can be more important than usual if you want to do one special something
    ID = 7500 ; to know what explod you want to modify
    scale = 1.5-(.033*time), 1.5-(.033*time)

    Notice how, if the ModifyExplod is triggered every tick for a certain duration, the value of "time" increases, meaning that the values given for the "scale" parameter changes as time passes : basically, this here is making the explod shrinking with time.

  • Type = PlaySnd : also a very common SCTRL. Plays a sound. Different channels can be used ; if one sound uses the same channel as an already playing sound (of your own character), the first sound will be interrupted by the second.

  • [State 105, SFX]
    type = PlaySnd
    trigger1 = Anim = 370
    trigger1 = AnimElem = 5
    value = 40,0
    channel = 2

  • Type = Helper : a quite important SCTRL. As of the moment of creation of the helper, just give it a statedef number to start at and maybe an ID.

  • [State 1000, 1]
    type = Helper
    trigger1 = AnimElem = 4
    ID = 1010 ; a unique identifier for the helper, so the parent can look at it later as longas it's here
    name = "KoOhken" ; a name for the helper, just to look good and feel pretty
    pos = 65,-75
    Stateno = 1010 ; the helper starts with the code at that state and then reads it just as the character would
    ownpal = 1

  • Type = TargetState : used for throws - in a broad sense, as long as you want to be able to control the animation and movements of the target.

  • [State -2, Hou'ooLv2Cancel]
    type = TargetState
    triggerall = NumTarget(2000) ; check if you do have a target
    trigger1 = Anim != 2002 ; other triggers, skipped for this example
    value = 2054

    Puts the target in the indicated statedef from your own file. Do note that you actually need a Target for it to work. You have a target when you hit and as long as the victim stays in a MoveType = H state.

    [State 916, HitGround2]
    type = SelfState
    trigger1 = Pos Y >= 0 && Vel Y > 0
    value = 5100

    An example of a SelfState, to put at the end of your custom Gethit state where the victim is put. Here, the victim is sent to the state where he lands on the ground after falling from getting hit. Triggered when he actually reaches the ground.
 
MOST COMMON TRIGGERS (Show/hide)
As with state controllers, there are a number of triggers you will be using much more often than others.
  • Trigger1 = Command = "[name]" : triggers when you have pressed a button input sequence that has a name defined in the CMD file. You will often be using that trigger in the CMD file, but you may easily want to trigger some changestate or variable set directly in a state in your CNS file.
  • Trigger1 = Command = "SmashKFUpper" ; as defined in the first part of the CMD file
  • Trigger1 = StateType = [state] : an important trigger for changestates in the CMD file, rarely useful in the CNS file. When you want to perform a standing light punch, you don't want to trigger it if you are in the air. Use StateType for a trigger. One thing to note, for standing and crouching attacks, the trigger commonly used is not statetype = C or = S, but statetype != A ; you simply differentiate crouching and standing attacks by checking if you are holding the direction "down" or not.
  • Trigger1 = StateType != A ; you must not be in the air
  • Trigger1 = StateNo = [state number] : a very common trigger for chains and combos. If you want to chain a crouch light punch into a stand light punch, you will simply go to the changestate to the second attack and allow it to trigger while you are in stateno = [crouch light punch state].
  • Trigger1 = StateNo = [1000,1500] ; the number of the state you are currently in is between 1000 and 1500
  • Trigger1 = Anim = [number], trigger1 = AnimElemNo([tick offset]) = [animation element number], trigger1 = AnimElemTime([anim number]) = [animation element number] : an extremely common trigger in general. All sorts of effects and movements need to be triggered at a specific point of the animation - AnimElemNo is the trigger you'll want to use most of the time. [tick offset] is a number of tick, [animation element number] is the number of the frame in that animation. If the animation is made of 5 frames, the first is element 0, the second is element 1, and so on. If you need a more precise timing, you can use AnimeElemTime([element number]) = ([number of ticks]), where you can trigger your controller a specific number of ticks after the beginning of the specified animation element.

  • Trigger1 = Anim = 500 ; just as it says on the tin
    Trigger2 = AnimElemNo(0) < 5 ; currently displaying the fifth element of the current animation, however many ticks that frame lasts
    Trigger3 = AnimElemTime(5) = 3 ; currently three ticks after the start of the fifth element of the current animation, regardless of how many ticks the element lasts
    Trigger4 = AnimElem = 2, >= 0 ; another way of saying "0 or more ticks after the start of the second element of the current animation"

  • Trigger1 = P2Dist X = [0,number], trigger1 = P2BodyDist X = [0, number] : useful for grabs which you don't want to trigger if the opponent is too far away. P2Dist X gives the distance between the axes of both characters, and P2BodyDist X is the distance between the front (as defined by the Width constant) of both players. The same triggers exist with P2Dist Y and P2BodyDist Y. This may also be useful for AI coding, about which we will talk in a moment.

  • Trigger1 = P2BodyDist X = [0, 15] ; a typical distance range for a grab to be allowed
 
DEBUG MODE (Show/hide)
Activating the debug mode gives you plenty of information on what really is happening on the screen at this exact instant. To turn on the debug mode, hit ctrl+d (assuming you allowed it in the mugen.cfg file, it is enabled by default). Hitting ctrl+c will display the collision boxes of both players.
For the debug text, you can see on the bottom left corner one of the lines telling you what stateno you currently are in (this is useful if you think you are in a given stateno but actually are in another, or if you are stuck and need to know where...), what animation you are in, what element of the animation you are in ; use that in conjunction with the pause key and frame advance key (the keys on your keyboard next to the F1~12 keys) to keep track of exactly where you are in your code when things happen on the screen. You can use that to fix your triggers and fix which states and animations are used. When a helper is on screen, you can hit ctrl+d again until the information for the helper are displayed to check the same things ; you can also see the state of the other character.
bottom debug text
State number, animation (action) number, animation element, number of ticks into the animation are displayed in the bottom left corner. The name of the character it talks about is also displayed, as you can switch between characters, even see the data of helpers. Note that if you are currently reading your opponent's file (by being put in a custom gethit state), this line appears in yellow. This is useful to notice when someone used a TargetState and forgot to release the target through a SelfState.

It is also possible to display the value of triggers of your choice, with a Type = DisplayToClipboard. Check the docs that come with Mugen for the detail on how to use that controller, which you will probably want to put in StateDef -2 with something like a trigger1 = 1 (to let it be constantly activated). This controller lets you display on the debug text the value of whichever trigger you want, such as the distance to the opponent, the current value of a variable (extremely useful to keep track of when your variable takes a different value) and so on.

;---------------------------------------------------------------------------
[State -2, Clipboard]
type = DisplayToClipboard
trigger1 = time
text = "Combo : %f, dampener : %f, button : %d, vy : %f, anti-cheat : %d \n CvS2 Kim Kaphwan by Byakko"
params = FVar(10),FVar(13),var(4), Vel Y, Var(50)
ignorehitpause = 1

With this code...
DisplayToClipboard debug text
... you get this sort of extra info, right below the bottom debug text.

Other than this state debug, the debug mode also gives you some more information : if your character is missing a required sprite or a required animation, or if his code is performing an illegal operation that doesn't directly crash Mugen (such as trying to display a non-existent animation), Mugen will display a warning in the top part of the screen. A term you might come across is a "debug flood" - just as the name says, if an error is constantly happening, the debug text will be flooded by the same message constantly.
top debug text
Warnings and coding problems will be displayed on the top left side.

This debug mode MUST be one of your first reflexes when coding and troubleshooting. It will always help you.
 
TRIALS AND ERRORS (Show/hide)
The very first step you can take in Mugen coding is to open one of KFM's files, look for one something you're interested in, change the value, and see what it does. Then change the value again, and test the difference. Keep doing that until you get an idea of what the controller or parameter does, and how the value affects what you get on the screen.
This is the best method to learn how to code : trials and errors.
Change a value, test how it looks, and change it again. Break something, test what it does, and change it. Since the code is nothing but text where you can revert all your changes, you aren't risking anything by changing random values and testing what it does. You're probably not going to get the right velocity or timing on your first try anyway (unless you happen to have a tool to obtain it from the original game), so never fear changing a single value by 0.2 over and again until it looks perfectly right. You only need to close Mugen, save the changes, and restart it.
You'll also easily get into situations where something you thought was made right ends up causing troubles with something you are currently adding - just change it. Of course, that implies you're probably going to have to re-test everything that was related to it, but this is the price of getting it right. It's never difficult, and it's always a matter of spending an extra couple of minutes ; this is where you dedication shows.

Despite how simple this advice sounds, this is probably the point that will weight the most out of everything you can learn about coding. This cannot be stressed enough. Never feel down about spending an extra five minutes to change a value and see if it looks better. Never feel it's a waste of time. It never is.
 
TRIGGER REDIRECTION (Show/hide)
We have seen that helpers can have their own variables. We have seen that sometimes, you might want to access information that belongs to another character, or more generally, another element / another object in play. The tool for that is trigger redirection.
Take the example of a variable that belongs to the helper. The helper is considered as a separate object, that has its own variables - while the parent has his own variables as well. Sometimes, the helper needs to look at a variable from the parent, and vice-versa, the parent at a variable owned by his helper. Quite simply put, trigger redirection is a redirection for triggers : putting "Helper([helper's ID]),var(1)" will return the value of the helper's var(1) instead of the character's var(1). With that method, a given object (a character, a helper) can have access to any trigger of another object (the opponent, the parent/root, a helper, the target being hit, the partner) just by adding the redirection with a coma in front of the trigger. All triggers can be used together with a trigger redirection, and that can give you a lot of freedom. As with custom GetHit states, just try not to modify the value of another character's variable, you don't know what it might break. Trigger redirection will also be very useful for things like AI detection to know what exactly the enemy is doing and where he is - a simple example is "EnemyNear,StateType" to check if the nearest enemy is on the ground or in the air, at the very least.
Just as an additional note, in the case of redirection to enemies and helpers, you'll want to add a "trigger1 = numenemy" or "trigger1 = numhelper" just before, because Mugen might give you a debug flood (whether you actually have a helper/enemy at this point or not).

trigger1 = EnemyNear, StateType = A ; if the nearest enemy is in the air
trigger2 = EnemyNear, MoveType = A && EnemyNear, Vel X >= 6 ; if the nearest enemy is attacking and moving forward

At the time of writing, it is impossible to use multiple redirection (to check the enemy's helper's variable, for example) ; it may be possible to use a slight workaround by grabbing the PlayerID (which I quickly mentionned earlier) of each element and making just one redirection directly with that ID, but this can't do everything and will quickly show some limits. Multiple redirection is planned for future versions of Mugen.
 
ARTIFICIAL INTELLIGENCE (Show/hide)
Although some people (and some games) like to make AIs that can pick up your slightest mistake or delay to maul you and chain you for dozens of seconds without letting you touch the ground, the point of an artificial intelligence is to behave like a human as much as possible. Paying more for your mistakes may be a mark of increasing difficulty, but telegraphed sequences set in stone where you know exactly what the AI is going to do if you do this or that action are just plain bad. No, there's not necessarily any direction corelation between the former and the latter, but the underlying concept here is balance and variety. And behaviors that look as human as possible.

Let's take it from the beginning : make a list of the moves that are available to you depending on the situation, and then try to determine when the AI will attempt to use it. Is the opponent all the way across the screen doing nothing ? You'll probably want to charge up your powerbar if you can, or you'll run at him, or you'll throw a projectile and hope he'll be forced to move. Or you might do nothing, if you want a few seconds to relax. Is the opponent jumping at you, a couple of meters in front and above you, going down ? Dragon Punch. If he's close, throw a light punch or a crouching light kick - and if it connects, try a combo, like a second light punch or a special, or maybe a super if you can. Pointing out that the AI can perform combos too is important. If you know all your moves, which moves are safe in what situation, everything about them, you'll know what to do in every single situation (provided your character doesn't have a crappy movelist, of course).
Well, artificial intelligence is all about making the computer do the same thing as you. When you have more than one option (I hope your movelist is good enough for that), add a bit of randomness in your moves (with the trigger "Random", see the docs for details) ; adding random in your triggers helps in making sure your character doesn't always instantly attack every tick it can do something, but sometimes lets half a second or two pass before attacking. Simply remember that your triggers will be evaluated on every single tick, 60 times per second, so adjust your "random" trigger and make it loose enough to not be over aggressive.
Most of the work here is to determine the right triggers - to be used along with trigger redirection.

an attack flowchart / pattern

Once you have established a flowchart of all your possibilities (I hope they're varied enough), you can start porting the conditions for each move into code.
The first thing you want about the AI is to detect if it actually is the AI controlling the character. Basically, you use a switch (a variable) that will check if the AI is in control, and then be the main trigger for everything AI-related : if the AI is in control, do everything the AI should do, simple as that.
Up until Mugen 1.0, a few methods were made to detect that, some more complicated than others, and a number of which didn't work properly - if you see a character you control suddenly take over and start moving on its own, it means you inadvertantly activated the AI control switch, meaning the code thinks the AI is the one playing. You don't want that. As far as I know, the AI detection method that is the most trustful is the one set up by Winane - look up Winane AI activation and follow the steps very carefully (and I mean veeeeery carefully). Or get Mugen 1.0 and just use the shiny new AILevel trigger.
Once you have determined that the AI is in control, look at your ChangeStates in your CMD file : they say that the ChangeState can trigger if you input the corresponding command. Well, also allow it to be triggered if the AI is on. The AI version should have the same triggers (the same restrictions and availability) as the human input. And then add the triggers you set up for the AI, as described in the previous step. Again, usage of the "Random" trigger is important. Mix in the availability in combos, if a special move is available when in the middle of another attack for a combo, point out that the AI can do it (with a trigger on your AI switch replacing the command input) - again with a "Random" factor, for all of your combo options.

;---------------------------------------------------------------------------
; AI Ko Hou
[State -1, AIKH]
type = ChangeState
triggerall = StateType != A ; if I am not in the air
triggerall = AILevel && StateType != A && RoundState = 2 && (ctrl || StateNo = 500) && P2StateNo != [120,160] ; if I can do it
trigger1 = EnemyNear, StateType = A && P2BodyDist X < 150 && (Random < 100+35*(Life<400)+15*(P2BodyDist X <55)) ; if the enemy is in the air and coming at me
trigger2 = EnemyNear, MoveType = A && EnemyNear, Vel X >= 6 && Random < 120 && P2BodyDist X = [130,220] ; if the enemy is attacking and comming at me (yeah, you tell me if that's smart)
trigger3 = AnimElem = 3, > 1 && (Random < 75+30*(Life<400))
trigger3 = StateNo = 400 || StateNo = 410 || StateNo = 430 || StateNo = 200 || StateNo = 205 || StateNo = 235 ; if I am in one of the listed state numbers (all are attacks that don't need to connect)
trigger4 = StateNo = 210 || StateNo = 225 || StateNo = 300 || StateNo = 1460 ; if I am in one of the listed state numbers (all are attacks)
trigger4 = MoveContact && Random < (75+35*(Life<400)) ; if the attack in the above trigger4 has connected
value = 1100

An example of triggers allowing the AI to detect when to perform an uppercut. Note that most of these triggers include an increasing chance of performing the attack the less life I have, making the AI more aggressive as I lose life. Also notice how often I look at where the opponent is with "EnemyNear, StateType = A" or "EnemyNear, Vel X".

This is the generic guideline. For more technical details on how to make your triggers more specific, you can try to look up other characters or more detailed tutorials, if you can find some. But the largest part of the work is getting the right triggers, the ones that check where the opponent is and what he is doing, and deciding which move to perform depending on that.

Back to top
Powered by PHP         Powered by Engrish        Valid XHTML 1.0 Transitional        Valid CSS        Get Firefox        Scal hosted