Skip to content

Variant Abilities

LtxPgm edited this page Dec 3, 2024 · 2 revisions

Overview

Transfurred players and latexes have access to unique abilities that they can use in-game in a variety of ways. In the definition of a TransfurVariant<?>, you can specify which abilities a player will have as that variant. When a TransfurVariant<?> is instanced, the abilities are too. Where an ability has a AbstractAbility<?> definition type, and a AbstractAbilityInstance instance type. This allows abilities to save and load it's own data as needed.

Ability Properties

There's a plethora of properties that are already programmed in to be used, such as how the player uses the ability, cooldowns, network payloads, etc.

Usage type

UseType describes how an ability should behave upon a keypress.

  • INSTANT - The ability immediately activates, deactivates, and applies its cooldown. Doesn't activate until cooled down, and the key has been released.
  • CHARGE_TIME - The ability needs to charge with the key down, until getChargeTime() ticks have passed. After that time, it will immediately activate, deactivate, and apply the cooldown.
  • CHARGE_RELEASE - The ability will tickCharge() when the key is down. When the key releases, the ability activates, deactivates, and applies its cooldown.
  • HOLD - The ability immediately activates on key press, tick()s the ability each tick the key is down. Deactivates and applies cooldown upon release.
  • MENU - Special type that indicates the ability will be startUsing() when selected in the ability menu. Will tick() until menu returns back to inventory (default menu)

AbstractAbility vs AbstractAbilityInstance

Depending on how your ability functions, you either need to implement AbstractAbilityInstance or you can just extend SimpleAbility. Like TransfurVariant<?>, AbstractAbility<?> are not instantiated for each player. So implementations of AbstractAbility<?> CANNOT keep user specific variables, and should be treated as final.

SimpleAbility

Ideal for abilities that don't need to keep their own variables, such as an ability that creates an item, or changes a property in TransfurVariantInstance.

public class MyAbility extends SimpleAbility {
    public void startUsing(IAbstractChangedEntity entity) {
        entity.displayClientMessage(new TextComponent("Hello World!"), true);
    }
}

When activated, this ability will display "Hello World!" on the player's screen. One instance of MyAbility will be created, in the ability registry.

AbstractAbilityInstance

Used in any scenario not covered by SimpleAbility, and has some functions that need to be defined.

public class MyAbility extends AbstractAbility<MyAbilityInstance> {
    public MyAbility() {
        super(MyAbilityInstance::new);
    }
}

public class MyAbilityInstance extends AbstractAbilityInstance {
    public ItemStack myExtraItem = ItemStack.EMPTY;

    public MyAbilityInstance(AbstractAbility<?> ability, IAbstractChangedEntity entity) {
        super(ability, entity);
    }

    ...

    public void onRemove() {
        super.onRemove();
        this.entity.addItem(myExtraItem);
    }

    public void saveData(CompoundTag tag) {
        super.saveData(tag);
        tag.put("myExtraItem", myExtraItem.serializeNBT());
    }

    public void readData(CompoundTag tag) {
        super.readData(tag);

        if (tag.contains("myExtraItem"))
            myExtraItem = ItemStack.of(tag.getCompound("myExtraItem"));
    }
}

The player will now have an instance of MyAbilityInstance that saves with them. This example ability has an additional item slot, saves it, loads it, and returns it to the player when the ability is removed for any reason (untransfurred, died).

Registration

Abilities are registered objects, akin to variants. They should be added to the ChangedRegistry.ABILITY ("changed:ability") registry.

Checking for Abilities

AbstractAbility has two static functions to help get entity abilities (player/latex).

// Returns the player's summon sharks ability instance if present, or else null
AbstractAbility.getAbilityInstance(player, ChangedAbilities.SUMMON_SHARKS);

// Returns an optional wrapping the player's slither ability instance, or else empty
AbstractAbility.getAbilityInstanceSafe(player, ChangedAbilities.SLITHER);