YesNoOk
avatar

Ginyu's Body Change, or an essay on how to switch character controls in Mugen (Read 83966 times)

Started by XGargoyle, 10 years ago
Share this topic:
Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#1  10 years ago
  • ******
  • Hedgehog Whisperer
  • Red Bull addict
    • Spain
    • xgargoyle.mgbr.net
This will be a long read, you've been warned ;)

You’ve seen it in Dragon Ball: Captain Ginyu swaps his body for Goku’s one, but things don’t turn quite as expected, resulting in the characters unable to reach full potential on the new hosts. If you don’t know what I’m talking about, here’s a short clip of the Body Change’s side effects
https://www.youtube.com/watch?feature=player_detailpage&v=MRZziD6WxoE#t=74

How can we replicate this effect in Mugen? The engine doesn’t allow switching control directly, but there are workarounds to achieve a similar effect.

I’m going to propose one of them, which I’d like to discuss with you guys on how to improve it or even find a better method.

The current implementations from other authors either rely on heavy customization of Ginyu and the other enemies (such as including other character’s sprites within the SFF) or requiring lots of code that need to be updated with every character “compatible” with Ginyu. Also, some of the current implementations are really cheap such as characters exchanging life values or similar tricks, unbalancing whatever balance had the original characters.

My goal was to create a code that didn’t have the abusive behavior of the previous implementations, was balanced enough to bring an added value to the fight strategy, and required the least modification for the other characters to make it compatible with Ginyu.

So, this is the result:


This is what you need to make it work:
Ginyu needs to place the enemy on a custom state. In the concept video I’m using a projectile, but it really doesn’t matter if you use a hitdef, a projectile or a helper to place the enemy into a custom state.

The custom state in which the enemy is placed is:
Code:
  1. [Statedef XXXX]
  2. type = U
  3. movetype = I
  4. physics = U
  5. ctrl = 0
  6. velset = 0,0
  7. poweradd = 0
  8. [State Enemy Helper on Player]
  9. type = Helper
  10. trigger1 = !time
  11. helpertype = normal ;player
  12. name = "P2onP1"
  13. ID = 9123
  14. stateno = 9123
  15. pos = 0,0
  16. postype = p2   
  17. facing = 1
  18. keyctrl = 0
  19. ownpal = 0
  20. supermovetime = 0
  21. pausemovetime = 0
  22.  
  23.  
  24. [State ChangeState]
  25. type = SelfState
  26. trigger1 =  !time
  27. value = 0
  28. ctrl = 1

This code will make P2 create a Helper that will be placed on top of Ginyu (P1). The State for the Enemy’s Helper needs to be located on the Enemy’s files.
Ginyu also needs the following state, which will be the “P1onP2” Helper:
Code:
  1. ;GINYU
  2. [Statedef 9124]
  3. type    = U                      ;State-type: S-stand, C-crouch, A-air, L-liedown
  4. movetype= U                      ;Move-type: A-attack, I-idle, H-gethit
  5. physics = U                      ;Physics: S-stand, C-crouch, A-air
  6. juggle  = 0                      ;Number of air juggle points move takes
  7. ;Commonly-used controllers:
  8. velset = 0,0                     ;Set velocity (x,y) (Def: no change)
  9. ctrl = 0                         ;Set ctrl (Def: no change)                     ;Change animation (Def: no change)
  10. sprpriority = 10                 
  11.  
  12. [State 9124, NotHitBy]
  13. type = NotHitBy
  14. trigger1 = 1
  15. value = SCA,NA,SA,HA,NP,SP,HP,NT,ST,HT
  16. time = 1
  17. ignorehitpause = 1
  18. ;persistent =
  19.  
  20. [State 9124, Pos] ;bind the helper to a fixed position
  21. type = PosSet
  22. trigger1 = 1
  23. x = (enemy, pos x)
  24. y = enemy, pos y
  25. ignorehitpause = 1
  26.  
  27. [State 9124, turn] ;the helper will face the enemy
  28. type = Turn
  29. trigger1 = pos Y = 0
  30. trigger1 = facing = root,facing
  31. ignorehitpause = 1
  32.  
  33. [State 9124, 2] ;this will allow the helper to replicate the same animation than the root
  34. type = ChangeAnim
  35. trigger1 = Anim != (enemy, anim)
  36. trigger2 = AnimElemNo(0) > (enemy, AnimElemNo(0))
  37. value = enemy, anim
  38. elem = enemy,AnimElemNo(0)
  39. ignorehitpause = 1
  40.  
  41. [State 9124, DestroySelf]
  42. type = DestroySelf
  43. trigger1 = root,var(51)=0 ;time = 500
  44. ignorehitpause = 1
  45. ;persistent =

This code basically places a Helper on top of the Enemy (P2) and it replicates the same animation number as the Enemy.
Ginyu also needs the following -2 states:

Code:
  1. [State -2, Ginyu Mode ON]
  2. type = VarSet
  3. trigger1 =1
  4. var(51)= IfElse((enemy,Numhelper(9123)=1),1,0)
  5.  
  6.  [State -2, Ginyu missing animation check]
  7. type = VarSet
  8. triggerall = Teamside = 1
  9. triggerall = NumHelper(9124)=1
  10. trigger1 = (helper(9124),AnimElemNo(0)) = (enemy, AnimElemNo(0))
  11. var(53) = Ifelse((helper(9124),anim)!=(enemy,anim),0,1)
  12.  
  13. [State -2, Ginyu missing animation check]
  14. type = VarSet
  15. triggerall = Teamside = 2
  16. triggerall = NumHelper(9124)=1
  17. trigger1 = (helper(9124),AnimElemNo(0)) = (enemy, AnimElemNo(0)+1)
  18. var(53) = Ifelse((helper(9124),anim)!=(enemy,anim),0,1)
  19.  
  20. [State -2, AssertSpecial]
  21. type = AssertSpecial
  22. trigger1 = var(51)=1
  23. flag = invisible
  24. ignorehitpause = 1
  25.  
  26. [state -3, remove afterimage]
  27. type = afterimagetime
  28. trigger1 = var(51)=1
  29. time = 0
  30.  
  31. [State -2, Ginyu Helper on Enemy]
  32. type = Helper
  33. trigger1 = !NumHelper(9124)
  34. trigger1 = var(51)=1
  35. helpertype = normal ;player
  36. name = "P1onP2"
  37. ID =  9124
  38. stateno = 9124
  39. pos = 0,0
  40. postype = p2    ;p2,front,back,left,right
  41. facing = 1
  42. keyctrl = 0
  43. ownpal = 0
  44. supermovetime = 0
  45. pausemovetime = 0

var(51) basically tells the game that the Body Swap has been enabled. Var(53) keeps track of the animation of the enemy versus the helper’s animation. Due that P2 code is executed with 1 tick after P1 code, we need to do a workaround to keep that 1 tick delay, otherwise the code will not work when performed by P2.

Now, let’s see the code that needs to be added to the enemy’s files to make it compatible with Ginyu:
Code:
  1. ;GINYUs Helper
  2. [Statedef 9123]
  3. type    = U                      ;State-type: S-stand, C-crouch, A-air, L-liedown
  4. movetype= U                       ;Move-type: A-attack, I-idle, H-gethit
  5. physics = U                      ;Physics: S-stand, C-crouch, A-air
  6. juggle  = 0                      ;Number of air juggle points move takes
  7. ;Commonly-used controllers:
  8. velset = 0,0                     ;Set velocity (x,y) (Def: no change)
  9. ctrl = 0                          ;Set ctrl (Def: no change)
  10. sprpriority = 10                 
  11.  
  12. [State 9123, NotHitBy]
  13. type = NotHitBy
  14. trigger1 = 1
  15. value = SCA,NA,SA,HA,NP,SP,HP,NT,ST,HT
  16.  
  17. time = 1
  18. ignorehitpause = 1
  19.  
  20. [State 9123, Pos] ;bind the helper to a fixed position
  21. type = PosSet
  22. trigger1 = 1
  23. x = (enemy, pos x)
  24. y = enemy, pos y
  25. ignorehitpause = 1
  26.  
  27. [State 9123, turn] ;the helper will face the enemy
  28. type = Turn
  29. trigger1 = pos Y = 0
  30. trigger1 = facing = root,facing
  31. ignorehitpause = 1
  32.  
  33. [State 9123, 2] ;this will allow the helper to replicate the same animation than the root
  34. type = ChangeAnim
  35. trigger1 = anim != (enemy, anim)
  36. trigger2 = AnimElemNo(0) > (enemy, AnimElemNo(0))
  37. value = enemy, anim
  38. elem = enemy,AnimElemNo(0)
  39. ignorehitpause = 1
  40.  
  41. [State 0, DestroySelf]
  42. type = DestroySelf
  43. trigger1 = time = 500 ;its a good idea to kill the helper after some time, but we can find other ways to kill it. This is up to the author
  44. ignorehitpause = 1

