UltimaxTank
¶
Assumptions¶
It is assumed this enemy's eventondeath is set to its matching EventDialogue.
It is also assumed this enemy is loaded with the UltimaxTank
animid as the presence of extra
elements are assumed which are normally initialised by AnimSpecificQuirk for this animid.
It is also assumed this enemy is initially fought alone so their summoning move logic works in expected ways.
HardMode changes¶
HardMode being true does the following changes:
- In the canonballs throw move, the amount of hits to do changes to 3 from 2
- In the canonballs throw move, the amount of frames each canonball takes to reach its target changes to 21.0 frames from 29.0 frames
- In the canonballs throw move, the damageammount of each DoDamage calls changes to 3 from 4
- In the canonballs throw move, each canonballs now inflicts the AttackDown condition to the target if
commandsuccess
is false after the DoDamage call (didn't blocked, ignores FRAMEONE) and the target doesn't have the Shield condition - In the bomb throw move, the amount of frames the bomb moves to reach its target changes to 37.0 frames from 44.5 frames
- In the spinning dash attack move, the amount of frames this enemy moves changes to 71.0 frames from 91.0 frames
- In the thrusting dash attack move, the amount of frames this enemy moves changes to 36.0 frames from 46.0 frames
Move selection¶
6 moves are possible:
- A multiple targets canonballs throws
- A party wide bomb throw of a random type
- A party wide spining dash attack
- Prepares themselves for a big attack with 2
charge
and DefenseUp condition - Summons a new WaspTrooper or WaspHealer
- A party wide thrusting dash attack
Move 6 is always (and only) used if basestate
is 104 (meaning move 4 was used before since it sets it to that value).
Move 1 and 2 are treated as the same during the move selection process. If it's selected, what determines the move used between the 2 is locktri
(this is only true after the phase transition in the pre move logic happened). If it's false, move 1 is used and if it's true, move 2 is used. They will be refered to as "move 1-2" in the move selection process below.
As for the decision of which move to use among move 1-2 through 5, it is based on odds. However, some moves have additional requirements that must be fufilled for the move to be used if selected. If the move is selected, but their requirements aren't fufilled, either another move will be used or a continue directive will be issued to the enemy action loop which restarts the entire action and effectively rerolls the move selection. The following table contains all these informations for every moves:
Move | Odds | Requirements | Falback if requirements aren't fufilled |
---|---|---|---|
1-2 | 3/10 | None, the move is always used | N/A |
3 | 2/10 | HPPercent is 0.8 or below | Move 1-2 is used |
4 | 2/10 | HPPercent is 0.65 or below | Move 1-2 is used |
5 | 3/10 | This enemy is the last remaining enemydata and turns is above 0 (past the first main turn of the battle) |
Continue directive issued to the enemy action loop which restarts the entire action and rerolls the move selection process |
Pre move logic¶
The following logic always happen before a move is used if locktri
is false (this logic hasn't happened before) and HPPercent is below 0.5. If those requirements are met, a phase transition happens:
- animstate set to 11 (
Hurt
) - MainManager.GradualScale called on
model
's 0-0-1-2 child (the canon's pipe) to change their scale to (0.85, 1.3, 1.0) with 60.0 frametime without destroy (done in paralele) UltimaxPartExplodeShake
sound plays- Done 3 times:
- DeathSmoke particles plays at this enemy + (1.0 + a random number between -2.0 and 2.0, 2.0, -1.5)
- Yield for 0.5 seconds
UltimaxPartExplode
sound playsexplosionsmall
particles plays at this enemy position (-2.25, 3.0, 0.0)model
's 1-3 child's ParticleSystem (some some particles flowing up) playsmodel
's 0-0-1-2 child (the canon's normal pipe) is disabledmodel
's 0-0-1-4 child (the canon's broken pipe) is enabledlocktri
set to true (this prevents this logic from happening again for this battle)- Yield for 0.5 seconds
- animstate set to 0 (
Idle
) - Yield for 0.25 seconds
Post move logic¶
The following logic happens after a move is used only if all of the following conditions are met:
turns
% 2 is 0 (every 2 main turns starting from the first one)basestate
isn't 0 (the charging move wasn't used)- GetRandomAvaliablePlayer with nullable doesn't return -1. NOTE: This targetting scheme is broken. See the nullable GetRandomAvaliablePlayer documentation for more details. Also, this is separate from the AddDelayedProjectile 1 calls mentioned requirement below. The actual return isn't used
AddDelayedProjectile calls¶
# | Conditions | obj | targetpos | damage | turnstohit | areadamage | property | framespeed | summonedby | hitsound | hitparticle | whilesound |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Happens up to 2 times, but each calls requires that a GetRandomAvaliablePlayer call with nullable doesn't return -11 | A new Prefabs/Objects/BeeRocket GameObject rooted whose SpriteRenderer's sprite uses the projectilepsrites[17] sprite (a brown missile projectile) positioned at (0.0, 20.0, 0.0) and with a z angle of 75.0 |
A random playerdata with uniform probability among the elements (NOTE: all GetRandomAvaliablePlayer calls with nullable do NOT have their returns used to determine the target, only to check that the call may happen) |
4 | 2 | 0 | null | 60.0 | This enemy | Explosion3 |
explosion |
MisseleFall |
1: This is separate from the post move logic requirement. NOTE: This targetting scheme is broken. See the nullable GetRandomAvaliablePlayer documentation for more details. The actual return value isn't used, the target is determined separately from this call, but it actually makes it more broken because it not only disregard the player party formation, but it also disregard forceattack
.
Logic sequence¶
- SetDefaultCamera called
- MoveTowards startp with 2.0 multipluer
- Yield all frames until
forcemove
is done - Camera moves to look near (3.0. 1.0, 0.0)
- Yield for 0.25 seconds
- For each hits (2 times):
- GetRandomAvaliablePlayer with nullable call and if it returns -1, the hit is skipped
- animstate set to 101
- A new
Prefabs/Objects/BeeRocket
GameObject rooted whose SpriteRenderer's sprite uses theprojectilepsrites[17]
sprite (a brown missile projectile) positioned at the second to lastextra
(the missile launcher of themodel
) position and with a z angle of -60.0 - DeathSmoke plays at the
Prefabs/Objects/BeeRocket
position - HitPart particles plays at the
Prefabs/Objects/BeeRocket
position b33BotRocketLaunchInAir
sound plays- Over the course of 41.0 frames, the
Prefabs/Objects/BeeRocket
moves to (this enemy x position - 1.0, 10.0, 0.0) via a SmoothLerp. On the second half, before each yield, this enemy animstate is set to 0 (Idle
) Prefabs/Objects/BeeRocket
position set to (0.0, 20.0, 0.0)Prefabs/Objects/BeeRocket
z angle set to 75.0- AddDelayedProjectile 1 call happens
Move 1 - Canonballs throws¶
A multiple targets canonballs throws.
nonphyscal
set to true¶
This move always sets nonphyscal
to true which affects the effects of the FrostBite
, SpikeBod
and PoisonTouch
medal if equipped on the target.
DoDamage calls¶
# | Conditions | attacker | target | damageammount | property | overrides | block |
---|---|---|---|---|---|---|---|
1 | Always happen 2 times (3 times instead if hardmode is true), but each calls requires that there's at least 1 player party member alive (hp above 0 and not eatenby) |
This enemy | playertargetID after GetSingleTarget (target changes for each calls) |
4 (3 if hardmode is true) | null | null | commandsuccess |
Logic sequence¶
- Camera moves to look near (1.75, 0.0, 0.0)
UltimaxMove
sound plays- MoveTowards + 2.5 in x using 1 (
Walk
) as walkstate and 100 as stopstate - Yield all frames until
forcemove
is done - Done for each hit which is 2 times (3 times instead if hardmode is true):
- If there's no alive player party members (
hp
above 0 and not eatenby), the hit is skipped - GetSingleTarget called
- animstate set to 100
- MainManager.GradualScale called on the
model
's 0-0-1-2 child (the canon's pipe) to change its scale to (0.7, 1.0, 1.25) with 20.0 frametime without destroy (done in paralel) UltimaxCannonBallSuckIn
sound plays- Yield for 0.5 seconds
model
's 0-0-1-2 child (the canon's pipe)'s scale set to (1.25, 1.0, 0.7)- MainManager.GradualScale called on the
model
's 0-0-1-2 child (the canon's pipe) to change its scale to 1.0x with 10.0 frametime without destroy (done in paralel) - A new
Prefabs/Objects/RollingRock
GameObject is created rooted positioned atmodel
's 0-0-1-2 child (the canon's pipe) position + (-5.4, -0.3, 0.0) with a scale of 0.5x - ShakeScreen called with an ammount of 0.1 and 0.3 time with dontreset
- animstate set to 101
Prefabs/Objects/RollingRock
's first material's color is set to 404040 (mostly dark gray)- This enemy x position increases by 0.85
- MainManager.MoveTowards called on this enemy to move them to - 0.85 in x with 20.0 frametime without smooth and without local (done in paralel)
UltimaxCannonBallShot
sound playsexplosionsmall
particles plays at thePrefabs/Objects/RollingRock
position- Over the course of 29.0 frames (21.0 frames instead if hardmode is true),
Prefabs/Objects/RollingRock
moves toplayertargetentity
position + 1.0 in y. Before each frame yield, z angle is increased by 20.0 * MainManager.framestep
- ShakeScreen called with an ammount of 0.1 and 0.6 time with dontreset
- DoDamage 1 call happens
- If hardmode is true,
commandsuccess
is false (didn't blocked, ignores FRAMEONE) andplayerdata[playertargetID]
doesn't have the Shield condition:- StatusEffect called to inflict the AttackDown condition on
playerdata[playertargetID]
for 2 main turns (effectively 1 since the current main turn ends soon enough) with effect
- StatusEffect called to inflict the AttackDown condition on
- MainManager.ArcMovement called on
Prefabs/Objects/RollingRock
to - 10.0 in x with the y component at 0.0 with a spin of -20.0 in z, 5.0 height and 40.0 frametime with destroyonend - Yield for 0.5 seconds
- If there's no alive player party members (
Move 2 - Bomb throw¶
A party wide bomb throw of a random type.
nonphyscal
set to true¶
This move always sets nonphyscal
to true which affects the effects of the FrostBite
, SpikeBod
and PoisonTouch
medal if equipped on the target.
PartyDamage calls¶
# | Conditions | caller | damage | property | block | jumpheight | spinammount | jumpevenonblock | overrides |
---|---|---|---|---|---|---|---|---|---|
1 | Always happen | This enemy | 2 (4 instead if the bomb thrown is a SpicyBomb ) |
Depends on the bomb thrown: | commandsuccess |
0.0 | Vector3.zero | false | null |
1: This is unexpected because of an issue where no effects are applied to this bomb type. It was expected to inflict DefenseDown, but that doesn't happen even after this call
Logic sequence¶
TwistDoorEnter
sound plays- animstate set to 103
- ShakeSprite called with 0.1 intensity and 3.0 frametimer
- Yield for a frame
The bomb type is then determined with random odds:
SpicyBomb
: 1/5PoisonBomb
: 1/5SleepBomb
: 1/5FrostBomb
: 1/5NumbBomb
: 1/5
However, if it's a SleepBomb
, FrostBomb
or NumbBomb
and any of the player party members have the Freeze, Numb or Sleep conditions, the result is rerolled to be one of the following with equal chances each:
SpicyBomb
PoisonBomb
BurlyBomb
After determining the bomb type, this is what the logic does:
- A new sprite object is created rooted with the matching item sprite
- Over the course of 31.0 frames, the item sprite moves from the
model
's 0-0-1-1 child position (the SpriteRenderer near the lid) + (-0.4, 1.92, -0.1) to + (0.95, 1.73, 0.0) via a lerp, but calculated over 4 frames (further frames won't have any changes, but still have yields) Toss4
sound playsToss3
sound plays- Over the course of 44.5 frames (37.0 frames instead if hardmode is true), the item sprite position moves to
partymiddle
via a BeizierCurve3 with a ymax of 6.0. Before each yield, the item sprite's z angle increases by 10.0 * MainManager.framestep
- The item sprite is destroyed
Explosion
sound plays- Different effects happens depending on the bomb type (except for
BurlyBomb
where no effects happen):SpicyBomb
:- ShakeScreen called with an ammount of 0.2 and 0.75 time with dontreset
explosion
particles plays atpartmymiddle
PoisonBomb
:- ShakeScreen called with an ammount of 0.1 and 0.75 time
PoisonEffect
particles plays atpartmymiddle
with 2.0x scale
SleepBomb
:- ShakeScreen called with an ammount of 0.1 and 0.75 time
- DeathSmoke particles plays at
partmymiddle
with 3.0x size
FrostBomb
:- ShakeScreen called with an ammount of 0.1 and 0.75 time
mothicenormal
particles plays atpartmymiddle
with 3.0x scale
NumbBomb
:- ShakeScreen called with an ammount of 0.1 and 0.75 time
ElecFast
particles plays atpartmymiddle
with 2.0x scaleimpactsmoke
particles plays atpartmymiddle
- PartyDamage 1 call happens
- Yield for 0.5 seconds
- Yield for 0.25 seconds
Move 3 - Spinning dash attack¶
A party wide spining dash attack.
PartyDamage¶
# | Conditions | caller | damage | property | block | jumpheight | spinammount | jumpevenonblock | overrides |
---|---|---|---|---|---|---|---|---|---|
1 | Always happen | This enemy | 4 | null | commandsuccess |
0.0 | Vector3.zero | false | null |
Logic sequence¶
UltimaxMove
sound plays- MoveTowards this enemy + 5.0 in x with a 2.0 multiplier using 1 (
Walk
) as walkstate and 100 as stopstate - Camera moves to look near (3.75, 0.0, 0.0)
- Yield all frames until
forcemove
is done flip
set to falseUltimaxSpinAttackSqueeze
sound plays- Over the course of 31.0 frames,
startscale
changes to (0.8, 1.25, 1.0) via a lerp - SetDefaultCamera called
UltimaxSpinAttack
sound playsmodel
's 1-1 child's ParticleSystem (smoke particles going outwards) plays- Over the course of 91.0 frames (71.0 frames instead if hardmode is true):
- This enemy moves to (-20.0, 0.0, 0.0) via a lerp
startscale
changes to the value before this action via a lerp, but the factor is multiplied by 3 (meaning it will reach 1.0 after a third of the way)- y
spin
set to 15.0 * (current frame / total frames * 5.0) clamped from 5.0 to 15.0 (meaning from 75.0 to 225.0 reaching the max after a 1/5 of the way) - On the first frame this enemy x position becomes lower than -4.5:
- ShakeScreen called with 0.1 ammount and 0.5 time with dontreset
- PartyDamage 1 call happens
spin
zeroed out- FlipAngle called with setangle
- position set to (20.0, 0.0, 0.0)
- SetDefaultCamera called
UltimaxMove
sound plays- MoveTowards startp with 4.0 multiplier
- Yield all frames until
forcemove
is done
Move 4 - Prepares big attack with 2 charge
and DefenseUp condition¶
Prepares themselves for a big attack with 2 charge
and DefenseUp condition. No damages are dealt.
dontusecharge
set to true¶
This move always sets dontusecharge
to true which means charges
will not get zeroed out in post action.
Logic sequence¶
UltimaxChargeAttackSqueeze
sound plays- Camera moves to look near this enemy
basestate
, animstate and the local startstate are all set to 104 which allows this enemy to use the thrusting dash attack move on the next actor turn- ShakeSprite called with 0.2 intensity and 45.0 frametimer
- SahkeScreen called with an ammount of 0.05 and 0.75 time with dontreset
- Yield for 0.5 seconds
- Yield for 0.25 seconds
- StatusEffect called to inflict the DefenseUp condition on this enemy for 2 main turns (effectively 1 since the current main turn ends soon) with effect
- Yield for 0.25 seconds
- StatEffect called on this enemy with type 4 (green up arrow)
- Yield for 0.5 seconds
charge
set to 2
Move 5 - Summons a WaspTrooper or WaspHealer¶
Summons a new WaspTrooper or WaspHealer. No damages are dealt.
Logic sequence¶
TwistDoorEnter
sound plays- animstate set to 102
- Camera moves to look near this enemy
- Yield for 0.5 seconds
Whistle
sound playscheckingdead
set to a new SummonEnemy call to summon either a WaspTrooper or WaspHealer enemy (determined randomly with uniform odds) with typeOffscreen
at (0.95, 0.0, -1.25)- Yield all frames until
checkingdead
is null (the coroutine completed) enemydata[lastaddedid]
gets some adjustements:hp
andmaxhp
: value gets multiplied by 0.5 then flooredexp
: divided by 10 floored
Move 6 - Thrusting dash attack¶
A party wide thrusting dash attack.
PartyDamage¶
# | Conditions | caller | damage | property | block | jumpheight | spinammount | jumpevenonblock | overrides |
---|---|---|---|---|---|---|---|---|---|
1 | Always happen | This enemy | 4 | Pierce1 | commandsuccess |
0.0 | Vector3.zero | false | null |
1: Enemy piercing damages are disabled so this property does nothing, see the CalculateBaseDamage documentation to learn more
Logic sequence¶
- Camera moves to look near (3.75, 0.0, 0.0)
- ShakeSprite called with 0.1 intensity and 57.0 frametimer
UltimaxChargeAttackSqueeze
sound plays- Over the course of 31.0 frames, this enemy moves to + 4.0 in x via a lerp and
startscale
changes to (0.8, 1.25, 1.0) via a lerp model
's 1-2 child's ParticleSystem (blue thrust particles) plays- Yield for 0.5 seconds
- SetDefaultCamera called
UltimaxChargeAttack
sound plays- Over the course of 46.0 frames (36.0 frames instead if hardmode is true):
- This enemy moves to (-20.0, 0.0, 0.0) via a lerp
startscale
changes to the value before this action via a lerp, but the factor is multiplied by 3 (meaning it will reach 1.0 after a third of the way)- On the first frame this enemy x position becomes lower than -4.5:
- PartyDamage 1 call happens
model
's 1-2 child's ParticleSystem (blue thrust particles) stops playing- Yield for 0.25 seconds
- position set to startp + 15.0 in y
UltimaxChargeAttackFallBack
sound plays- Over the course of 21.0 frames, this enemy moves to startp via a lerp
startscale
set to (1.25, 0.8, 1.25)- ShakeScreen called with 0.2 ammount and 1.0 time with dontreset
impactsmoke
particles plays at this enemy position- Over the course of 31.0 frames,
startscale
changes to the value it had before this action via a lerp basestate
, animstate and the local startstate all set to 0 (Idle
) to prevent this enemy from using this move again on the next actor turn