ikemen-engine / Ikemen-GO

An open-source fighting game engine that supports MUGEN resources.
https://ikemen-engine.github.io
Other
717 stars 125 forks source link

Teleporting target with CvS2 Felicia #1070

Closed Jesuszilla closed 1 year ago

Jesuszilla commented 1 year ago

Describe the bug

I use a custom pushback system to handle proper Capcom pushback for ground hits as well as proper air acceleration for air hits. The system makes use of typically unused GetHitVar items to store necessary values. This seems to work fine for the most part, but when the opponent is knocked down, they tend to teleport.

I have no idea why the teleporting is happening either as there are no TargetBind or BindToTarget SCTRL's being used, nor are there any PosSets in the system apart from those to set Pos Y = 0 when landing from a fall. The relevant states to look at are -2 in the character CNS for most of the pushback value setting (fvar(39) for target 1 pushback, fvar(16) for target 2 pushback; var(56) is the timer split into 2 16-bit ints for both) and the TargetState SCTRLs and the states in the 15000's in cvssystem.lol

Buffering for the character is handled via multiple states defined in a helper in buffering.vns. The helper handles reading all inputs and sets a variable (root var(46)) to tell the character the stateNo to go to based on the input. States are skipped based on whether the root stateNo var's been set, or if Vans's Chizuru seal projectile is active.

To Reproduce

Download the attached character in the zip below and put her in a clean IKEMEN-Go build (0.98.2) with no other scripts or addons against a vanilla KFMz.

cvsfelicia.zip

Expected behavior

There should be no teleports after trips just as she does in M.U.G.E.N.

Screenshots / Video

https://youtu.be/esxqUBT8bQM

Engine Version (or source code date)

v0.98.2

Operating system

Other (mention in description)

Extra context or search terms

Happens on a clean build (no external scripts or screenpacks) on Raspberry Pi 4 Model B as well as Windows. Video demo done on Raspberry Pi 4 Model B.

K4thos commented 1 year ago

regarding this:

I use a custom pushback system to handle proper Capcom pushback for ground hits as well as proper air acceleration for air hits. The system makes use of typically unused GetHitVar items to store necessary values.

; You must then set the following values in your hitdefs (you can skip throws) ;fall.envshake.ampl = 0 ; to kill fall envshake altogehter ;fall.envshake.freq = [float] ; X accel (for air custom state) ;fall.envshake.time = [int_data] ; base ID is -1073741824. This also stores your variable indices. Refer to formula below.

the problem is no longer there after commenting out fall.envshake.freq and fall.envshake.time from cvsfelicia.cns, so looks like just setting fall.envshake.ampl to 0 is not enough for these values to not be overriden in ikemen go with some defaults or maybe they reset at different time. Can you elaborate how they behave in mugen and when they reset? I've never seen this workaround before. Is it popular method?

edit: I see this in source code:

if hd.envshake_time > 0 {
    sys.envShake.time = hd.envshake_time
    sys.envShake.freq = hd.envshake_freq * float32(math.Pi) / 180
    sys.envShake.ampl = int32(float32(hd.envshake_ampl) * c.localscl)
    sys.envShake.phase = hd.envshake_phase
    sys.envShake.setDefPhase()
}

so no check for fall.envshake.ampl. I assume mugen doesn't do any envshake calculations when ampl == 0?

Jesuszilla commented 1 year ago

It appears not to do anything in M.U.G.E.N when the ampl is set to 0, no, because when they hit the ground, there is no envshake applied from the HitDef. It doesn't make sense how this parameter is affecting X position in IKEMEN-Go, however.

K4thos commented 1 year ago

the above source code snippet is unrelated. It happens as soon as kfm goes to a custom state 15030. And it's fixed by changing fall.envshake.time from -535329753 to 535329753, so I suspect it's a facing problem. Not sure how to fix it, though. Maybe some value is read from the state owner or the opposite way, when custom stated. Do you suspect what trigger may be responsible? Paste a code block that uses this fall.envshake.time value for custom stated target movement, please.

Jesuszilla commented 1 year ago