The enemy also needs to include this code in their -2/-3 states:
Code:
  1. [State -3, AssertSpecial]
  2. type = AssertSpecial
  3. triggerall = enemy,Name=" Ginyu "
  4. trigger1 = enemy,var(51)=1 ;Ginyu Mode ON
  5. flag = invisible
  6. ignorehitpause = 1
  7.  
  8. [state -3, remove afterimage]
  9. type = afterimagetime
  10. triggerall = enemy,Name=" Ginyu "
  11. trigger1 = enemy,var(51)=1 ;Ginyu Mode ON
  12. time = 0
  13. ignorehitpause = 1
  14.  
  15.  
  16. [State -3, Prevent playing missing anim] ;HACK
  17. type = ChangeAnim
  18. triggerall = enemy,Name=" Ginyu "
  19. triggerall = enemy,var(51)=1 ;Ginyu Mode ON
  20. trigger1 = stateno = 0
  21. trigger1 = !time
  22. trigger2 = enemy,var(53)=0
  23. value = 0
  24. ;elem = 1
  25. ignorehitpause = 1
  26.  
  27.  
  28. [State -3, Prevent Wrong State S]
  29. type = ChangeState
  30. triggerall = enemy,Name=" Ginyu "
  31. triggerall = enemy,var(51)=1 ;Ginyu Mode ON
  32. triggerall = statetype=S
  33. trigger1 = enemy,var(53)=0
  34. value = 0
  35. ctrl = 1
  36. ignorehitpause = 1
  37.  
  38. [State -3, Prevent Wrong State C]
  39. type = ChangeState
  40. triggerall = enemy,Name=" Ginyu "
  41. triggerall = enemy,var(51)=1 ;Ginyu Mode ON
  42. triggerall =  statetype=C
  43. trigger1 = enemy,var(53)=0
  44. value = 11
  45. ctrl = 1
  46. ignorehitpause = 1
  47.  
  48. [State -3, Prevent Wrong State A]
  49. type = ChangeState
  50. triggerall = enemy,Name="Ginyu"
  51. triggerall = enemy,var(51)=1 ;Ginyu Mode ON
  52. triggerall = statetype=A
  53. trigger1 = enemy,var(53)=0
  54. value = 50
  55. ctrl = 1
  56. ignorehitpause = 1

I’m using a enemy,name trigger to check the identity of Ginyu and then execute the necessary code. Other alternatives to this would be through a helper or anim check, but as this is a concept move, I’ll leave the possible methods of “standardization” open to discussion.

The full code results in a helper on top of an invisible character repeating the same animation as the invisible character. That means if P1 plays animation 200, the Helper will play the same animation 200 using his own sprites (actually the other player’s ones). If the character plays an animation not available or if the animation from the character is longer or shorter than the one from the Helper, then it will revert to an idle state. This replicates the original concept of the move in which the characters weren’t able to reach the full potential of the new bodies. It also brings a new strategy layer as both characters are nerfed down having most of his attacks disabled for the duration of the move.

The full code is also to implement in other characters as it can be placed at the end of statedef -2 or -3, requiring one single copy&paste process to make it compatible. There are no sprites to be added or modified, making it easier the compatibility with other characters Ginyu also doesn’t need to update his code every time a new character is added to the compatibility list.

The code isn’t exempt of problems though. First of all, whenever a character tries to play a missing animation, there will be a debug warning. Also, the characters could get stuck for some ticks while performing some moves. Another known issue is that the actual animation and clsn boxes are the ones from the invisible character. This means that if animation 200 for the character is a high punch, but the enemy’s animation 200 is from a low kick, the hitsparks and the movehit behavior will not reflect on the animation being displayed. Effects such as Explods around a particular animation will still be played on the Helper (which in some cases will not match with what's shown on screen)

Also, in the same fashion, the Helper could turn into a fireball if the animation numbers from one character match the Helper’s ones. A full game implementation using my “helper on top of character” would easily prevent such problems by restricting the attacks that could be performed during the Body Change being enabled -remember Ginyu’s var(51)- as well as limiting the explods that should be displayed during Ginyu’s Body Change mode. Obviously this will require more customization on the enemy’s files, but for full game authors, my method could be a viable option to implement a true Body Change attack.

Let me know your thoughts or comments on this :)
XGargoyle: Battle posing since 1979
http://xgargoyle.mgbr.net
http://www.pandorabots.com/pandora/talk?botid=e71c0d43fe35093a  <-- Please click that link
http://paypal.me/XGargoyle  <-- Donations welcome!
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#2  10 years ago
  • *****
  • Smooches
    • USA
    • Skype - Neocide
oh I love you <3 I've been trying to figure something out with this for my ginyu since I made his sheet.


I'll have to test this out later on.
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#3  10 years ago
  • ***
  • #1 Boss Lady
    • UK
Brilliant. I do wonder if it would ever be possible to switch health values as well, now that'd be interesting.
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#4  10 years ago
  • ******
  • Hedgehog Whisperer
  • Red Bull addict
    • Spain
    • xgargoyle.mgbr.net
As long as the enemy is a target or in a custom state, you can modify his life without problems
XGargoyle: Battle posing since 1979
http://xgargoyle.mgbr.net
http://www.pandorabots.com/pandora/talk?botid=e71c0d43fe35093a  <-- Please click that link
http://paypal.me/XGargoyle  <-- Donations welcome!
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#5  10 years ago
  • ******
  • Video Game Veteran
  • Can you do it? SUREYOUCAN!
    • USA
    • gcnmario.free.fr
