RoA Workshop Guide – Coding Recovery Moves Pt. 2: Adding Extra Functionality with GML

Although Grid Indexes are flexible, there are some aspects critical to recovery moves that can’t be done with Grid Indexes alone. In this guide we’ll cover a few essential and convenient features that can be added to your recovery moves via attack scripting.

(While this is technically a coding guide, most of the examples here should be safe to copy-paste without much coding knowledge. You may need to edit the attack variable names or the window numbers to make them work with your own character’s attacks.)

Wall-Jump Cancels

Most characters’ Up-Special attacks can be cancelled into a walljump, either during the attack or during its endlag frames. This often goes unnoticed, but it’s essential for making certain recovery moves feel faster and more responsive.

To make an attack wall-jump-cancellable, you’ll need to set the ‘can_walljump‘ variable to ‘true’ inside your ‘attack_update.gml‘ script. Normally, only the end of the attack can be cancelled; therefore you may want to add an ‘if’ statement to control which window of the attack can be cancelled. You can make your Up-Special wall-jump-cancellable with the following code:

if (attack == AT_USPECIAL) {
//allow Up-Special to be walljump-cancelled on window 3 and later.
if (window >= 3) can_walljump = true;

Blastzone Mercy

If your character’s recovery is able to move during the startup, it’s a good idea to make it such that it can’t enter the blastzone mid-recovery. This prevents cases where a player loses a stock despite knowing his or her Up-Special had been used in time.

It is more common to just halt the player’s movement during startup instead, which has the same effect. You can do this with Grid Indexes, by simply setting AG_WINDOW_VSPEED_TYPE and AG_WINDOW_HSPEED_TYPE to ‘1‘. But if your character must be able to move or fall during startup, then consider a failsafe like the example below.

if (attack == AT_USPECIAL) {
if (window == 1 && !hitpause) {
//if the player is about to fall into the bottom blastzone, prevent them from falling any further.
if (vsp > 0 && y > get_stage_data(SD_BOTTOM_BLASTZONE) - 20) vsp = 0;

Single-Use Recoveries without Pratfall

For some character designs, you may wish to design a Recovery move that does not end with pratfall, such as Etalus’s Up-Special. Usually, usually, recoveries like these are ‘utility’ only, with no rising hitbox and only one use per airtime. While I would always recommend a more typical recovery with a hitbox and pratfall (they’re easier to code, easier to balance and generally less of a headache), there is an easy way to implement Up-Special moves without pratfall should you choose to.

The in-built variable ‘bear_uspecial‘, originally intended for Etalus, exists for this purpose. ‘bear_uspecial‘ will be set to ‘true‘ whenever the character takes a hit, lands on the ground or performs a walljump. From there, we simply need to initialize it in our own character, set the variable to ‘false‘ whenever Up-Special is used, and force the move on a cooldown until ‘bear_uspecial‘ becomes ‘true‘ again.

bear_uspecial = true;
if (attack == AT_USPECIAL) {
bear_uspecial = false;
if (bear_uspecial == false) {
//While bear_uspecial equals false, set up-special's cooldown to a minimum of 2.
move_cooldown[AT_USPECIAL] = max(move_cooldown[AT_USPECIAL], 2);

Ledge Snap

Most Side-Special recovery moves – and some Up-Specials too – allow the player to ‘snap’ above the ledge if they use an attack that would barely get caught on it. Since there is no ledge-grabbing in Rivals, a mercy rule like this helps lessen the frustration from barely missing the right ledge height.

Despite how common this is in base-cast Special moves, there isn’t a built-in solution, so a custom function is provided in the example below. Note that all custom functions (using the ‘#define’ keyword) must be placed right at the bottom of your .gml file.

snapped_to_ledge = false;
if (attack == AT_FSPECIAL) {
	//startup window
	if (window == 1) { 
		snapped_to_ledge = false;
	//moving window
	//check for hitpause, so that the character doesn't ledge-snap while in hitpause.
	if (window == 2 && hitpause == false) { 
		//attempt to snap to the ledge, if the character has not yet attempted to do so.
		if (snapped_to_ledge == false) {
			snapped_to_ledge = ledge_snap();
//bottom of attack_update.gml

#define ledge_snap
//allows a moving attack to snap onto and over the ledge without getting caught, 
// similar to Maypul and Orcane's Forward-Specials.
// returns 'true' when the attack successfully snaps over a ledge
//code example by Mawral - free to use without credit.

var step = 16; //the maximum distance to move up from the ledge. must be a power of 2. '16' or '32' is recommended.
var xx = x + spr_dir; //use 'xx = x - spr_dir' if the attack moves backwards.

//check if there is a ledge ahead. if there is not, return 'false' and end the script.
var par_block = asset_get("par_block");
if (!place_meeting(xx, y, par_block) || place_meeting(xx, y - step, par_block)) return false;

//move the player onto and above the ledge.
x = xx;
y -= step;
//then, move downwards as far as possible without cutting into the stage.
for (step /= 2; step >= 1; step /= 2) {
	if (!place_meeting(x, y + step, par_block))  y += step; 
//ledge snap successful. return 'true'.
return true;






Leave a Reply

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