GetHitVar(fall.envshake.time) in this system is only used for two purposes: storing variable indices and identifying that the HitDef is compatible with trades. Thus, negative is required for that uppermost bit to help make it more uniquely identified. The bits indicating compatibility when set correspond to the value -1073741824. All other bits are used to store variable indices to read from as follows:

[enemy1_pushback_fvar_index] | ([enemy2_pushback_fvar_index]64) | ([split_pushback_timer_var_index]4096) | ([dizzy_notification_var_index]262144) | ([primary_target_id_var_index]16777216) | -1073741824

6 bits, 6 bits, 6 bits, 6 bits, 6 bits so 30 bits total plus the two bits at the end to indicate compatibility. So it probably isn't related to that.

However, there is this which I use to provide a standard implementation for those who need friction:

[State 5030, 10]
type = VelMul
triggerall = HitShakeOver
triggerall = time > 0 || (prevStateNo = [15030,15050])
triggerall = HitVel X
triggerall = (GetHitVar(fall.envshake.time)&-1073741824) = -1073741824
triggerall = GetHitVar(XVel) < 0
triggerall = numEnemy >= 1
triggerall = (GetHitVar(ChainID)&-65536) = 131072
trigger1 = playerID(GetHitVar(ChainID)&16383), cond(numTarget, target, ID, -1) = ID || playerID(GetHitVar(ChainID)&16383), numTarget > 1
x = cond(GetHitVar(fall.envshake.phase) != 0, GetHitVar(fall.envshake.phase), 1.0)
y = playerID(GetHitVar(ChainID)&16383), cond(IsHelper, root, cond(numHelper(247), helper(247), cond(Const(Size.ShadowOffset) = 2228224 && FVar(Const(Size.Air.Front)) != 0, FVar(Const(Size.Air.Front)), 1.0), 1.0), 1.0)

[State 5030, 11]
type = VelMul
triggerall = HitShakeOver
triggerall = time > 0 || (prevStateNo = [15030,15050])
triggerall = HitVel X
triggerall = (GetHitVar(fall.envshake.time)&-1073741824) = -1073741824
triggerall = GetHitVar(XVel) != 0
triggerall = numEnemy >= 1
triggerall = (GetHitVar(ChainID)&-65536) != 131072
trigger1 = Enemy(0), cond(numTarget, target, ID, -1) = ID || Enemy(0), cond(MoveType = H, (GetHitVar(fall.envshake.time)&-1073741824) = -1073741824, 0) || Enemy(0), numTarget > 1
x = cond(GetHitVar(fall.envshake.phase) != 0, GetHitVar(fall.envshake.phase), 1.0)
y = Enemy(0), cond(numHelper(247), helper(247), cond(Const(Size.ShadowOffset) = 2228224 && FVar(Const(Size.Air.Front)) != 0, FVar(Const(Size.Air.Front)), 1.0), 1.0)

[State 5030, 12]
type = VelMul
triggerall = HitShakeOver
triggerall = time > 0 || (prevStateNo = [15030,15050])
triggerall = HitVel X
triggerall = (GetHitVar(fall.envshake.time)&-1073741824) = -1073741824
triggerall = GetHitVar(XVel) != 0
triggerall = numEnemy > 1
triggerall = (GetHitVar(ChainID)&-65536) != 131072
trigger1 = Enemy(1), cond(numTarget, target, ID, -1) = ID || Enemy(1), cond(MoveType = H, (GetHitVar(fall.envshake.time)&-1073741824) = -1073741824, 0) || Enemy(1), numTarget > 1
x = cond(GetHitVar(fall.envshake.phase) != 0, GetHitVar(fall.envshake.phase), 1.0)
y = Enemy(1), cond(numHelper(247), helper(247), cond(Const(Size.ShadowOffset) = 2228224 && FVar(Const(Size.Air.Front)) != 0, FVar(Const(Size.Air.Front)), 1.0), 1.0)

If I comment these SCTRLs out, or if I explicitly set fall.envshake.phase = 0 in the HitDef, the problem goes away. So I think we've found our culprit. Does fall.envshake.phase default from a different value than MUGEN's when not specified?

K4thos commented 1 year ago

yes, this was indeed a problem. fall.envshake.phase defaulted to NaN instead of 0, if it was skipped from HitDef. Thanks for the help with investigation.