RoA Workshop Guide – GML – Making Parries Function

Parries are an integral part of Rivals of Aether’s game mechanics, and this is no different for workshop characters. However, each character also has their own quirks for how parries are handled, and the Rivals engine does not handle every parry situation flawlessly. Some parry behavior has to be coded manually in order for a character to function as intended. In this guide I’ll be going over which parry situations you’ll need to be aware of, and provide simple code examples to fix the most common problems.

Projectiles

Projectile parries are the main case that most modders will have to check for. When a projectile is parried, Rivals’s engine will automatically flip its direction and make it able to hit its sender – but it doesn’t automatically increase the lifetime or the speed of the projectile. 

Due to this, a workshop-character projectile may get reflected by a parry, but then disappear before it reaches the player that originally threw it. In order to fix this, we need to manually reset the projectile’s ‘hitbox_timer‘ variable to 0 when it gets parried.

When handling most parry situations, we use the script ‘got_parried.gml‘. You may need to create it in your character files if it doesn’t exist already. The code in ‘got_parried.gml‘ is performed each time an opponent parries one of your character’s hitboxes, melee or projectile. From here, we can get information about the hitbox that was parried, and use that to change its properties accordingly.

This code example will make a Forward-Special projectile speed up and travel its full distance when parried, similar to Zetterburn’s Forward-Special.

//got_parried.gml
//in got_parried.gml, 'my_hitboxID' references the hitbox that got parried.
//check if this hitbox is for a Forward-Special attack, and is a projectile (type == 2).
if (my_hitboxID.attack == AT_FSPECIAL && my_hitboxID.type == 2) {

    //reset the projectile's lifetime.
    my_hitboxID.hitbox_timer = 0

    //speed up the projectile by 50%, or some other number. 
    //This is optional, but common for projectiles like Zetterburn's.
    my_hitboxID.hsp *= 1.5;
    my_hitboxID.vsp *= 1.5;

    //remember that a faster projectile will also travel further over the same length of time. 

    //To increase the projectile's speed but still make it travel the same distance, you can shorten its total lifetime like so:

    my_hitboxID.length /= 1.5;
}

Parries and Move Cancels

If your attacks or special moves are cancellable, it is important to double-check that players can’t cancel out of them after being parried. Otherwise, your character will be able to bypass being stunned, which is typically something you don’t want.

Take this attack_update.gml script for example. Here, the player will be able to jump-cancel their Down-Special during window #3.

//attack_update.gml
if (attack == AT_DSPECIAL && window == 3) {
    can_jump = true;
}

If we add a check for the variable ‘was_parried‘, we can make it so that the player can only jump-cancel the attack if they did not get parried.

//attack_update.gml
if (attack == AT_DSPECIAL && window == 3 && was_parried == false) { 
    can_jump = true;
}

was_parried‘ will only equal ‘true‘ if a melee hitbox gets parried. Therefore you can’t use this variable to check when a projectile is parried.

Extended Parry Stun

Sometimes you may want to have a projectile stun the opponent for a length of time, instead of reflecting. Rivals has a built-in mechanic called ‘Extended Parry Stun’ for this purpose: it applies a variable amount of parry stun, depending on how far away the opponent is when they parried it. It is used in cases such as Absa’s Forward-Special and Etalus’s Forward-Special.

The main function of this doesn’t require any extra code outside of your attack grid index script. Just set the attack’s HG_PROJECTILE_PARRY_STUN to 1, and HG_EXTENDED_PARRY_STUN to 1.

//attacks/fspecial.gml
set_hitbox_value(AT_FSPECIAL, 1, HG_PROJECTILE_PARRY_STUN , 1);
set_hitbox_value(AT_FSPECIAL, 1, HG_EXTENDED_PARRY_STUN , 1);

If you’re putting extended parry stun on a projectile, you may also want to have the projectile be destroyed when it is parried, instead of having it reflect. You can do this by setting the hitbox’s ‘destroyed‘ variable to ‘true‘ (or 1).

//got_parried.gml
if (my_hitboxID.attack == AT_FSPECIAL && my_hitboxID.type == 2) {
    //destroy the projectile.
    my_hitboxID.destroyed = true;
}

(Note that the ‘destroyed’ variable will only work for projectiles. Normally you wouldn’t need to destroy a melee hitbox, but in the rare chance that you do, you could try the function destroy_hitboxes().) 

Removing Parry Stun on Single-Hit Jabs

In Rivals of Aether, Jab attacks are the only attacks that negate being stunned when an opponent parries them. If you continue to the end of your jab combo or cancel it into a tilt, you will still be put in parry stun afterwards.

The exception to the rule is for jabs that are a single attack and not a combo (e.g. Clairen, Elliana, Shovel Knight). Single-hit jabs should not have parry stun, but the Rivals engine does not account for this by default. This means that you’ll need to remove the parry stun manually. The simplest way to do this is to force ‘was_parried‘ to equal ‘false‘ (or 0) in the ‘attack_update.gml‘ script. 

//attack_update.gml
if (attack == AT_JAB) {
    //prevent this attack from having parry stun.
    was_parried = false;
}

This will work for any other attack too, for example, if you wanted to make an attack similar to Clairen’s Neutral Special which also ignores parry stun.

Sanitizing got_parried.gml Scripts

Lastly, I consider it good practice to make sure your got_parried.gml and hit_player.gml scripts can’t interfere with other characters’ hitboxes in any way, including projectiles that have been parried twice or more. To do this, we include a line at the top of the script, which will stop the script running any further if the hitbox’s ‘player’ and ‘orig_player’ do not match. With this in place, the scripts will only trigger for projectiles that your player originally spawned, and not for projectiles that your character parried first.

//got_parried.gml 
//ignore everything if the attack parried was a reflected attack.

if (my_hitboxID.player != my_hitboxID.orig_player) exit;

//the rest of the got_parried.gml script goes under here.

Footnote: Kragg NSpecial Rock Shards

If your character has a projectile for their Neutral Special attack, here is one more engine quirk that you’ll need to be aware of. When a workshop character attacks Kragg’s rock, the rock shards made by it will trigger all of that character’s hitbox scripts – including ‘got_parried.gml‘, ‘hitbox_update.gml‘ and ‘hit_player.gml‘. This even overrides the sanitization described above, since the Kragg shards count the workshop character as being the original player. Therefore, you’ll need to account for this when changing the hit and parry properties of your Neutral-Special projectiles.

As Kragg’s rock shards have a ‘hit_priority‘ of 1, I get around this by setting my Neutral-Special projectiles’ HG_PRIORITY to anything other than 1, then checking for the ‘hit_priority‘ variable inside any hitbox scripts. An example for got_parried.gml might look like this.

//got_parried.gml
//check for NSpecial projectiles, but ignore Kragg rock shards. Reset the projectile lifetime on parry.

if (my_hitboxID.attack == AT_FSPECIAL && my_hitboxID.type == 2 && my_hitboxID.hit_priority != 1) {
    //reset the projectile's lifetime.
    my_hitboxID.hitbox_timer = 0;
}

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *