YesNoOk
avatar

Trouble with generic attack clashing [unsure if an Ikemen GO problem] (Read 10111 times)

Started by DoubleATam, March 28, 2023, 07:45:38 am
Share this topic:
Trouble with generic attack clashing [unsure if an Ikemen GO problem]
#1  March 28, 2023, 07:45:38 am
  • everything-hobbyist girl
  • she/her
Suddenly got into mugen (and more specifically ikemen go) for the first time in over a decade, and spent the past couple weeks researching some way to implement an attack clashing mechanic, by which I mean two normal moves canceling each other out on impact (not to be confused with anime beam-style clashes). I kinda wanted to see what would happen to put this on a lot of characters, but the existing solutions I found (such as beterhans's Saber) generally chose to manually put hitoverrides in all the individual relevant attack states (or sometimes, some other works i found attempted to do it with ReversalDefs despite that overriding the real HitDefs). This is a lot of work and didn't actually behave how I wanted, so I fiddled around and I think I made something closer.

I made a helper that mimics your current animations (invisibly), but it triggers a ReversalDef whenever you enter an attack state. This is pretty jank especially since it seems like I can't just synchronize with the animation frames and HitDefs directly, but it's something. According to what I've read in another thread, if a ReversalDef goes off for a helper, it will still in fact take precedence over the main player getting hit; and this partially seems to work that way. It *nearly* works.

Where this goes wrong is... I don't know if this is a mugen vs ikemen difference, or just a known bug, or what, but. While the reversal always goes off, depending on semi-consistent yet seemingly nondeterminstic circumstances, sometimes one of the two players will get hit despite its clone reversing the foe, and sometimes one of the two players will be reset to idle state as soon as it gets reversal'd by the other (despite the lack of a state change! I've tested it before, ReversalDef doesn't usually do that on its own). And it seems to depend on "controller port", ie, functional difference between p1 and p2.
I tested this using a modified KFM in a mirror match, and with a modified KFM vs regular KFM, and then again with the player numbers reversed: all had different results. (And this is to say nothing of the fact that the exact effects were different when i tested this earlier today, despite my not having made apparent functional differenes. Sometimes the results also depended on who punched first; that doesn't seem to be the case anymore?)

I'm more familiar with typical code so I went with ZSS scripting, I hope that doesn't invalidate my troubles. (I can convert this back to CNS if y'all find it strictly necessary, but it'd take a while since it's so verbose and not how i usually work.)
Here's the code to spawn the helper; I put at the end of -1 state, not sure if that's the ideal place for it:
Code:
if 
!numhelper(705)
&& roundstate >= 2
{
helper{
helpertype: normal;
stateno: 705; #i used PotS parry as a guideline but ultimately the code's all different
ID: 705;
name: "Parry Detection"; #naming the helper this lets it set off the "parrying" system message in ikemen go; i dunno if that's good or just confusing clutter
postype: p1;
pausemovetime: 65535; #todo look up why these are here
supermovetime: 65535;
ownpal: 1;
}
}

And here is the helper code in question:

Code:
[Statedef 705; #can't decide what number this should actually be. keeping it the same as the parry one is trouble
type: A;
physics: N;
movetype: I; #I thought reversaldef was supposed to not work unless movetype was A?
velset: 0, 0;
ctrl: 0;
]

BindToRoot{time: -1;} #stick to player
if root,facing != facing { turn{} } #make it flip itself
PalFX{add: 0,-255,-255; time:-1;} #DEBUG: tinted for testing animation disparities
#assertspecial{flag:invisible;} #TODO: turn invisible when done testing
NotHitBy{value: SCA;} #is this invincible enough? TODO: iirc it isn't, ironically because of reversaldefs
#will figure out a hitoverride here later

if anim != root,anim #on animation change
|| !root,AnimElemTime(1) || !root,AnimTime #on animation loop?
{
changeanim {value: root,anim;} # animation mimicking, somewhat imperfect especially when hitstun happens

if root,movetype = A #if it were up to me i'd have it go off on every hitdef, but sadly..
{
ReversalDef{
reversal.attr: SCA,NA,SA;
pausetime: 0,0;
sparkno: 3;
numhits: 0;
kill: 0;
}
}
}

ignoreHitPause if moveHit = 1 {
superPause{ #just temporary but does the trick for now.
pos: 25, -57;
time: 10;
anim: 100; #the anim's also useful for figuring out who's doing it
sound: 20, 0;
}
}

I hope this is enough info, I've been stumped. I was kinda hoping to come out with a useful resource or toy by the end of this.

I suppose there is still one thing left for me to try, which is converting it all to CNS and testing it in mugen to see if it's an ikemen go difference I can report.
Last Edit: March 28, 2023, 07:52:46 am by DoubleATam
Re: Trouble with generic attack clashing [unsure if an Ikemen GO problem]
#2  March 28, 2023, 10:35:11 am
  • ******
    • Portugal
    • network.mugenguild.com/pots/

  • Online
Are you using Ikemen 0.98.2? Reversaldefs had that issue of not protecting other players from the same hit but it's been fixed in the latest versions. Try using the nightly build.

And that method isn't such a bad idea. In Ikemen you could make the clash helper use AssertSpecial Animfreeze with RedirectID to the root.
You can help with Ikemen GO's development by trying out the latest development build and reporting any bugs on GitHub.
My Mugen and Ikemen content can also be found here.
Re: Trouble with generic attack clashing [unsure if an Ikemen GO problem]
#3  March 28, 2023, 03:13:11 pm
  • everything-hobbyist girl
  • she/her
Are you using Ikemen 0.98.2? Reversaldefs had that issue of not protecting other players from the same hit but it's been fixed in the latest versions. Try using the nightly build.
Oh yeah, I forgot to specify I am indeed already using the v0.99rc1 nightly. I actually saw your issue report in my desperate search for anything related, too. It might simply not have been fixed "enough" yet, which is a possibility.
I think that confirms the next thing I should do is test it in mugen. (You can tell I was dreading that somewhat.)

And that method isn't such a bad idea. In Ikemen you could make the clash helper use AssertSpecial Animfreeze with RedirectID to the root.
Thank you, but er, sorry, which method? Do you mean for hitpause?
Re: Trouble with generic attack clashing [unsure if an Ikemen GO problem]
#4  March 28, 2023, 03:42:19 pm
  • everything-hobbyist girl
  • she/her
OK it actually didn't take too long to rip the band-aid off. here's the CNS:

Code:
[State -1, clash]
trigger1 = !numhelper(777777) && roundstate >= 2
type = helper
helpertype= normal;
stateno= 777777; #i used PotS parry as a guideline but ultimately the code's all different
ID= 777777;
name= "Parry Detection"; #naming the helper this lets it set off the "parrying" system message in ikemen go; i dunno if that's good or just confusing clutter
postype= p1;
pausemovetime= 65535; #todo look up why these are here
supermovetime= 65535;
ownpal= 1;

Code:
[Statedef 777777]; #can't decide what number this should actually be. keeping it the same as the parry one is trouble
type= A;
physics= N;
movetype= I; #I thought reversaldef was supposed to not work unless movetype was A?
velset= 0, 0;
ctrl= 0;

[State 777777, btr];
trigger1=1
type=BindToRoot
time= -1; #stick to player

[State 777777, face];
trigger1= root,facing != facing
type=turn ;#make it flip itself

[State 777777, pal];
trigger1=1
type=PalFX; #DEBUG: tinted for testing animation disparities
add= 0,-255,-255;
time=-1;

[State 777777, invis];
trigger1=0; #TODO: turn invisible when done testing
type=assertspecial
flag=invisible;

[State 777777, nhb];
trigger1=1
type=NotHitBy; #is this invincible enough? TODO: iirc it isn't, ironically because of reversaldefs
value= SCA;

;#will figure out a hitoverride here later


[State 777777, anim];
trigger1= anim != root,anim || !root,AnimElemTime(1) || !root,AnimTime ;#on animation change or loop?
type=changeanim
value=root,anim ; animation mimicking, somewhat imperfect especially when hitstun happens

[State 777777, reversal];
triggerall= anim != root,anim || !root,AnimElemTime(1) || !root,AnimTime ;#on animation change or loop?
trigger1 = root,movetype = A ;#if it were up to me i'd have it go off on every hitdef, but sadly...
type=ReversalDef
reversal.attr= SCA,NA,SA;
pausetime= 0,0;
sparkno= 3;
numhits= 0;
kill= 0;


[State 777777, pause];
trigger1 = moveHit = 1
type= superPause ; #just temporary but does the trick for now.
pos= 25, -57;
time= 10;
anim= 100; #the anim's also useful for figuring out who's doing it
sound= 20, 0;
IgnoreHitPause = 1;

And upon testing it in mugen 1.0 ... that seemingly confirms this is a new bug in ikemen. I guess I'll head over to the github next.

Should I go ahead and mark this as "solved" (well, considering the blocking issue is unrelated to my actual efforts), or are there other workarounds or suggestions I should know?
Last Edit: March 28, 2023, 05:38:58 pm by DoubleATam
Re: Trouble with generic attack clashing [unsure if an Ikemen GO problem]
#5  March 28, 2023, 05:53:12 pm
  • ******
    • Portugal
    • network.mugenguild.com/pots/

  • Online
Oh yeah, I forgot to specify I am indeed already using the v0.99rc1 nightly. I actually saw your issue report in my desperate search for anything related, too. It might simply not have been fixed "enough" yet, which is a possibility.
Yeah. We debugged it in the context of parries, which is one player hitting and one reversing. It's possible it has some other nuances if it's two players both attacking and blocking like a clash.

Quote
Thank you, but er, sorry, which method? Do you mean for hitpause?
Yeah. Just one alternative to your superpause, which freezes everything on screen.

Quote
And upon testing it in mugen 1.0 ... that seemingly confirms this is a new bug in ikemen. I guess I'll head over to the github next.

Should I go ahead and mark this as "solved" (well, considering the blocking issue is unrelated to my actual efforts), or are there other workarounds or suggestions I should know?
I guess it's solved as far as the purpose of this board goes, yeah. Cool that you could find a new bug.

Also about your comments:
Quote
#naming the helper this lets it set off the "parrying" system message in ikemen go; i dunno if that's good or just confusing clutter
Is no longer true. Currently any ReversalDef that doesn't put the opponent in a custom state (like Geese's counters) triggers a parry message.

Quote
NotHitBy{value: SCA;} #is this invincible enough?
Should also have time: -1. And ignorehitpause just to be sure.
And possibly other things depending on what the helper does, but here it ought to be enough.

Quote
value=root,anim ; animation mimicking, somewhat imperfect especially when hitstun happens
You should also copy the root's animelem. And for helpers that copy a player's animations, I like to freeze their own animation so it doesn't progress on its own (AnimFreeze).

Quote
if root,movetype = A #if it were up to me i'd have it go off on every hitdef, but sadly..
You can create a function that is just a ReversalDef with RedirectID = [Clash helper ID] then call it when you call a Hitdef. One of many ways to do it I guess.
Or you can turn the Reversaldef on when the root has some HitdefAttr, and off when they don't. This might be better.
You can help with Ikemen GO's development by trying out the latest development build and reporting any bugs on GitHub.
My Mugen and Ikemen content can also be found here.
Last Edit: March 28, 2023, 05:56:13 pm by PotS
Re: Trouble with generic attack clashing [unsure if an Ikemen GO problem]
#6  March 28, 2023, 08:15:17 pm
  • everything-hobbyist girl
  • she/her
Thank you so much for your help!
I suppose I still have some more questions not related to the main problem, so I'll keep the thread just a bit more.

Is no longer true. Currently any ReversalDef that doesn't put the opponent in a custom state (like Geese's counters) triggers a parry message.
Curious, that's not what I thought I read in action.zss ... Ah, a lot of code has been refactored in the repository in the past few weeks, so I guess that change isn't in the newest RC yet.

You should also copy the root's animelem. And for helpers that copy a player's animations, I like to freeze their own animation so it doesn't progress on its own (AnimFreeze).
Ohh I definitely glossed over everything that went into an animElem, so I ignored that parameter in ChangeAnim. Now that I know what to look for I understand...
Code:
# animation mimicking
assertspecial{flag: animfreeze;}
ignoreHitPause{ changeanim {
value: root,anim;
elem: root,animElemNo(0);
} }
This works MUCH better.
There's still some inaccuracies when that player gets hit, and when characters move each other (the clone helper isn't affected by pushing, knockback, etc, so its position can end up mispredicting where you end up or seeming 1 frame behind), but it's probably good enough for attacks.

You can create a function that is just a ReversalDef with RedirectID = [Clash helper ID] then call it when you call a Hitdef.
Definitely, but again, this is meant to be a generic system with minimal-to-no modification to existing characters.

Or you can turn the Reversaldef on when the root has some HitdefAttr, and off when they don't. This might be better.
Huh! I definitely missed that trigger as well. Unfortunately it doesn't tell me whether that hitdef is new or not, so it makes the reversaldef replenish itself indefinitely. (For example, you can repel multiple attacks with a single really slow attack. I could see that being valid, but I haven't decided if it's behavior I want.)
Maybe I can work around it with MoveReverse and MoveContact? Hmm no, seems those only reset per state, not per hitdef.