Skip to content

Powers (Buffs)

Alchyr edited this page Dec 16, 2024 · 9 revisions

Power is the game's general term for all buffs and debuffs that go on the player or enemies, not to be confused with Power cards, which are cards that usually apply Powers to the player.

All powers extend from the AbstractPower class. The BasePower class extends from AbstractPower and provides some additional utility to make it easier to set up.

An example of a power that increases the damage of attacks (basically Strength):

public class NotStrengthPower extends BasePower {
    public static final String POWER_ID = makeID("NotStrength");
    private static final AbstractPower.PowerType TYPE = AbstractPower.PowerType.BUFF;
    private static final boolean TURN_BASED = false;
    //The only thing TURN_BASED controls is the color of the number on the power icon.
    //Turn based powers are white, non-turn based powers are red or green depending on if their amount is positive or negative.
    //For a power to actually decrease/go away on its own they do it themselves.
    //Look at powers that do this like VulnerablePower and DoubleTapPower.

    public NotStrengthPower(AbstractCreature owner, int amount) {
        super(POWER_ID, TYPE, TURN_BASED, owner, amount);
    }

    public float atDamageGive(float damage, DamageInfo.DamageType type) {
        //If NORMAL (attack) damage, modify damage by this power's amount
        return type == DamageInfo.DamageType.NORMAL ? damage + this.amount : damage;
    }

    public void updateDescription() {
        this.description = DESCRIPTIONS[0] + amount + DESCRIPTIONS[1];
    }
}

Description

The text for powers is loaded from PowerStrings.json, and accessed using the DESCRIPTIONS array. In this example, you would put something like this

  "${modID}:NotStrength": {
    "NAME": "Not Strength",
    "DESCRIPTIONS": [
      "Attacks deal #b",
      " additional damage."
    ]
  }

into the PowerStrings.json file under localization.

    "DESCRIPTIONS": [
      "Attacks deal #b", <- This is DESCRIPTIONS[0]
      " additional damage." <- DESCRIPTIONS[1]
    ]

This results in the description made by

this.description = DESCRIPTIONS[0] + amount + DESCRIPTIONS[1]; being

Attacks deal #b? additional damage.

Numbers in power descriptions are always blue, which is what the #b is for, which colors the text it's attached to. Keywords should be capitalized and colored yellow using #y.

The base game generally does all its descriptions in parts like this, and putting them together in the description based on certain conditions.

Icon

BasePower loads its images from the modid/images/powers folder in resources. For this example power with the ID being makeID("NotStrength"), you would need an ~30x30 image at modid/images/powers/NotStrength.png, and an optional ~84x84 higher resolution version at modid/images/powers/large/NotStrength.png. The large version is used for an image flash vfx that occurs when a power is applied. If it is not provided, it will just scale up the lower resolution version, which can look quite pixelated. The sizes of these images don't have to be exact. A 32x32 image with an empty margin is around the size you want for the icon. The filled space should be around 28x28.

If you want to check the power (using AbstractDungeon.player.getPower/hasPower), use the POWER_ID field. Typing the ID yourself is prone to errors and also wouldn't be changed if you adjusted the power's ID later.

ex. if (AbstractDungeon.player.hasPower(NotStrengthPower.POWER_ID)) {

Using Powers

Regardless of whether a power is a buff or debuff, or intended to be applied to the player or an enemy, powers are always applied using an ApplyPowerAction.

The constructor of ApplyPowerAction you'll be using most often is

public ApplyPowerAction(AbstractCreature target, AbstractCreature source, AbstractPower powerToApply)

Target and source are relatively self-explanatory; if a player uses a card to buff themselves, the target and source would both be the player. If the player uses a card to debuff an enemy, the target would be the enemy and the source would be the player.

Next is the power to be applied. This will just be a new instance of whatever power you want to apply. The only thing to remember is that the power's owner must match the target of the action.

For a card that says "Gain !M! NotStrength." the code would be

    @Override
    public void use(AbstractPlayer p, AbstractMonster m) {
        addToBot(new ApplyPowerAction(p, p, new NotStrengthPower(p, magicNumber)));
    }

ApplyPowerAction also has constructors with more parameters. You won't need these often, but you should still know what they're for.

The next parameter is stackAmount. When applying a power to a target, if the target doesn't already have that power, then the instance you give to the action is directly applied to the target. If the target already has that power, instead, the already existing power's amount will be adjusted by stackAmount.When stackAmount is not provided, ApplyPowerAction will just use the amount of the power you're applying, which is why it isn't necessary most of the time. A case where you might want it to be different is for certain powers that can't be stacked, such as Barricade. In cases like this, you can use 0, or even just check if the player has the power before adding the ApplyPowerAction to the queue. Non-stacking powers generally use -1 for their amount, as negative numbers are normally not displayed unless canGoNegative is set to true in the power's constructor.

After stackAmount, the next parameter is either boolean isFast or AttackEffect effect.

isFast simply makes the ApplyPowerAction faster, with less delay before the next action will happen. This is used if you're applying many powers at the same time, such as debuffing all enemies.

effect causes the ApplyPowerAction to use an AttackEffect which are generally used by the DamageAction class as a visual/sound effect.

Clone this wiki locally