YesNoOk

Show content

This section allows you to browse the content for this member. Note that you can only see content for which you have sufficient viewing permissions.

****
Vans is Offline
Contact Vans:

Vans

Contributor

Messages by Vans

    

Re: “Useless” constants we could make better use of?

 June 02, 2018, 11:57:21 AM View in topic context
 Posted by Vans  in “Useless” constants we could make better use of? (Started by Jesuszilla May 31, 2018, 04:32:44 PM
 Board: Development

On topic, what kind of values are you expecting to store and retrieve using the "constants"? For what purpose? And what advantages does this method bring versus the commonly use of community animations, or projectile/explods ID checks?

Well, the thing is, this is not meant to be a replacement of animations and/or projectile explod checks. Those methods will always be more efficient for detecting true or false statements. A constant would provide meaningful data (position, state number, coordinates, etc).

I can provide a reasonable use: properly defining mid.pos and head.pos. The standard set by Elecbyte ONLY allows for one fixed value of head.pos, which is usually calculated in many different ways depending on the person. Some people calculate this using a stance sprite, while others use sprites 5000,0 or 5010,0. It's a hilarious mess.

Consider Sakura's throw, for example:



Get hits vary so wildly between characters that head.pos is quite frankly not good enough for binding her properly in this throw.

One possibility would be to introduce individual gethit mid.pos and head.pos. For example, we could define head and body positions for the 5000,XX and 5010,XX series of sprites. With this we can avoid the vagueness of the original head.pos constant and actually make neck / body hold throws not look strange in more characters.
    

Re: “Useless” constants we could make better use of?

 June 01, 2018, 07:46:18 AM View in topic context
 Posted by Vans  in “Useless” constants we could make better use of? (Started by Jesuszilla May 31, 2018, 04:32:44 PM
 Board: Development

Adding to ink's idea, one possibility is to make use of one system variable.

We have 4 integer and 4 float sysvars respectively. To my knowledge only sysvar(0) and sysvar(1) are used at all within common1.cns, and the remaining two are rarely known to exist by most coders.

One possibility is to have the root store the PlayerID of said data helper during boot on state 5900. Once that is done, we can simply read the variables by retrieving the playerID from the opponent. This idea isn't too bad, a community helper would give us access to a whopping 100* standarized variables. The scary part is moderating their use.



I think it'd be pretty cool. I'm not sure how we'd use the double jump one though. Is there a way to read what it's set for in the opponent that I'm forgetting?

Yeah, you can read most of them using const (in this case const(movement.airjump.num)). The one I pitched originally was const(data.KO.echo) (lol).

The reason I pitched it is because it only uses values from 0 to 1, but it still behaves like a full integer constant.

One thing I should point out is that if some standard would be made, it should be used to detect data that can only be useful in numerical form and not boolean form. In the case of boolean form, it is much faster and efficient to detect an animation and not a number.

So just having a whole bunch of variables to indicate "yes or no" conditions would be a waste in this case.

 

One last possibility is using empty Projectiles. Projectiles are always a primitive root-owned object, so they're very fast to detect. Projectiles with no hitdef data are equally as efficient as explods in engine load, but tend to be less limited as they're very rarely used in most cases. Projectiles also let us define "windows", since they can be set to expire over a fixed amount of time.

Chizuru makes use of a dummy projectile to report that her sealing technique hit the opponent.
    

Re: Asymmetry, Transformations and custome changes are possible in MUGEN.

 May 30, 2018, 10:14:29 AM View in topic context
 Posted by Vans  in Asymmetry, Transformations and costume changes are possible in MUGEN. (Started by inktrebuchet November 28, 2017, 04:30:58 PM
 Board: Development

Eh? I remember being able to detect facing in custom states.

While facing can be detected, the problem is that you cannot detect if a sprite was "physically" flipped using .AIR code, I guess.
    

Re: chizuru Kagura

 April 10, 2018, 05:13:16 PM View in topic context
 Posted by Vans  in chizuru Kagura (Started by dampir June 11, 2014, 10:21:46 PM
 Board: Sprite Projects

She got a new intro in KOF98UM. In KOF2003, other than a new intro, all the new animations came from Maki.
    

Re: hitcount bug

 December 17, 2017, 11:57:01 PM View in topic context
 Posted by Vans  in hitcount bug (Started by DR119 December 17, 2017, 10:17:17 PM
 Board: M.U.G.E.N Development Help

    

Re: Marcos Bejarano Released Kyo Green

 December 01, 2017, 10:00:53 AM View in topic context
 Posted by Vans  in Marcos Bejarano Released Kyo Green (Started by Yagoshi300 December 01, 2017, 03:28:27 AM
 Board: Found Releases 1.0+

what is this
    

Re: under any circumstances do not enter this thread

 October 17, 2017, 06:54:06 PM View in topic context
 Posted by Vans  in under any circumstances do not enter this thread (Started by Vans October 14, 2017, 11:58:36 PM
 Board: Projects

    

new and improved athena asamiya

 October 17, 2017, 06:52:12 PM View in topic context
 Posted by Vans  in new and improved athena asamiya (Started by Vans October 17, 2017, 06:52:12 PM
 Board: Your Releases, 1.0+

    

Re: under any circumstances do not enter this thread

 October 15, 2017, 06:27:36 PM View in topic context
 Posted by Vans  in under any circumstances do not enter this thread (Started by Vans October 14, 2017, 11:58:36 PM
 Board: Projects

    

Re: Join the 2D making of KOF XIV

 October 15, 2017, 12:14:43 PM View in topic context
 Posted by Vans  in Join the 2D making of KOF XIV (Started by Rowy Delson October 15, 2017, 11:25:02 AM
 Board: Idea Engineering

    

under any circumstances do not enter this thread

 October 14, 2017, 11:58:36 PM View in topic context
 Posted by Vans  in under any circumstances do not enter this thread (Started by Vans October 14, 2017, 11:58:36 PM
 Board: Projects

    

Phase 5: Defining joystick commands.

 August 10, 2017, 05:51:30 PM View in topic context
 Posted by Vans  in Tiny Buffering! An easy, simple and compact buffering system!  (Started by Vans February 25, 2017, 04:04:10 PM
 Board: Development

Thanks for sticking around for all this time! Today we can finally go over the most important (and the easiest!) step. We will be defining commands.

Once you complete this section, you will be 100% capable of deploying a character with buffering.

.CMD standardization and synchronization.

A believing heart is everyone's magic!

Remember how I asked you to strip your .CMD of all special commands? Today is the day where we will start inserting them again.

In Tiny Buffering we take care of buttons as separate "entities", this means that in terms of MUGEN's parser we are only worried about checking the actual joystick inputs. Thanks to this, it is only necessary to define special commands as purely directional inputs and nothing more!

While this sounds natural in terms of the system itself, Tiny Buffering was designed precisely so we only had to define commands this way. This is because one extremely important goal can be effortlessly achieved and that is .CMD standardization.

What does this mean? Well, in MUGEN each .CMD file is limited to 128 unique command labels. For example, if we wanted to program a character with two different types of "shoryuken" depending on whether we use a punch or a kick... then we would have at least two different labels for what is the exact same motion of the joystick. Depending on the complexity of the character, many different labels might need to be used for the exact same joystick motion because the buttons are different.

Tiny Buffering eliminates this distinction, we only need one* label per joystick motion!

If we are programming a full game, for example, we can easily utilize one single .CMD file with these labels defined for every single character. We save space, resources and achieve what I call .CMD "synchronization".

.CMD synchronization.

In MUGEN we have one interesting trigger called "command", but what does it actually mean? When we program a character we know we have command labels, and when we use this trigger we ask MUGEN to check if the command used corresponds to the label. But this is not what MUGEN does!

When MUGEN loads our character it compiles a "list" formed by ALL our command labels, using the order in this list it identifies which commands we are asking for. This means, for example, that if "QCF_p" appears as the third command in this list, then what MUGEN does is the following:

  • MUGEN reads: command = "QCF_p"
  • MUGEN interprets this as checking if the third item on the list activates.
  • MUGEN checks if the third item on the list is activated.
  • MUGEN returns the trigger as true if the joystick command was performed.

The key is the second item, MUGEN is not actually looking for the name of the command, it is looking for its position on the list it compiles at the beginning. Which features open up to use if we have perfect .CMD synchronization? Easy!

Let's say you have a full game comprised of perfectly .CMD synchronized characters. When this happens the following triggers become perfectly valid and accurate in every situation:

  • partner,command
  • enemy,command
  • target,command

Number one is the most important in this list. With perfectly synchronized .CMD files, we can read our partner's commands accurately.

Having perfect .CMD synchronization allows us to program many features, including (but not limited to) real tagging! This type of tagging does not require the use of CTRL+3, remapping the keys of the second player or any external setups for it to work. With careful operation, this type of gameplay can be programmed with good .CMD synchronization!

Defining commands.

This is a piece of cake!

In this example we will program a special move, a super move is done exactly the same way! Let's set up a simple quarter circle motion.

In our CMD file we will need to define the joystick motion, like so:

Code:
[Command]
name = "qcf"
command = ~D, DF, F
time = 21

Observe that I have no buttons defined in it, this is important as we do this separately!

One important parameter here is "time", this is the window of time the player has to complete this motion. In KOF's case (by counting) a quarter circle motion has at maximum 21 frames for it to be completed.

Now, since we have defined a quarter circle forwards motion we will also need its reversed version. Recall that Tiny Buffering is an object that detects joystick motions in an absolute sense, this means that we absolutely need a label for the reversed version so we can detect it!

Just like we did the quarter circle forward, let's define the reversed version:
Code:
[Command]
name = "qcb"
command = ~D, DB, B
time = 21

Just like we did with the buttons, we will be setting a timer for this quarter circle!

Let's head over to the Tiny Buffering file and find the [COMMAND BUFFER] section so we can code it!

The basic timer should look like this:
Code:
;An example of defining buffering for a quarter circle.
[State 10371, QCF Init]
type = VarSet
trigger1 = p2dist X >= 0 && command = "qcf"
trigger2 = p2dist X < 0 && command = "qcb"
var(20) = 13 ;The joystick motion will be active for 13 frames.

As before, we create a timer that will have a window of "13" frames. Observe that we have two triggers, the first one is when the opponent is to the front so we keep track of the joystick motion DOWN,DOWN-RIGHT,RIGHT. In the other case, our opponent is to our back, so we check for the joystick motion DOWN,DOWN-LEFT,LEFT.

Since this helper does not turn, this assures us that we will not be affected by the reversed commands bug as we wanted before!

Now, in my case, KOF does not allow me to perform a standing special move if I hold down or the opposite cardinal direction at the end. To add this limitation, I will adjust my own triggers a little bit:

Code:
;An example of defining buffering for a quarter circle.
[State 10371, QCF Init]
type = VarSet
triggerall = command != "holddown"
trigger1 = p2dist X >= 0 && command = "qcf" && command != "holdback"
trigger2 = p2dist X < 0 && command = "qcb" && command != "holdfwd"
var(20) = 13 ;The joystick motion will be active for 13 frames.

Perfect! Depending on what you are attempting to code, you can add restrictions and refined checks as you wish. Observe that even the detection of reversed commands is completely open to you, the coder!

Let's not forget to log on our checklist that we have added defined this command:


Finally, let's head over to the [BUFFER DECREASE] and then [COMMANDS] subsection so we can decrease this timer. We will define it exactly as the button ones are set up:

Code:
;An example of decreasing the buffer timer for a quarter circle.
[State 10371, QCF Dec]
type = VarAdd
triggerall = root, HitPauseTime = 0
trigger1 = var(20)
var(20) = -1

So this section should look like this:


We are done in the Tiny Buffering file, all that is left is to go back to the .CMD and program the changestate!

In my case I am programming Reppuken, so I will need to check for punches to activate this special move. Exactly like we did the buttons, we make use of var(20) to detect the joystick motion!

This is how the changestate looks in my .CMD:

Code:
;---------------------------------------------------------------------------
;Reppuken
[State -1, Reppuken]
type = ChangeState
value = 1000
triggerall = RoundState < 3
triggerall = numhelper(10371)
triggerall = helper(10371), var(20)
triggerall = (helper(10371), var(0) = [1,3])  || (helper(10371), var(1) = [1,3])
triggerall = statetype != A
triggerall = !NumHelper(1005)
trigger1 = ctrl || stateno = 101
;Basic moves cancelable into command moves
trigger2 = stateno = 205 && animelemtime(2) > 0 && animelemtime(3) < 0
trigger3 = stateno = 215 && animelemtime(4) > 0 && animelemtime(5) < 0
trigger4 = stateno = 305 && animelemtime(2) > 0 && animelemtime(3) < 0
trigger5 = stateno = 315 && animelemtime(3) > 0 && animelemtime(4) < 0
trigger6 = stateno = 400 && animelemtime(3) > 0 && animelemtime(4) < 0
trigger7 = stateno = 405 && animelemtime(2) > 0 && animelemtime(3) < 0
trigger8 = stateno = 500 && animelemtime(2) > 0 && animelemtime(3) < 0
trigger9 = stateno = 505 && animelemtime(4) > 0 && animelemtime(5) < 0
;Mawashi Geri kara-cancel
trigger10 = stateno = 800 && animelemtime(9) < 0

Observe that the triggers that use the buffering are these:
Code:
triggerall = numhelper(10371)
triggerall = helper(10371), var(20)
triggerall = (helper(10371), var(0) = [1,3])  || (helper(10371), var(1) = [1,3])

var(20) is to detect the joystick motion and var(0) and var(1) detect punches, just like in our map!

We can now test and see how the buffering makes our commands easier to do, we can also check ourselves that the reversed commands bug is nowhere to be seen!

With this the very basics of how to use Tiny Buffering are complete! We can now rejoice in our new found buffering life.

Hurray!
    

The reversed commands bug.

 July 28, 2017, 01:10:06 PM View in topic context
 Posted by Vans  in Tiny Buffering! An easy, simple and compact buffering system!  (Started by Vans February 25, 2017, 04:04:10 PM
 Board: Development

The dreaded reverse commands bug.

Uncover the truth!

The reversed commands bug is one of the most folklore bugs mentioned by many experienced MUGEN coders. This bug became more popular when Elix, a former KOF creator, mentioned that zzzasd was the only KOF creator to attempt a fix for this bug. However, the bug itself has never been fully described or explicitly mentioned. Here it is:

MUGEN bug (reversed commands): Whenever MUGEN calls upon a turn function on an object, all instances of the "F" or "B" token in the command definitions are flipped by the parser. In essence, the default MUGEN joystick detection has no memory upon turning.

Allow me to explain in layman's terms what this means. For the sake of having no confusions here, I will be saying LEFT or RIGHT as a physical direction on the joystick, this means that I don't account for the current state of the game.

Suppose you have a DP motion, such as this:

Code:
[Command]
name = "dp_p"
command = ~F, D, DF, y
time = 20

Let's set an example scenario. Let's say that I want to do a reversal DP on a jumping opponent that is trying to cross me up. Naturally, you would adjust your input towards the direction your opponent is facing.

For the sake of having hard numbers, pretend that I input LEFT and DOWN-LEFT in 3+3 frames and that I will input the final direction in the 7th frame. Let's look step by step what happens:


As soon as the turn occurred, MUGEN read my inputs as "B,D,DF", so when I press a button I will not obtain a DP as I wanted.

By the same token, i can get a DP by accident.

Suppose the same cross up is about to happen and I hold forward. Suppose that I want to input a backwards half circle, "~F,D,B" instead to do a super cool command throw:


Well I'll be damned. There is the DP.

So the issue here is: if I begin to adjust for the turning behavior in my inputs, those inputs I did are not adjusted by MUGEN once I did them. In terms of command labels, this means that I have no way of retrieving the raw inputs that I was doing in the joystick (in LEFT, RIGHT fashion). MUGEN doesn't keep an accurate record of it. Because in essence, I did input a half circle just fine.

What does this mean for potential fixes? Well.

  • If we attempt to fix it by checking for the reversed command during the turning animation, then we will get the proper command only if we buffer it completely before or after the turning animation. A partial attempt will fail like the ones above.
  • If we split the detection into directionals only, then this bug will also affect these directionals. This extra layer would present problems while trying to keep memory of the raw inputs, since we are still depending on MUGEN's parser and the turning flag.

In terms of solving this issue, there is an underlying and fatal mathematical problem. The assignment MUGEN provides from joystick motions to commands is NOT a function. This means that MUGEN is assigning two different names to the same object.

That is, the RIGHT direction on the joystick is assigned to "F" if we are facing right or "B" if we are facing left. Essentially, we cannot detect if what the user did on the joystick was press RIGHT, because all the information we can obtain is either "F" or "B". Effectively, this is Schrödinger's direction. There is no inverse for this mapping, because it is not a function.

Mathematically, this problem cannot be solved unless we have a way of obtaining a real function to read the actual joystick inputs without tampering. So, what if we get rid of turning altogether?!

If we have an object in MUGEN, that is not affected by the turn behavior then the directions we press will never, EVER be affected by this turning bug. This means that every single directional input we read will actually correspond to what the user is physically doing to the joystick!

Eureka! A helper is an object that can satisfy this condition! This is precisely what Tiny Buffering does to fix the reversed commands bug once and for all!
    

Phase 4: Multiple button presses and shortcuts

 July 25, 2017, 12:25:20 PM View in topic context
 Posted by Vans  in Tiny Buffering! An easy, simple and compact buffering system!  (Started by Vans February 25, 2017, 04:04:10 PM
 Board: Development

Today we will go over working with double button presses and defining custom shortcuts.

Double button presses.


Now that we know how to work with single button presses, we can start thinking about the multiple button case!

If you recall what we did before, Tiny Buffering assigns a timer to each button we press. This timer, or buffer, represents how long this button shall be active. For multiple button presses, we want to follow the same basic idea.

One of the strong aspects of Tiny Buffering is that the implementation of multiple button presses is completely free! That means that we have complete control over their detection and definition. This control allows us to detect multiple-button negative edge, define custom shortcuts and even restrict or simplify the detection.

The most basic and common definition of a multiple button press is the first one that comes to mind: a multiple button press should be detected if all the buttons involved are active. That is, the active window is the same as the intersection of the active windows of the buttons.

This type of definition is the most simple and the best example to learn how to define them.

In this example, I will be defining a multiple button detection for the LP+LK combination, this will allow me to detect a roll.

Definition.

To define a multiple button press first we scroll down to the [DOUBLE BUTTON BUFFER] section in the main Tiny Buffering file. This section has been specifically made for this purpose.

Our first example is this:

Code:
[State 10371, DOUBLE BUTTON init]
type = null
trigger1 = var(14) := (((var(0) = [1,3]) && (var(3) = [1,3]))) ;var(0) is LP and var(3) is LK.

The trigger in this null controller has been written in variable assignment syntax, you can find more information about it in the CNS documentation, under expressions. This is a method for assigning variables directly using triggers instead of varset controllers.

Remembering our fabulous button map from the previous section, we see that var(0) and var(3) are the LP and LK buffer windows respectively.

Let's then analyze the expression:
Code:
 (((var(0) = [1,3]) && (var(3) = [1,3])))

Recall that if we evaluate an expression within parenthesis in MUGEN, then it will return either 0 or 1. Thus, this expression will return one of those two values.

This means that the expression does the following: the value returned is 1 if the windows for LP and LK are both active at the same time and it shall be 0 otherwise. We are then assigning this value to var(14).

This is a very fast way of programming varsets, and it is extremely useful when attempting to do heavy recursion and reducing controller instances. I encourage everyone to practice this type of variable assignment as an exercise.

Having this controller in place, var(14) is what we need to detect LP+LK!

This is what my controller for performing a roll looks on my CMD now:

Code:
;---------------------------------------------------------------------------
;Roll 1
[State -1, Roll 1]
type = ChangeState
value = 750
triggerall = RoundState < 3
triggerall = numhelper(10371)
triggerall = helper(10371), var(14) ;LP+LK detection
triggerall = command != "holddown"
triggerall = Statetype != A
trigger1 = Statetype = S
trigger1 = ctrl
trigger2 = stateno = 150 && power >= 1000
trigger3 = stateno = 151 && power >= 1000
trigger4 = stateno = 101

Creating shortcuts.


I hope you're getting your hands dirty, or all this reading will be pointless!

I once more will remind everyone of our fabulous map. It is so important that I will now repost it:

NORMAL BUTTONS
=>

NEGATIVE EDGE BUTTONS
=>

At this point in time we have done something extremely important: we are the ones that have full control over how, when and where a button is pressed. We have full control over the behavior of the buttons, to the point where we can think that the original MUGEN ones behave like hardware.

Since I am working with a KOF character, I only need 4 unique buttons for all the required actions of the character. This means that I have two free buttons: HP (Z) and HK (C). For this reason, I will create button shortcuts using the remaining two buttons, just like in the home ports of these games.

As an example, I will code a shortcut for the rolling command (LP+LK). This has always been assigned to the HK (C) button since the KOF series appeared on Playstation.

The idea is simple: whenever I press HK, the game should behave as if I pressed LP and LK at the same time. But wait! Our beautiful map says that, in fact, we want var(0) and var(3) to be set at the same time whenever I press HK! This is extremely easy to do now!

Let's create a new section for button shortcuts!

Before the DOUBLE BUTTON BUFFER section, let's insert a new section for shortcuts (if you don't have it already):

Code:
;-----------------------  [SHORTCUT DEFINITIONS]-------------------------------;
;This section allows you to define the behavior of shortcut buttons.

Your buffering file should look like this:


Recall that the coding order is sensitive! So make sure the order is correct!

Our objective is this: set the windows for var(0) and var(3) at the same time whenever we press HK. We can use variable assignment to do this!

Code:
;-----------------------  [SHORTCUT DEFINITIONS]-------------------------------;
;This section allows you to define the behavior of shortcut buttons.
[State 10371, SHORTCUT INIT]
type = null
trigger1 = command = "c"
trigger1 = (var(0) := 3) && (var(3) := 3)

This automatically defines a real shortcut, pressing the HK (C) button will behave as if you pressed both the LP (X) AND LK (A) buttons at the same time. That means that this button can be used not only to roll, but also to perform other actions such as special moves.

Now, one of the true powers of Tiny Buffering will shine! Recall that variable number identifiers accept expressions as input!.

So for example, you could use an expression of the form "var(root,var(xx)) := 3" to select which button to define. This means that these shortcuts can be fully customizable using a configuration file! This is something that was impossible before!

This concludes the introduction to multiple button presses and defining shortcuts.

My coding files after finishing this section can be found here.

See you next time!
    

Re: Sakura's House + Desolate Playground

 June 30, 2017, 08:11:25 PM View in topic context
 Posted by Vans  in Sakura's House + Desolate Playground (Started by -Whiplash- June 29, 2017, 12:41:16 PM
 Board: Your Releases, 1.0+

I haven't checked the stage itself, but I love the concept.

I just wanted to mention one thing: you guys might want to modify the starting position of the characters, because as it stands right now it provides an unfair advantage to P2 since P1 is closer to the corner.

Great job nonetheless!
    

Phase 3: Working with Buttons.

 June 30, 2017, 04:26:50 PM View in topic context
 Posted by Vans  in Tiny Buffering! An easy, simple and compact buffering system!  (Started by Vans February 25, 2017, 04:04:10 PM
 Board: Development

Let's do some actual work now and define our basic moves.

Adjusting our mindset.

Don't slack off!

Tiny Buffering already provides a foundation, which is buffers for the 7 buttons on the joystick. In order to not get confused it is very useful to think of the arrangement in a graphical way. This foundation has two different set of buttons, one set is for normal button presses and the other is for negative edge detection.  I have prepared two useful graphics so you can always remember what these buffers are!

First, I would like to get everyone on the same page as to what I mean by "LP", "MP" and "HK". This map I refer to works like this:

=>

Most coders will use this type of layout when working with Capcom characters. Of course, this order is inherited from the arcade and the home ports of their games. I believe that this order is natural and easier to understand than using the names "X", "Y", "Z", etc. In case of NeoGeo games, there is ambiguity when using the actual button names, in those cases I will do my best to specify which button I am talking about.

Tiny Buffering provides the following two maps for the two sets of buttons. This graphic makes it more natural to understand the layout.

NORMAL BUTTONS
=>

NEGATIVE EDGE BUTTONS
=>

Now that we have these two button maps in our mind, we can actually start using them now!

Working with buttons

First let's provide buffering for our basic attacks, that is, the attacks that only require a button press to work. I shall provide an example and let you do the rest.

First I find one of my basic attacks...

Code:
;---------------------------------------------------------------------------
;Jumping Light Punch
[State -1, Jumping Light Punch]
type = ChangeState
value = 600
triggerall = RoundState < 3
triggerall = command = "x"
triggerall = Statetype != C
trigger1 = Statetype = A
trigger1 = ctrl

And then adjust the command trigger to check for the appropriate buffered version...

Code:
;---------------------------------------------------------------------------
;Jumping Light Punch
[State -1, Jumping Light Punch]
type = ChangeState
value = 600
triggerall = numhelper(10371) ;Prevent debug flood.
triggerall = RoundState < 3
triggerall = helper(10371), var(0) ; The buffered version of LP
triggerall = Statetype != C
trigger1 = Statetype = A
trigger1 = ctrl

Note that the line 'numhelper(10371)' is required to prevent debug flood errors, so don't forget it!

In case your basic contains any lines such as:
Code:
triggerall = command != "holddown"

Then these should be replaced to lines of the form:
Code:
(helper(10371),command != "holddown")

As you can see, it is the same condition! The difference is that we're asking our buffering helper to check.

This is used to keep everything standard, as we will be asking our buffering for directions further down the road. In case you have any basic commands such as running or hopping, you can leave them as-is for now. We do not need to modify these for Tiny Buffering step 1!

After carefully making the appropriate changes, my .CMD file now looks like this.
    

Phase 2: Buffering and Timers.

 June 30, 2017, 03:03:49 PM View in topic context
 Posted by Vans  in Tiny Buffering! An easy, simple and compact buffering system!  (Started by Vans February 25, 2017, 04:04:10 PM
 Board: Development

Alright, today we shall be learning about how to work with the buttons. This will also help us understand the main idea behind buffering.

Understanding a buffer.

I figured we'd need good motivation for this section.

A fighting game engine has two very important pieces to deal with user inputs, these two parts are the command parser and the buffer.

The command parser is the system that constantly receives input from the user via the joystick. This system constantly receives the input data and alerts the engine whenever it finds a favorable "pattern", these "patterns" are precisely the revolutions used to define special moves. You can think of this system as a system that understands "joystick-ese" and translates it into "commands".

In MUGEN, the command parser is the section that is located in the .CMD. For example, take a look at this line:

Code:
[Command]
name = "QCF"
command = ~D, DF, F

This piece of code is directly communicating with the command parser in MUGEN. This code says, "Dear command parser, keep a look out for the word '~D, DF, F' from joystick-ese, and translate it into 'QCF'". Afterwards, we can only refer to the command by name, because this parser is actively translating the word.

The command buffer is the system that receives the data from the command parser and performs operations in order to fine-tune the controls and adjust priorities. This piece was introduced mainly because of two things: humans are slow and using joysticks proficiently is difficult.

The command buffer will receive a note from the command parser whenever a new "word" is received. The buffer will then decide how complex this "word" is to give the user enough time to perform other actions with the joystick and complete a message. Without a buffer playing fighting games would be next to impossible, as we would have 1-frame windows to perform any action!

You can think of the command buffer as an editor for the translation given by the parser. The parser only translates words, but the editor makes sure these words flow together nicely.

These two systems are very intimately linked and both are absolutely necessary while designing a fighting game.

In the concrete case, Tiny Buffering is a replacement for MUGEN's buffering system in order to correct its flaws. Not only can we correct its flaws, we also have more precise control over the buffering system to more closely replicate buffering in commercial games.

On the other hand, Tiny Buffering Step 2 provides a replacement for MUGEN's command parser. This is, again, done to correct bugs and problems in the original implementation.

Timers.

Stop time!

Let's get to work now! Now that we have a general idea of how a buffer works, there's one very important concept that pops up, and that is, the concept of windows. By window we of course mean an interval of time which is often defined in "frames", or that is, 60ths of a second.

Thus, we arrive at a core concept for a buffer, and this is the concept of timers, in order to create these windows we require a set of carefully defined timers.

To define a timer in MUGEN we need three things:
  • A variable to store the timer.
  • A controller that initializes the timer.
  • A controller to decrease our timer.
That is, we need two controllers in order to define a timer. The Tiny Buffering template I provided already includes several pre-defined timers as an example, but we shall go over them to understand why they were defined that way.

Let's take a look at one of the timers that is labeled "LP" in my example:

Code:
;----------------------------[BUFFER DECREASE]---------------------------------;
...
;--------------------------------[BUTTONS]-------------------------------------;
...

[State 10371, LP Dec]
type = VarAdd
triggerall = root, HitPauseTime = 0
trigger1 = var(0)
var(0) = -1

...

;--------------------------[BUFFER DEFINITION]---------------------------------;
;----------------------------[BUTTON BUFFER]-----------------------------------;
...

[State 10371, LP Init]
type = VarSet
trigger1 = command = "x"
var(0) = 3 ;This defines how long the buffering should be for this button.

Alright! So as we can see, this is indeed a proper timer with two pieces: the timer definition controller and the controller to decrease the timer. Please note that I specifically wrote a huge label at the top that says "buffer decrease" and another that says "buffer definition", and this has to do with the coding priority I spoke about before. If these two controllers are reversed in order, then the timer will decrease as soon as we define it, making the window ambiguous.

Since this is extremely important, I will now write in big bold letters so you remember.

When you define a timer, the controller that decreases this timer should be ABOVE the controller you use to define the timer.

Tiny Buffering already separates these sections so you never forget or get confused. Respect these sections and you will avoid problems.

I cannot stress this point enough, I know of many veteran coders who do not pay attention to the coding order and priority in controllers and end up making mistakes when defining timers. This is a real problem, please just follow the section labels and you will be fine, they were designed for precisely this purpose.

While it is possible to write timers in a million ways and one so they can be in a different order, we are really just going around the problem. The way we will be using is the simplest way to write them so there is no ambiguity between what the constants represent and what each controller does. In other words, this is code that can easily be read and easily understood for everyone involved.

Moving on! Let's take a look at the pieces here. First, the buffer definition controller:

Code:
[State 10371, LP Init]
type = VarSet
trigger1 = command = "x"
var(0) = 3 ;This defines how long the buffering should be for this button.

This controller creates a timer of "3" frames whenever we press the "x" button (commonly mapped to Light Punch). This number represents (in frames) how long the buffer window should be for this button. In KOF, this number is usually '3' frames for a button, which is what I provided as default.

Similarly, we will use the same syntax when we move to joystick commands.

Let's take a look at the buffer decrease controller:

Code:
[State 10371, LP Dec]
type = VarAdd
triggerall = root, HitPauseTime = 0
trigger1 = var(0)
var(0) = -1

As you can see, this controller decreases the timer by 1 frame. I will now explain the first trigger.

The condition 'root, HitPauseTime = 0' checks if your character is currently in hitpause. If the buffer was to decrease during hitpause, then the commands would not work correctly if the hitpause is longer than the buffer. Fighting games actively perform this operation to preserve the timer when the player is paused in this fashion.

This trigger is necessary because a helper does not inherit the hitpause effect of the root.

The second trigger, "var(0)" is the same as the trigger "var(0) > 0". This checks if our timer is still active before we attempt to decrease it.


Timers for the rest of the buttons are defined and designed in this manner. We will define more complex timers with this same mindset later on.
    

Re: Tiny Buffering! An easy, simple and compact buffering system!

 June 29, 2017, 10:14:18 AM View in topic context
 Posted by Vans  in Tiny Buffering! An easy, simple and compact buffering system!  (Started by Vans February 25, 2017, 04:04:10 PM
 Board: Development

Indeed, normally that behavior is difficult to replicate, especially with characters that have an extremely short running animation. This system can reproduce that behavior because it allows you to instantly reset the buffer time of all the buttons in a single frame, like KOF does.

This is also useful for implementing roman cancels and any feature that requires very precise control over the buffer windows.
    

Coding structure, priority and recursion.

 June 03, 2017, 06:42:47 PM View in topic context
 Posted by Vans  in Tiny Buffering! An easy, simple and compact buffering system!  (Started by Vans February 25, 2017, 04:04:10 PM
 Board: Development

In this section I'll talk a little about coding structure, coding priority and recursion.

Coding priority.

The Tiny Buffering system was designed to make efficient use of the way MUGEN handles coding. Remember that the code in each state is parsed from top to bottom in a single frame. This implies that the order in which we structure the coding is important when we try to optimize or achieve certain types of behavior.

The concept of protecting code order is not a new one, this is actually really important when we are trying to define the .CMD file. If we place two very similar commands in the wrong order, then we could run into trouble.

For example, consider the case where you have a dragon punch (F,D,DF + P) and a fireball (D,DF,F + P). On the .CMD file, you would require [ChangeStates] in order to use both of these moves. Let's say that the state for the dragon punch is 1000, and the state for the fireball is 1100.

Let's observe what happens with the two different code orders.

CASE 1. In our .CMD file we write the two changestates in this order:

Code:
[Changestate, to state 1100]
trigger1 = ...   ;The dots mean the rest of the coding goes here.
...

[Changestate, to state 1000]
trigger1 = ...
...

If we write in this order, then the engine will read the [Changestate] for state 1100 before the [Changestate] for state 1000. That is, the dragon punch changestate code takes priority over the fireball changestate code.

Let's say then that you input F,D,DF,F + P very quickly to get a dragon punch. At the time we press punch, MUGEN will have understood that your joystick inputs were exactly "F,D,DF,F".

Since "D,DF,F" is a part of those inputs, and the changestate for 1100 takes priority over the other one, then this changestate will trigger first. This means, we will perform a fireball instead of a dragon punch.  As you can already tell, this does not happen in commercial fighting games.

So what happens in the other case?

CASE 2. In our .CMD file we write the two changestates with the opposite order

Code:
[Changestate, to state 1000]
trigger1 = ...   ;The dots mean the rest of the coding goes here.
...

[Changestate, to state 1100]
trigger1 = ...
...

In this case, state 1000 takes priority over state 1100, and thus, the test we had before will now work as it should! This is the right order we wanted!

When we are deciding the order of changestates for commands we usually call this "coding through order of complexity". Some people also refer to this as "putting the complicated commands on the top". Just as the name implies, the more complex the command, then the more coding priority it will require, otherwise more simple commands will take precedence over it.

This type of coding concept can be generalized to all the coding that is done in MUGEN, and it is very good practice to carefully decide the order in which certain types of behavior are programmed.

Thinking outside the box about the box.

Now that we are starting to pay attention to the coding order, we can have a clear picture in our mind of the way coding is read. So let's just put it into an actual picture now:


This concept is very simple and very fundamental in MUGEN coding, but not many coders make full use of the power and possibilities good order optimization can provide. MUGEN provides a very powerful coding style that is well tuned for programming things recursively. Good coding order can expand simple ideas, like displaying digits on-screen, to very complicated ideas, like programming an entire system for handling text.

So when it comes to working with a system such as Tiny Buffering, then it is a very good idea to change our perspective a little. We can think of Tiny Buffering as a box, this is an invisible magic box that contains code that is checked every single frame. Since this box is a helper, then this box is executing its coding, independently from the player, every single frame!

This means that we have created a piece of coding that, regardless of the state of the root, will be running its own vital pieces of code independently. We can also communicate and trade information with this box. This means that we are working with a compact system, its definitions and behavior are all self-contained in their own states and it runs independently from the root.

Recursion and phantom data.

So now that we are working with a compact system, why is it so important to take care of the order we program things? That is so we can keep our options open for recursion. Recursion is a technique to define and execute things following a specific order.

We can think of a simple example: using only one variable, how would we display on-screen the individual digits of a 4-digit positive integer? This could come up if we are trying to define a system for displaying hit points or damage. Let's think about this problem and write down a logical solution to this (you can then attempt to code it as an exercise).

I will leave the solution as a spoiler in case you wanna try it yourself before reading!

Spoiler, click to toggle visibilty

So what happens in this example? Recall that mugen is reading our code from top to bottom in a single frame. So what happens to the values we kept feeding to var(0)? They certainly existed, but they are nowhere to be seen in the next frame. This is transitional or phantom data.

In MUGEN we can tailor many different types of phantom data, they could be constants (like in the example) or even entire states! A transitional state would be a state that is completely parsed by MUGEN during a frame, but it is not a state that is active at the time of a frame being drawn.  Plenty of MUGEN bugs are caused by people not realizing the existence of phantom states, their properties, and how to account for them. Even Elecbyte themselves have bugs caused by phantom states. Particularly, a big mistake is making use of the statement "trigger1 = 1" instead of "trigger1 = time >=0" but this is a discussion for a different time.

For Tiny Buffering, we shall not be requiring the use of any phantom states, but we will be taking care of having good coding order so we can make use of recursion. When it comes to variable-heavy systems or implementations, utilizing transitional data with variables is an extremely simple and efficient way of optimizing their use and simplifying the coding.
    

Re: Life bar Kof 97HD

 May 11, 2017, 08:43:27 AM View in topic context
 Posted by Vans  in Life bar Kof 97HD (Started by k6666orochi May 09, 2017, 06:54:11 PM
 Board: Projects

That looks really slick! Love it!