Rivals of Aether

Rivals of Aether

Qua Mario
Floral qua Floral  [developer] 16 Nov, 2021 @ 10:19am
Compat for Devs: Carryable Objects
There are two ways Mario can carry an object. Grab carrying is when he moves into something while holding the Run button. When Mario grabs something, he can kick it forwards or directly up. Lift carrying is when he stands beside something and presses the Spin button, while holding Run. Mario can't Lift things while he's in midair, and he's forced into a pickup animation for a few frames when he does Lift something, so it's the more committal of the two - generally, Mario can only Lift heavy objects, but can Grab or Lift lighter objects.
Much like making things freezable, first you'll need to add this to your init:
neo_data_compat = { carryable_objects: undefined };
Objects can then be made carryable in quite a similar way to how they are made freezable:
if(player_id.neo_data_compat.carryable_objects != undefined) array_push(player_id.neo_data_compat.carryable_objects, self);
And, again like the freezables list, Mario will clean out this list for you to remove the IDs of objects that have been deleted. This is why it's still important that you initialize the list as undefined and then check if Mario has changed it to an array for you.
One thing that can be useful to know: You can test basic compatibility by enabling the Carry Anything cheat in Mario's MunoPhone. Press Taunt in Practice Mode with your character loaded, select the Cheats app, and scroll down until you reach the Carry Anything cheat.

