YesNoOk
avatar

Invalid Combo detection (Read 1493 times)

Started by Ricepigeon, December 10, 2018, 09:42:20 pm
Share this topic:
Invalid Combo detection
#1  December 10, 2018, 09:42:20 pm
  • *****
  • Gaps? Where we're going, we don't need gaps...
    • USA
    • ricepigeon.neocities.org
This was something I ended up studying around late 2018 when I ran into issues involving my own code, so the majority of this code is loosely based on a similar method used by 41's characters.

If you've ever played any fighter that allows P2 to air tech out of a combo, such as Blazblue or Melty Blood, you'll know that the game usually gives you some type of indicator when you perform an invalid combo, where the opponent could have recovered during your combo but decided not to. This tutorial attempts to replicate such a system.

NOTE: You'll need at least 1 free variable in your character's code. For this example, I'll be using Var(35).

Assuming that you have the sprites needed for your "INVALID" indicator, you'll want to have 4 different animations: a fade in, and a fade out, one for each side (p1 and p2). Make sure that the last animation element of your fade-in animation has an infinite (-1) duration, while your fade-out animations have a finite time, otherwise you'll get weird instances of multiple explods:

Code:
;Invalid - Left fadein
[Begin Action 7944]
7900,8, -100,0, 1
7900,8, -80,0, 1
7900,8, -60,0, 1
7900,8, -40,0, 1
7900,8, -20,0, 1
7900,8, 0,0, -1

;Invalid - Left fadeout
[Begin Action 7946]
7900,8, 0,0, 1,, AS256D0
7900,8, 0,0, 1,, AS224D32
7900,8, 0,0, 1,, AS192D64
7900,8, 0,0, 1,, AS160D96
7900,8, 0,0, 1,, AS128D128
7900,8, 0,0, 1,, AS96D160
7900,8, 0,0, 1,, AS64D192
7900,8, 0,0, 1,, AS32D224

;Invalid - Right Fadein
[Begin Action 7945]
7901,8, 100,0, 1
7901,8, 80,0, 1
7901,8, 60,0, 1
7901,8, 40,0, 1
7901,8, 20,0, 1
7901,8, 0,0, -1

;Invalid - Right Fadeout
[Begin Action 7947]
7901,8, 0,0, 1,, AS256D0
7901,8, 0,0, 1,, AS224D32
7901,8, 0,0, 1,, AS192D64
7901,8, 0,0, 1,, AS160D96
7901,8, 0,0, 1,, AS128D128
7901,8, 0,0, 1,, AS96D160
7901,8, 0,0, 1,, AS64D192
7901,8, 0,0, 1,, AS32D224

Next, place the following code in your -2 state:

Code:
[State -2, Invalid Combo Explod]
type = Explod
trigger1 = numhelper(27944)
trigger1 = numexplod(27944)=0
trigger1 = helper(27944),var(59)=1
anim = 1998 ;<-Invisible anim
ID = 27944
pos = 0,0
postype = p1  ;p2,front,back,left,right
facing = 1
vel = 0,0
removetime = 999999999
pausemovetime = 999999999
supermovetime = 999999999
sprpriority = 5
ownpal = 1
removeongethit = 0
ignorehitpause = 1

[State -2, Invalid Combo RemoveExplod]
type = RemoveExplod
triggerall = numexplod(27944)
trigger1 = numhelper(27944)
trigger1 = helper(27944),var(59)=1
trigger1 = (helper(27944),var(0)=0)||(helper(27944),var(0)>100)
trigger1 = numenemy
trigger1 = enemynear(0),movetype!=H
trigger2 = numhelper(27944)=0
id = 27944
ignorehitpause = 1

[State -2, Invalid Combo Helper]
type = helper
trigger1 = numexplod(27944)=0
trigger1 = numenemy
trigger1 = P2StateType = A && P2MoveType = H
trigger1 = EnemyNear,CanRecover
trigger1 = (p2stateno != [120,155]) && (p2stateno!=[250,262]) && (p2stateno!=[450,451])
trigger1 = movehit=0
helpertype = normal
name = "Invalid Combo"
ID = 27944
pos = 0,0
postype = p1
stateno = 27944
ownpal = 1
facing = 1
pausemovetime = 999999999
supermovetime = 999999999

[State -2, Helper Movehit Flag]
type = varadd
trigger1 = var(35)>0
var(35)=-1
ignorehitpause = 1

In addition, add the following to each of your Helper states that have any Hitdefs (NOTE: Make sure these Helpers are created directly by the root and do not have another helper as its parent, otherwise this method will not work)

Code:
[State 2011, Helper Hit Flag]
type = parentvarset
trigger1 = MoveHit=1
trigger1 = p2stateno != [120,159]
var(35)=2
ignorehitpause = 1
persistent = 0