There was a SFA custom Dhalsim, which had a similar effect. But instead of switching bodies, it turned the other character into another Dhalsim.
Also, like how SvC Zero's metool helper transforms an enemy into a Metool upon contact.

It's basically just transformation frames from one end, to another.  But I see what you did there. ;)

"You must defeat my flaming
dragon punch to stand a chance."
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#6  10 years ago
  • ***
  • Non est hoc propter hoc sed propter est hoc
    • USA
    • doubletrend-zeta.neocities.org/
Is there really no way to manually force the opponent back to idle without any debug error message?

The way I'm reading the ChangeAnim code, if the animation isn't the enemy's normal one or the animelemno of the specified animation (200 or whatever it may be), is greater than the enemy's normal one, then it uses the animation of the enemy? (wow this is a lot more confusing to try to convey in words than I originally thought it would be, am I right in my understanding of it?)
Spoiler: code snippet for reference (click to see content)

Couldn't you have a separate ChangeAnim sctrl that takes precedence if said animation doesn't exist by forcing specific basic animation numbers to be used? I would think that if we could specify, say, 200-999 as a block of animations to pull from, then we can limit the helper to those animations and then if they try to use any other animation it would force them back to idle, hopefully without any debug error.
However, I don't have the greatest knowledge of the nuances of the CNS, so I'm having trouble figuring out what trigger you would even use for that, or even if it's possible at all, seeing how Enemy, Anim would require them to already be in that animation, and Enemy, AnimExist only takes into account whether the animation exists within the AIR.
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#7  10 years ago
  • ******
  • Hedgehog Whisperer
  • Red Bull addict
    • Spain
    • xgargoyle.mgbr.net
The code snippet you refer basically forces the Helper to have the same animation timings (ticks) than the other player. This prevents the case of a helper having an animation shorter than the enemy. Without that code, the Helper would loop the animation over and over as long as the enemy was still doing his animation.

However, I took notice of your suggestion of checking if the animation actually exists on the enemy and came up with the following code improvement.

On Ginyu's statedef -2/-3, add this:
Quote
[State -2, Ginew AnimExist]
type = VarSet
trigger1 = NumHelper(9124)=1
var(52)= IfElse((enemy,AnimExist(Anim)!=Helper(9124),AnimExist(enemy,Anim)),0,1)

and on the enemy's cns, add these states (in bold the modifications versus the original code:
Quote
[State -3, Prevent Wrong State S]
type = ChangeState
triggerall = enemy,Name="Ginyu"
triggerall = enemy,var(51)=1
triggerall = statetype=S
trigger1 = enemy,var(53)=0
trigger2 = enemy,var(52)=0
value = 0
ctrl = 1
ignorehitpause = 1

[State -3, Prevent Wrong State C]
type = ChangeState
triggerall = enemy,Name="Ginyu"
triggerall = enemy,var(51)=1
triggerall =  statetype=C
trigger1 = enemy,var(53)=0
trigger2 = enemy,var(52)=0
value = 11
ctrl = 1
ignorehitpause = 1

[State -3, Prevent Wrong State A]
type = ChangeState
triggerall = enemy,Name="Ginyu"
triggerall = enemy,var(51)=1
triggerall = statetype=A
trigger1 = enemy,var(53)=0
trigger2 = enemy,var(52)=0
value = 50
ctrl = 1
ignorehitpause = 1

This addition will not prevent the debug flood of a missing animation, but it will prevent the enemy from entering a state in which the helper has no animation to play. This will prevent for example when a 4-button helper is replicating a 6-button character. With the new code, it will disable the buttons for these extra attacks.

This code revision has been a fast addition, so I'll be testing it in the following days. In any case, tanks for the feedback. I really appreciate it ;)
XGargoyle: Battle posing since 1979
http://xgargoyle.mgbr.net
http://www.pandorabots.com/pandora/talk?botid=e71c0d43fe35093a  <-- Please click that link
http://paypal.me/XGargoyle  <-- Donations welcome!
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#8  10 years ago
  • ******
  • Limited time to use Infinite power !
    • France
    • network.mugenguild.com/cybaster/
This is some very interesting piece of code right there. :)
I really like how you kept it simple to maintain while implementing the "not full potential" stuff !

PS : I'll do this readme update today, as I promised long time ago !!! :ninja:
Re: Ginyu's Body Change, or an essay on how to switch character controls in Mugen
#9  5 years ago
  • avatar
  • ****
  • Karate ni senshi nashi
    • Brazil
    • www.youtube.com/user/karate867
Sorry for the bump but its possíble use this code to make twoelve’s x-copy?