YesNoOk
avatar

Workaround for missing "ParentExist" trigger (Read 972 times)

Started by Ricepigeon, March 23, 2018, 09:28:35 pm
Share this topic:
Workaround for missing "ParentExist" trigger
#1  March 23, 2018, 09:28:35 pm
  • *****
  • Gaps? Where we're going, we don't need gaps...
    • USA
    • ricepigeon.neocities.org
This was something I came up with a few years ago when working on Alice back in 2013, and realized I never posted the tutorial here, so here goes nothing. Note that the addition of recursive DestroySelf controllers in MUGEN 1.1 makes this method obsolete, so this guide is primary directed at characters made for 1.0, where such a thing is not possible.

Have you ever had a situation where you needed to create a complex projectile or effect that utilized a single helper creating multiple helpers that were bound to it, only to encounter a glitch where, in the event that the parent helper was destroyed, the child helpers would just sorta stay on screen and Mugen's debug is spitting out complaints that all your child helper's bindtoparent controllers have no parent to bind to. You rush to alter your child helper's Destroyself controller, only to realize that there is no "ParentExist" trigger you can use to force them to destroy themselves. Sounds like all hope is lost right? Fortunately there is a clever workaround using trigger redirection.

For each parent helper, you'll need to reserve one variable for a unique ID, while each child helper will require two variables; one to keep track of the parent's unique ID, and one to keep track of the parent helper's playerID, which is created by the engine each time a helper is created and are periodically recycled as helpers are destroyed and new helpers created to take their place.

In the first state of parent helper, at the following line of code to the beginning of its state:

Code:
[State 20000, Parent ID]
type = varset
trigger1 = time = 0
var(0) = random*1000+random

This will generate a unique, 8-digit ID when the parent helper is created. You only have to set this once each time the helper is created, even if the helper goes through multiple states. Note that there is a very small chance (approx 0.0001%) that the same ID will be created twice, but the chance is so miniscule that this will rarely, if ever, happen. That's all for the parent helper.

The child helper is where things start to get a bit complicated, so I'll go through each part here. In the first state the child helper is created in, add the following to the beginning of the state:

Code:
[State 20010, Parent Destruct Safeguard]
type = varset
trigger1 = time = 0
var(1) = parent,id ;Set to parent's PlayerID
[State 20010, Parent Destruct Safeguard]
type = varset
trigger1 = time = 0
trigger1 = playeridexist(var(1))
var(0) = playerid(var(1)),var(0)

What you are basically doing is copying the values of both the parent helper's playerID (which is set by the engine) and the 8-digit ID that you generated earlier, into the child helper. The reason for copying both of these values into the child helper is to check for two possible scenarios:

Scenario 1: Parent no longer exists, Helper with Parent's Player ID doesn't exist
Scenario 2: Helper with Parent's Player ID exists, but unique ID don't match

Scenario 1 is pretty straightforward; if a helper with the parent helper's PlayerID doesn't exist, then that means that the parent helper doesn't exist and you can safely destroy the child helper.

Scenario 2 is a bit more complicated to understand, and requires a bit of understanding of how the MUGEN engine assigns PlayerIDs. As stated before, PlayerIDs are recycled by the engine each time a helper is destroyed; MUGEN will typically use the first available free PlayerID in these cases. In other words, you may run into situations where a helper with the parent's PlayerID exists, but the helper with that ID was actually created after the actual parent helper destroyed itself! It is for this reason that we needed that unique 8-digit ID number, as PlayerID alone is not enough to check if the parent helper no longer exists.

To satisfy both of these scenarios when checking to see if a child helper's parent exists, your triggers should typically look something like this:

Code:
trigger1 = !playeridexist(var(1))
trigger2 = playeridexist(var(1))
trigger2 = playerid(var(1)),var(0) != var(0)

Trigger1 will satisfy the first scenario; because there is no helper that exists with the parent helper's PlayerID, we can safely say that the parent was destroyed.
Both Trigger2s satisfy the second scenario; a helper exists with the same PlayerID as our child helper's parent, but their unique 8-digit ID number does not match what we initially recorded, indicating that the original parent helper was destroyed.

If you want to prevent any unusual debug errors, you should also add the following triggers to all State Controllers utilizing a parent that isn't the root (ie ParentVarSet, BindToParent, etc.):

Code:
triggerall = playeridexist(var(1))
triggerall = playerid(var(1)),var(0) = var(0)

These triggers will check for the same consistency as the ones we defined above. If everything checks out, then the state controllers will execute without any problems. Otherwise, the controllers will not execute and prevent unnecessary debug flood.