This code will create a helper that will handle the check for the conditions for displaying the Invalid Combo explod. It also creates an invisible Explod whenever this helper is active and removes it whenever this helper does not exist or when the opponent is not in a hitstate. The helper will also check to see if this invisible explod exists and, if at any point it does not, then the conditions for displaying the actual explod are satisfied. For this example, anim 1998 is being used as a blank animation.

Var(35) acts as a flag to tell us when a helper-based projectile has hit an opponent, and then counts down. The reason we use a variable here instead of helper(xxx),movehit is not only to streamline the code instead of having to write down all Helper IDs, but also to avoid situations where multiple helpers with the same ID exist, such as any move that spawns multiple projectiles, which can easily cause the movehit triggers to return false negative results.

Next is the helper state:
Code:
;=====================================================
; Invalid Combo Helper
[StateDef 27944]
type = A
physics = N
moveType = I
anim = 1998
velSet = 0,0
ctrl = 0
;var(0) - Elapsed time measurement after hit (for Invalid)
;var(2) - helper attack or hit flag (for invalid display)
;var(59) - Flag (0=Default, 1=Invalid)

[State -2, Varset]
type = varset
triggerall = var(2)=0
trigger1 = root,var(35)>0
trigger2 = root,projhittime(XXXX)=1 ;PROJECTILE CONTROLLER IDS GO HERE
var(2)=1

[State -2, Varset]
type = varset
triggerall = time=0
triggerall = var(59)=0
trigger1 = root,numexplod(27944)=0
trigger1 = numenemy
trigger1 = p2statetype=A
trigger1 = root,movehit=0
trigger1 = EnemyNear(0),CanRecover
trigger1 = (p2stateno != [120,155]) && (p2stateno!=[250,262]) && (p2stateno!=[450,451])
var(59)=1

[State -2, Varset]
type = varset
triggerall = var(0)=0 && var(59)=1
trigger1 = root,movehit=1
trigger1 = numenemy
trigger1 = p2statetype=A
trigger1 = enemynear(0),hitshakeover
trigger2 = var(2)!=0
var(0)=1

[State -2, Counterhit Explod]
type = Explod
triggerall = numexplod(7944)=0
trigger1 = var(59)=1
trigger1 = var(0)>0
anim = 7944+1*(root,teamside!=1)
ID = 7944
pos = ifelse(teamside=1,0,320),120
postype = left
facing = 1
vfacing = 1
bindtime = -1
removetime = -1
pausemovetime = 999999999
supermovetime = 999999999
sprpriority = 999
scale = 0.5,0.5
ontop = 1
ownpal = 1
ignorehitpause = 1

[State -2, Counterhit Explod]
type = Explod
triggerall = numexplod(7945)=0
triggerall = numexplod(7944)=1
triggerall = numenemy
trigger1 = enemynear(0),stateno=5150 || enemynear(0),alive=0
trigger2 = p2movetype!=H && p2stateno!=5120
trigger3 = enemynear(0),ctrl = 1
anim = 7946+1*(root,teamside!=1)
ID = 7945
pos = ifelse(teamside=1,0,320),120
postype = left
facing = 1
vfacing = 1
bindtime = -1
removetime = -2
pausemovetime = 999999999
supermovetime = 999999999
sprpriority = 999
scale = 0.5,0.5
ontop = 1
ownpal = 1
ignorehitpause = 1

[State -2, REX]
type = removeexplod
triggerall = numenemy
trigger1 = enemynear(0),stateno=5150 || enemynear(0),alive=0
trigger2 = p2movetype!=H && p2stateno!=5120
trigger3 = enemynear(0),ctrl = 1
id = 7944
ignorehitpause = 1

[State -2, Timer]
type = varadd
trigger1 = var(0)>0
trigger1 = var(59)=1
var(0)=1

[State -2, Destroyself]
type = destroyself
trigger1 = var(59)=1
trigger1 = var(0)=0 || var(0)>101
trigger1 = numenemy
trigger1 = (p2movetype!=H && p2stateno!=5120)||(enemynear(0),ctrl = 1)||(enemynear(0),stateno=5150 || enemynear(0),alive=0)
trigger2 = var(59)=0
trigger2 = time>=1


One important thing to note is the first varset controller. If you have any attacks that utilize any projectiles using a Projectile state controller (as opposed to a Helper-based projectile), you'll need to write down each of their IDs as a separate trigger here, as this method won't be able to account for them otherwise. Effectively what this helper does is toggle between states where the opponent is in a state where they can recover (using var(59)). The reason why can't just use the canrecover trigger by itself is that this will immediately be reset the next time P2 is hit, so we need to be able to keep track of their previous state before the next hit connects. The way this helper is set up is that once these conditions are true, the Fade-in animation for our explod will display until the combo ends, at which point it will transition into the Fade-out animation.

     Posted: December 12, 2018, 10:00:37 pm
Psuedocode for the above in case anyone wants to devise their own implementation of this method:

Quote
--------------------------
In the player's State -2:
--------------------------

If the Invalid Check Helper exists and has its var(59)=1, create a permanent explod(99) if it does not exist.
The explod should be active during all pauses.

Remove the explod if one of the following cases is true:
Case 1:
- Invalid Helper exists and its var(59)=1
- Enemy is not in a hitstate
- Helper's var(0) is either 0 or greater than 100 (see below)
Case 2:
- Invalid Helper does not exist

Create the Invalid Helper under one of the following conditions:
Case 1:
- Explod(99) does not exist
- P2 is in an aerial state and a hit state
- P2 can recover
- P2 is not in a guarding state or any other custom state
- P1's move did not hit (movehit=0)
Case 2:
- Explod(99) does not exist
- P2 is in Specific Custom State for a certain duration

The Invalid Helper must be active during all pauses


----------------------------
In the Invalid Helper State:
----------------------------

var(0) - Elapsed time measurement after hit (for Invalid)
var(2) - Helper attack hit flag (for invalid display)
var(59) - Call type determination flag (0 = default, 1 = invalid)

When var(2)=0, if root,numhelper(x) and (helper(x),movehit=1), set var(2)=1

At Invalid Helper time=0, when var(59)=0, set var(59)=1 under any of the following conditions:
Case 1:
- Root,numexplod(99)=0 (see above)
- Enemy is in an aerial state
- root's move did not hit (movehit=0)
- Enemy can recover, and is not in any Custom States

Set var(0)=1 when one of the following cases are true:
Case 1:
- var(59)=1 and var(0)=0
- root,movehit=1
- Opponent is in an aerial state with hitshakeover = 1
Case 2:
- var(59)=1 and var(0)=0
- var(2)!=0

Display the Invalid Combo explod when all of the following are true:
- Explod does not exist
- var(59)=1
- var(0)>0

Remove the explod when one of the following are true:
- enemy is not in hitstate and is not in state 5120
- enemy regains control
- enemy is KOed

Increase var(0) by 1 when the following are true:
- var(59) = 1
- var(0) is nonzero

Destroy the helper when one of the following is true:
Case 1:
- Var(59)=1
- var(0)=0 OR >=102
- Opponent is not in a hitstate and not in 5120, has control, or is KOed
Case 3:
- Var(59)=0
- helper's time>=1
Re: Invalid Combo detection
#2  February 19, 2019, 06:17:07 am
  • ***
  • CPU Purple Heart
    • USA
    • www.dailymotion.com/2a8130871d2742d2f4da3b069
 Going to bump this to address a few problems I've ran into while attempting to adopt this invalid combo detector over 9's version. There seems to be a massive delay for certain attacks to which I have a feeling may have to do with hitpause timings. Here are a few examples testing my own character for this purpose.

 Works just fine with specials, grabs and attack based helpers... but her non-grab normals completely fail to set off the FX even though these chains can be teched out in spite of their somewhat lenient recovertime (even though they incur longer hitpauses than her specials and helpers).



 Note that I keep relaunching and the invalid display fails to show up even though this move can be recovered out of as long as it hits.

 Edit: For the record, I checked the variables on displayclipboard and they register just fine. It's just the explod fail to show up with her normals for some reason.

 Edit2: Deeper investigation through messing around with the triggers has revealed to me that it may have to do with something about the hitshake trigger for the timer setter.

Quote
[State 27944, Varset]
type = varset
triggerall = var(0)=0 && var(59)=1
trigger1 = root,movehit = 1
trigger1 = numenemy
trigger1 = p2statetype=A
trigger1 = enemynear(0),hitshakeover
trigger2 = var(2)!=0
var(0) = 1
Last Edit: February 19, 2019, 04:28:22 pm by Nep Heart
Re: Invalid Combo detection
#3  February 19, 2019, 07:17:09 pm
  • *****
  • Gaps? Where we're going, we don't need gaps...
    • USA
    • ricepigeon.neocities.org
Out of curiosity, are your characters using modified versions of the default hitstates? Iirc, there's an issue there where characters won't be able to tech until after their transition animation (5035) finishes, even if the animation timing is longer than the actual recovertime. My characters already have this fix implemented, so idk if that's what's causing it or if there's something else at work within Miki here that's conflicting with the code, since the system works fine on my end. Still, I'll take a closer look just in case.
Re: Invalid Combo detection
#4  February 19, 2019, 11:34:43 pm
  • ***
  • CPU Purple Heart
    • USA
    • www.dailymotion.com/2a8130871d2742d2f4da3b069
 I seemed to have found a workaround that turned out consistent with all my creations. I just changed a few triggers especially on the timer so that it can account for longer hitpausetimes and have the helper destroyself trigger earlier so as to prevent the explod from flickering post-combo (it's especially noticeable whenever a character bursts out of an invalid combo).