For Advanced Users
Also like the freezable object support, there are options to have greater control. Carrying is a much more complicated process than freezing - when Mario freezes something, all he needs to do is delete the original instance and create an ice block that contains its sprite. When Mario carries something, he needs to establish a connection with it and carefully manipulate it. As such, there are a lot of different options for the neo_carry_data:
if(player_id.neo_data_compat.carryable_objects != undefined) {} array_push(player_id.neo_data_compat.carryable_objects, self); neo_carry_data = { //Metadata name: "Unknown", //Readable data carried_type: 0, carried_dir: 1, carrier: 0, carrier_id: noone, was_released: 0, //Interaction limiters is_grabbable: false, is_liftable: false, no_interact_time: -100, //Compatibility tweaks half_width: undefined, half_height: undefined, xoffset: undefined, yoffset: undefined, sprite_can_flip: true, can_change_depth: true, override_mask: true, //Release behaviour force_gentle_drop: false, kick_hsp: 5, kick_up_vsp: -12, kick_sfx: undefined, throw_hsp: 5, throw_vsp: -4, //Carry effects super_heavy: false, blocks_attacks: false } };
Metadata: Just contains the name field
  • name: Used primarily for debugging purposes, doesn't affect anything in-game.
Readable data: These values are primarily here so you can code your object to check them and make it respond to getting carried, getting thrown, etc.
[/list]
  • carried_type: 0 when the object isn't being carried; 1 when the object is being held in a Grab; 2 when the object is being held in a Lift. You can manually set this to 0 to force Mario to drop the object.
  • carried_dir: Set to equal Mario's spr_dir.
  • carrier: Set to the player number of the Mario who's carrying it (i.e. an integer 1, 2, 3, or 4).
  • carrier_id: Set to the instance ID of the Mario who's carrying it.
  • was_released: 0 when the object is being carried; 1 when the object is dropped; 2 when the item is kicked; 3 when the item is kicked directly upwards; 4 when the item is thrown. This does not get reset, so you'll have to reset it yourself.
Interaction limiters: These values are for limiting how Mario can carry your object.
  • is_grabbable: If false, Mario can't Grab the object. If this gets changed to false after Mario's already Grabbed it, he won't be forced to drop it.
  • is_liftable: If false, Mario can't Lift the object. If this gets changed to false after Mario's already Lifted it, he won't be forced to drop it.
  • no_interact_time: Mario can't Grab or Lift the object until get_gameplay_time() returns a value higher than this number.
Compatibility tweaks: These values are related to making small changes to make your object work better when Mario is carrying it.
  • half_width: When not undefined, this tells Mario exactly how wide the object is rather than having him calculate it based on the sprite/mask size. Try this if Mario seems to be holding the object at an awkward position. If you set this value to something other than undefined, Mario will no longer take the object's image_xscale or spr_dir into account.
  • half_height: When not undefined, this tells Mario exactly how tall the object is rather than having him calculate it based on the sprite/mask size. Try this if Mario seems to be holding the object at an awkward position. If you set this value to something other than undefined, Mario will no longer take the object's image_yscale into account.
  • xoffset: Makes Mario hold the object in a different position. Positive values move the object forwards relative to Mario's spr_dir.
  • yoffset: Makes Mario hold the object in a different position. Positive values move the object downwards.
  • sprite_can_flip: Allows or disallows the sprite from flipping horizontally when Mario turns around while holding it. This is useful for objects that have text on them.
  • can_change_depth: Allows or disallows the object from having its depth manipulated by Mario. If true, Mario keeps the object within 1 depth layer of himself either above or below. It is only ever above him during part of his Spin Jump and Air Twirl animations while holding the object in a Grab.
  • override_mask: Allows or disallows the object from having its mask substituted out. If true, Mario will replace the object's collision mask with a one-pixel mask offset 60,000 pixels up and to the left, with the intent of preventing the object from colliding with anything while it is being held. He automatically puts the original mask back upon losing the object. If false, the object will simply keep its previous collision mask. For projectiles, this uses the collision_sprite that's used for terrain interactions, rather than the mask_index used for colliding with hurtboxes.
Release behaviour: These values affect what happens when Mario lets go of the object.
  • force_gentle_drop: When true, Mario cannot kick or throw the object and instead always drops it as if he was holding down on the control stick. This can also be set to 2 to disallow Mario from deliberately dropping the object when he's in the air, to prevent him from dropping it from heights. This feature is intended for objects that Mario probably shouldn't be kicking or throwing, such as if you wanted to add the baby penguin from Super Mario 64. It could also be useful for puzzle elements where being able to kick or throw the object somewhere Mario cannot access would be too easy. Although I don't know if anyone is actually going to be making puzzles for Qua Mario to play...??? It's worth knowing that setting force_gentle_drop to 2 can't prevent Mario from being forced to lose the object. Mario is forced to lose the object if something changes its carried_type to 0, if he moves under a ceiling that's too low for it while he has it in a Lift, or if his carry_obj is unexpectedly set to a different value (which shouldn't happen except in the most catastrophic of circumstances). He'll also, of course, exit the carrying state if the object gets instance_destroy()ed.
  • kick_hsp: The horizontal speed applied to the object when Mario kicks it forwards. This is added to half of Mario's current hsp when he kicks it, so if he's moving faster the object will be as well. If he's moving backwards, the object will be kicked at a lower speed. The object's vertical speed is always set to match Mario's vertical speed if he's moving up, or to 0 if he's moving down. If this is set to undefined, the object's horizontal speed will instead perfectly match Mario's.
  • kick_up_vsp: The vertical speed applied to the object when Mario kicks it upwards. If Mario is moving upwards, this is added to half of his current vsp as well, so if he's kicks the object while jumping it will go higher. The object's horizontal speed is always set to match Mario's hsp. If this is set to undefined, the object's vertical speed will instead perfectly match Mario's.
  • throw_hsp: The horizontal speed applied to the object when Mario throws it. This is added to half of Mario's current hsp. If the value is provided as undefined, the object's horizontal speed will instead perfectly match Mario's.
  • throw_vsp: The vertical speed applied to the object when Mario throws it. This is added to half of Mario's current vsp. If the value is provided as undefined, the object's vertical speed will instead perfectly match Mario's.
Carry Effects: Things that modify the way Mario behaves while he's holding the object.
  • super_heavy: Greatly reduces Mario's movement while held, but triples the damage dealt by Stomps. Not currently implemented.
  • blocks_attacks: If a hitbox intersects with both Mario and the object being held, Mario will completely resist the hit and the object will be destroyed.
Of course, as with the Neo Freeze Data, none of these values are required, and they will be filled in with their defaults if not given. However, some default behaviour should be explained. If you don't provide any neo_carry_data, the object will be both Grabbable and Liftable. You can also set it to the boolean value true for the same result. Setting neo_carry_data to the strings "Grab" or "Lift" will make it only carryable with that specific type of carry. If you provide neo_carry_data in the form of a struct, both is_grabbable and is_liftable will default to false if not included - so you'll have to include at least one of the two if you want your object to be actually carryable.