Skip to content

Enemy features

Certain enemies can opt in to some features by having some of their enemy data fields setup in a certain way or simply in their DoAction's action logic. There are enough features which are complex enough that they warrant their own explanations in a separate page. These features will be documented here.

eventondeath

This feature allows to trigger an EventDialogue when the enemy party member dies.

If the value isn't -1 and the enemy party member was detected dead (without flee) by CheckDead while inevent is false (meaning an EventDialogue wasn't in progress already), an EventDialogue whose id is the eventondeath will be triggered.

Note that this will intercept the normal death process that CheckDead normally does because it's possible that the EventDialogue wants to either not have the enemy party member dead or to handle the death in a custom manner.

eventonfall

This feature allows to trigger an EventDialogue when the enemy party member drops.

When set to any non negative value, whenever CalculateBaseDamage detects that the enemy party memeber should be dropped, it won't do it as it would have normally. Instead, it will set calleventnext to eventonfall which has the effect that on the next CheckEvent, the EventDialogue whose id was eventonfall will be triggered.

NOTE: This feature, while fully functional is UNUSED in practice. No actual enemy data entry has any non negative values.

moves

The value of this field determines the base amount of actor turn an enemy is allowed to have per main turn.

In more specific terms, it means that on the AdvanceTurnEntity of the enemy party member, unless there is a specific condition preventing this, the cantmove will be set to -moves + 1. It means having a laoded moves of 1 sets the cantmove to 0 every main turn and if the loaded moves is 2, it's set to -1 and so on. Intuitively, it's the always the amount of actor turns available per main turn.

deathtype

This field tells the manner in which the enemy dies on their battleentity's Death. It maps to a DestroyType like so:

deathtype entity.destroytype
0 SpinSmoke (without reservedata)
1 SpinNoSmoke
2 KO
3 SpinSmoke (with reservedata)
4 KO
5 SpinKO
6 Shrink
7 ShrinkNoSmoke
8 None
9 Sink
10 ExplodeAnim
11 DropSprites
12 None (destroyed on the next main turn)

However, there are some special notes to add on some of them:

  • 2, 3, 4 and 5: These values supports the reservedata feature. This feature will have CheckDead kill the enemy normally, but it will also add the enemy party member to a special array called reservedata. This is done for 2 reasons: it prevents the enemy's object from being destroyed which allows them to still be rendered and it also allows them to be revived or accessed after their death
  • 2 and 4: These 2 are functionally equivalent and share the same logic
  • 12: This one is handled by DoDamage after sustaining lethal damage and it ends by setting the battleentity's tag to DestroyTurn which destroys it on the next AdvanceMainTurn. It is very specific to the following enemies:
    • KeyR
    • KeyL
    • Tablet

Difficulty scaling

This feature is documented extensively in the appropriate section of enemy data documentation because it involves a lot of loaded fields and some complex logic.

EXP

This feature is documented extensively in the appropriate section of enemy data documentation because it involves a lot of loaded fields and some complex logic.

holditem and helditem

Enemy party members have the ability to hold an item. holditem holds its id and helditem holds its SpriteRenderer.

This is primarily used for stealing items from the player party or for visually rendering them using an item. The item can be dropped by calling DropItem.

hitaction

This field tells if an enemy wants to performa an action immediately on the next controlled flow update. These actions are performed out of the main turn flow because they are ran during the player phase. It's essentially a way for an enemy party member to temporarilly seize control of the turn flow to perform their action.

During Update, all enemydata elements are checked if any has hitaction set to true. If none do, nothing happens. For each that does have it set to true, the following happens:

  • If the enemy IsStopped returns true, their hitaction gets set to false and nothing happens as it gets skipped
  • Otherwise, enemy is set to true and a DoAction call occur with the battleentity with actionid being the enemydata index. This will also end the update cycle

Setting enemy to true here is temporary: it will go back to false as part of DoAction. DoAction is also responsible for setting the enemy's hitaction back to false. The overall effect is DoAction temporarily seize control of the battle flow, but for the game, it's as if we were in an enemy phase. The flow will go back to where it was in the player phase once it's handled. Due to hitaction being true, DoAction is able to handle this special case in a separate fashion.

This cycle repeats for all applicable enemies untill all hitaction are set to false at which point, the main turn procedure can continue.

There are 3 ways to automatically have hitaction set to true upon attack:

  • onhitaction
  • chargeonotherenemy
  • isdefending being -1

Details are in the sub sections below.

onhitaction

There is a standard way to have hitaction set automatically when the enemy party member is targetted during DoDamage and it's done by the onhitaction field. The conditions required to set hitaction to true is that enemy is false (we are in the player phase) and something else that depends on the field's value:

  • If it's 1, it's always fufilled
  • If it's 2, it's only fufilled if target.position is Flying
  • If it's 3, it's only fufilled if target.position is Ground

This allows the hitaction to happen whenever the enemy party member is targetted while in any or in specific positions.

chargeonotherenemy

There is an alternative way to get hitaction set to true automatically during DoDamage, but it only applies for enemy party members other than the target. That way is the chargeonotherenemy array field which holds an array of Enemy ids.

How it works is when the target sustains the damage, every other enemy party members who has the target.animid (their enemy id) in their chargeonotherenemy has their hitaction set to !enemy (false during the enemy phase, true during the player phase).

About isdefending being -1

There is a second way to automatically set hitaction to true when the enemy party member is targetted during DoDamage. That was is by having isdefending be -1 and the position of the enemy party member must not be Underground. If this applies, it will override onhitaction and take priority by always setting hitaction to true.

In practice, only the Underling enemy does this, every other Enemy defined in the game would rather use onhitaction or chargeonotherenemy.

defenseonhit and isdefending

The value of this field has 3 modes of operations:

  • -1: See the section above about hitaction
  • 0: The enemy party member is opting out of the hitaction and the isdefending logic
  • 1 or above: No hiaction logic, but it will get the isdefending logic.

As for the isdefending, it's where the enemy party member guards and it gain points of defenses during DefaultDamageCalc when piercing doesn't apply with the amount corresponding to the value and those defense points are recognised by TrueDef. They will apply when isdefending is true unless the enemy party member is Flipped. This also enables isdefending's toggling during DoDamage (See the section below for more details). NOTE: There are several caveats with this, check the CalculateBaseDamage documentation to learn more.

isdefending

As for isdefending, it is a field that tells if the enemy party member is guarding. Its initial value is false set by StartBattle.

Guarding is the only way to gain the defenseonhit points of defenses and the main way it's done is by DoDamage where the enemy party member is targeted. It's set to true if all of the following conditions are fufilled:

  • property is't Flip (Flip prevents guarding)
  • The final amount of damages calculated is above 0
  • The enemy party member's IsStopped is false (if it's true, isdefending is set to false instead which breaks guard)

It's also possible to manually guard from DoAction's action logic.

The guarding is visually represented by having UpdateAnim set battleentity.animstate to 24 (Block) when applicable (see the method's documentation for the exact conditions required).

However, it is possible to loose the guard in many ways which sets isdefending to false:

  • SetCondition: When inflicting (or amending) a Freeze, Numb or Sleep condition
  • CalculateBaseDamage: When hit with an attack that has a Flip property, guard is broken
  • ClearStatus: Breaking guard is part of the procedure of this method
  • DoAction: All enemy party members will break guard before their actions logic. It is of course possible to override this behavior inside the action logic itself

weight

This field is a way to modify the visual rendering of an enemy sustaining an attack. A low value will make them jump or launch more in the air while a high value will make them launch less or not at all. Its impact are purely visual.

As a general rule, this should be between 0.0 and 100.0 where 100.0 won't launch at all and 0.0 will launch the furthest.

sizeonfreeze

When the enemy party member has Freeze condition, GetEnemySize will return its sizeonfreeze instead of its size if the value is above 0.1. This is only used for visual effects and animations, but it allows to accounter for its battleentity.icecube.

data

This is a general purpose array mostly meant for DoAction's actions logic. Any enemy party member can use it to persist informations between their actions.

The only place it is written to outside of DoAction is in CheckSpecialID for a BeeBot animid if it's a battle entity. In that case, it's set to a new array of 1 element whose value is either 0 or 1 determined randomly.

extrastuff

This is a general purpose transform array for use by enemy party members only during their DoAction's actions logic. Any enemy party member can use it to persist transforms between their actions.

weakness

The name of this field is a missnomer because it doesn't represent only weaknesses, but rather a general purpose list of AttackProperties that can change the damage pipeline, especially during CalculateBaseDamage.

cantfall

When this field is true, it will never be dropped by CalculateBaseDamage when its position is Flying.

It will also prevent having its position set to Ground by RefreshEnemyPos (used by GetAvailableTargets or Chompy).

lockposition is a field that does the same logic in CalculateBaseDamage specifically, but it doesn't require the position to be Flying. It doesn't include the other logic cantfall has.

notaunt

When this field is true, it specifically affects the BeetleTaunt skill by preventing the Taunted infliction.

NOTE: This doesn't prevent the forceattack being set to currentturn which means that the actual enemy party members taunting logic still works despite this. This is only meant to prevent the animations or SetCondition calls which is still desired for enemies who do not perform any targetting actions in their action logic so it doesn't look out of place visually or logically in the case of the TauntPlus medal.

notired

When this is true, enemy party members will not have their tired (exhaustion) field incremented during EndEnemyTurn like it would normally if the DoublePain medal isn't equipped.

NOTE: This applies even if flags 614 is true (HARDEST is active) because it still requires the DoublePain medal to be equipped for enemy exhaustion to be disabled.

hidehp

When this is true, RefreshEnemyHP will never render the enemy party member's hp and def stats.

fled

Setting this to true causes the enemy party member to effectively die, but not in an usual way. CheckDead will detect the death, but process it with a very reduced logic only consisting of moving them offscreen and disabling their battleentity if their destroyentity is true (only happens if their deathtype was 12 and their hp got to 0 after sustaining them in DoDamage).

notattle

Setting this to true will prevent GetTattleable from including the enemy party member in the return which prevents Tattle to work on it.

This is used in SetItem when handling a Battle strategy list type when option 1 (Spy) has been chosen.

actimmobile

When this is true, the enemy party member will almost always not have their cantmove set to higher than 0 as a result of a stopping condition and it will almost always have IsStopped return false. This means they can almost always still act while inflicted by a stopping condition.

There is one notable exception to this rule: it's possible to have IsStopped not take this field into account by sending true as the skipimmobile. This is notably done during the hitaction processing checks (meaning this field won't have an impact on whether an enemy party member is considered stopped for the purpose of the hitaction).

There are only 3 enemies in the game that have this feature enabled:

  • VenusBoss
  • WaspKing
  • EverlastingKing

diebyitself

When all the remaining enemy party members who are alive (hp above 0) have this field set to true, it tells CheckDead to set their hp to 0 and their diebyitself to false before redoing a second (and last) enemy death checks. The second check will inevitably lead to detect their deaths and kill them properly.

The reason this happens is to handle the very specific case of killing an enemy party member while only stationary ones (such as SandWall or PisciWall) remains alive. When these cases happen, it's unecessary to keep them alive and they should die if they are the only ones that remains. In other words, each would die by itself, hence the name of the field.