Merge branch 'BattleControl'

This commit is contained in:
aldelaro5
2024-03-10 12:18:28 -04:00
155 changed files with 8847 additions and 705 deletions

View File

@@ -0,0 +1,22 @@
# ActionCommands
TODO: will be documented in part 3
|Value|Name|Description|
|-----|----|-----------|
|0|None|???|
|1|PressKey|???|
|2|HoldKeyBar|???|
|3|RandomPressKeys|???|
|4|TappingKey|???|
|5|HoldKeyCountdown|???|
|6|RandomPressKeysTimer|???|
|7|RandomTappingKeys|???|
|8|RandomTappingKeysTimer|???|
|9|RandomPressBar|???|
|10|RandomTappingBar|???|
|11|RandomPressKeyTimer|???|
|12|MultiPressBar|???|
|13|LongRandomBar|???|
|14|SequentialKeys|???|
|15|Crosshairs|???|
|16|PressKeyTimer|???|

View File

@@ -0,0 +1,2 @@
# DoCommand
TODO, will be documented in part 3

View File

@@ -0,0 +1,41 @@
# AttackDown
A condition that gives a -1 damage malus on attacks by the actor while it is active when the [AttackProperty](../../Damage%20pipeline/AttackProperty.md) isn't `NoExceptions`.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition, the turn amount is always increased by the existing one (meaning it stacks).
When inflicted as a new condition, nothing special happens.
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it is always inflicted to the actor when called.
It includes optional visual effects when effect is true:
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with type 2 (red down arrow)
- The `StatDown` sound is played if it wasn't already
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
If the attacker has this condition, a -1 damage malus is applied unless property is `NoExceptions`.
A variation of this logic is also enforced outside of the damage pipeline in GetMultiDamage. That method is used by the following [skills](../../../Enums%20and%20IDs/Skills.md):
- `IceSphere`
- `IceDrill`
- `BeeFly`
## [DoDamage](../../Damage%20pipeline/DoDamage.md)
After damage calculations, if the target's `hp` is still above 0 and it doesn't have the [Shield](Shield.md) condition, this condition will be inflicted via [StatusEffect](../Conditions%20methods/StatusEffect.md) if property is `AtkDownOnBlock`. The amount of turn to inflict is 2 turns unless block is true where it's 1 turn instead. On top of this, it inflicts for one more turn if the target is a player party member (meaning 3 turns or 2 with block).
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When an [AttackUp](AttackUp.md) condition is processed (when `hp` is above 0), if the actor's `atkdownonloseatkup` is true, this condition is inflicted by doing the following:
- actor's `atkdownonloseatkup` is set to false
- [SetCondition](../Conditions%20methods/SetCondition.md) is called to inflict this condition for 2 turns on the actor
- The `StatDown` sound is played
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with type 2 (red down arrow)
## [UseCharm](../../Battle%20flow/UseCharm.md)
This condition prevents a charm of type `AttackUp` to take effect as its effect would become redundant. Check the method's documentation to learn more.
## [CheckDead](../../Battle%20flow/Action%20coroutines/CheckDead.md)
When summoning `extraenemies` at the `AbandonedCity` [map](../../../Enums%20and%20IDs/Maps.md) while [flags](../../../Flags%20arrays/flags.md) 400 is true, this condition is inflicted to all enemies alongside [DefenseUp](DefenseUp.md) for 999999 turns.

View File

@@ -0,0 +1,38 @@
# AttackUp
A condition that gives a +1 damage bonus on attacks by the actor while it is active when the [AttackProperty](../../Damage%20pipeline/AttackProperty.md) isn't `NoExceptions`.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition, the turn amount is always increased by the existing one (meaning it stacks).
When inflicted as a new condition, nothing special happens.
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it is always inflicted to the actor when called.
It includes optional visual effects when effect is true:
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with type 0 (red up arrow)
- The `StatUp` sound is played if it wasn't already
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
If the attacker has this condition, a +1 damage bonus is applied unless property is `NoExceptions`.
A variation of this logic is also enforced outside of the damage pipeline in GetMultiDamage. That method is used by the following [skills](../../../Enums%20and%20IDs/Skills.md):
- `IceSphere`
- `IceDrill`
- `BeeFly`
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0), if the actor's `atkdownonloseatkup` is true, an [AttackDown](AttackDown.md) condition is inflicted by doing the following:
- actor's `atkdownonloseatkup` is set to false
- [SetCondition](../Conditions%20methods/SetCondition.md) is called to inflict the `AttackDown` condition for 2 turns on the actor
- The `StatDown` sound is played
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with type 2 (red down arrow)
## [UseCharm](../../Battle%20flow/UseCharm.md)
This condition prevents a charm of type `AttackUp` to take effect as its effect would become redundant. Check the method's documentation to learn more.
## [CheckDead](../../Battle%20flow/Action%20coroutines/CheckDead.md)
When summoning `extraenemies` at the `AbandonedCity` [map](../../../Enums%20and%20IDs/Maps.md) while [flags](../../../Flags%20arrays/flags.md) 400 is true, this condition is inflicted to all enemies alongside [DefenseUp](DefenseUp.md) for 999999 turns.

View File

@@ -0,0 +1,21 @@
# DefenseDown
A condition that removes a point of defense recognised by [TrueDef](../../Visual%20rendering/RefreshEnemyHP.md#truedef) which can result in a +1 damage effects while it is active when the [AttackProperty](../../Damage%20pipeline/AttackProperty.md) isn't `NoExceptions`. NOTE: This has several caveats, check the [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) documentation to learn more.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition, the turn amount is always increased by the existing one (meaning it stacks).
When inflicted as a new condition, nothing special happens.
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it is always inflicted to the actor when called.
It includes optional visual effects when effect is true:
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with type 3 (blue down arrow)
- The `StatDown` sound is played if it wasn't already
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
If the attacker has this condition, a defense may be removed resulting in a -1 damage effect that applies unless property is `NoExceptions`. NOTE: This has several caveats, check the method's documentation to learn more. Notably, it prevents the [Numb](Numb.md) condition to add a defense.
## [DoDamage](../../Damage%20pipeline/DoDamage.md)
After damage calculations, if the target's `hp` is still above 0 and it doesn't have the [Shield](Shield.md) condition, this condition will be inflicted via [StatusEffect](../Conditions%20methods/StatusEffect.md) if property is `DefDownOnBlock`. The amount of turn to inflict is 2 turns unless block is true where it's 1 turn instead. On top of this, it inflicts for one more turn if the target is a player party member (meaning 3 turns or 2 with block).

View File

@@ -0,0 +1,21 @@
# DefenseUp
A condition that gives a -1 damage on attacks to the actor as a point of defense recognised by [TrueDef](../../Visual%20rendering/RefreshEnemyHP.md#truedef) while the condition is active and property isn't `NoExceptions`. NOTE: This has several caveats, check the [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) documentation to learn more.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition, the turn amount is always increased by the existing one (meaning it stacks).
When inflicted as a new condition, nothing special happens.
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it is always inflicted to the actor when called.
It includes optional visual effects when effect is true:
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with type 1 (blur up arrow)
- The `StatUp` sound is played if it wasn't already
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
If the attacker has this condition, a -1 damage effect is applied unless property is `NoExceptions` / `Flip` or piercing applies. NOTE: This has several caveats, check the method's documentation to learn more (including incorrect logic concerning this condition and the `AntlionJaws` [medal](../../../Enums%20and%20IDs/Medal.md)).
## [CheckDead](../../Battle%20flow/Action%20coroutines/CheckDead.md)
When summoning `extraenemies` at the `AbandonedCity` [map](../../../Enums%20and%20IDs/Maps.md) while [flags](../../../Flags%20arrays/flags.md) 400 is true, this condition is inflicted to all enemies alongside [AttackUp](AttackUp.md) for 999999 turns.

View File

@@ -0,0 +1,156 @@
# Eaten
A special stopping condition specific to the `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md) that allows through unorthodox methods to treat a player party member as if they were dead alongside having their `eatenby` not null.
## [IsStopped](../IsStopped.md)
This condition is considered a stop condition and will always make this method returns true (unless skipimmobile is false while the actor'a [actimmobile](../Enemy%20features.md#actimmobile) is true). This include the lite version used in the [enemy phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase). Being stopped makes the actor unable to act regardless of their `cantmove` as well as a bunch of feature they no longer get access to.
## [GetFreePlayerAmmount](../Player%20party%20members/GetFreePlayerAmmount.md)
This condition makes a player party member not count as free. This affects many logic such as knowing if a player can act.
## [Relay](../../Battle%20flow/Action%20coroutines/Relay.md)
This condition will not be transfered to the target of the relay if the relayer had a `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md). It should be noted that it is not possible to relay from a player party member with this condition under normal gameplay so this clause effectively does nothing.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0):
- A yield of 0.75 seconds is set to happen after the method is done
- If `eatenby` exists backed by an enemy party member, the player party member's `hp` is above 0 and there is at least one enemy party member:
- [DoDamage](../../Damage%20pipeline/DoDamage.md) is called to the player party member with no attacker with a `NoExceptions` property, a `NoCounter` overrides without block. The damageammount is the player party member's `maxhp` / 10.0 + 1 ceiled and then clamped from 1 to 99
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 0 with the damage amount as the amount with the start being the `eatenby` enemy party member's `cursoroffset` and the end being (0.0, 2.0, 0.0)
- [Heal](../Heal.md) is called on the `eatenby` enemy party member for the same damage amount dealt to the player party member
- If the player party member's `hp` is 0 or below while there are at least 1 player party member with an `hp` above 0 while not having an `eatenby`:
- `eatenkill` is set to true (this is used in [AdvanceMainTurn](../../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) to handle this specific case)
- [EventDialogue](../../Battle%20flow/EventDialogue.md) 19 is started and stored in `checkingdead` (this will eventually call SpitOut, check the section below for more detail)
The turn counter of the condition is never decremented because it is expected to be removed manually.
## [AdvanceMainTurn](../../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)
Right after the return of [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md), this is where the `eatenkill` handling logic happen if it is true (meaning they just died as a result of the HP drain):
- `eatenkill` is set to false (this is meant as a one shot flag field)
- All frames are yielded while `spitout` is in progress
- `checkingdead` is set to a new [CheckDead](../../Battle%20flow/Action%20coroutines/CheckDead.md) coroutine starting
- All frames are yielded while `checkingdead` is in progress
This part is necessary because the player party member may have not died properly and in order to address this, a CheckDead is needed, but it is only safe to do so after `spitout` is done.
After the player party had all their actor turns advanced, this condition will prevent a player party member from receiving the effects of the `FavoriteOne` [medal](../../../Enums%20and%20IDs/Medal.md) when another party member with the medal gets attacked.
## [ClearStatus](../Conditions%20methods/ClearStatus.md)
This condition is excluded from removal meaning it will remain even after calling this method.
## How Eat and SpitOut works
This condition has very special logic associated with it because it involves very unorthodox methods to essentially "fake" the death of a player party member. This section will clarify these methods.
This condition is specifically made to be inflicted via a method called Eat and removed with a coroutine called SpitOut (which also performs a lot of other visual effects with a strong assumption that the eater is a `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md)).
### Eat
Inflicts this condition to `playerdata[playerid]` for `turns` turns and set their `eatenby` to `enemydata[enemyid].battleentity` and the `ate` of the enemy to `playerdata[playerid].battleentity`. This is meant to be called in the enemy party member's [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md)'s action logic.
```cs
private void Eat(int enemyid, int playerid, int turns)
```
NOTE: In practice, this only works if the enemy party member is a `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md) because this eating system wasn't made to handle any other enemies.
For simplicity, `playerdata[playerid]` will be refered to as the eaten and `enemydata[enemyid]` will be refered as the eater.
The method sets the following fields:
|Field|Value|
|-----|-----|
|eaten's `eatenby`|eater's battleentity|
|eater's `ate`|eaten's battleentity|
|eaten's `moreturnnextturn`|0|
|eaten's `charge`|0|
|eaten's battleentity.`shieldenabled`|false|
And it also does the following:
- The eaten's battleentity.`sprite` is disabled
- The eaten's battleentity.`shadow` is disabled
- [ClearStatus](../Conditions%20methods/ClearStatus.md) is called on the eaten
- The `Eaten` condition is inflicted to the eaten for `turns` amount of turns via [SetCondition](../Conditions%20methods/SetCondition.md). It should be noted that the turn counter doesn't mean anything because it will never get decremented.
The overall effect is that the eaten will appear to no longer be in the battle because their sprite and shadows are disabled, but they are physically still present. In fact, they are still considered an active party member and the Eaten condition alone can't change this (the furthest it goes on that front is making [IsStopped](../IsStopped.md) return true, but this only prevents acting, it doesn't treat them as if they were dead).
For more information on how this ends up treating the player party member as dead, see the `eatenby` section below. The `ate` field is less important and it is mainly used for the `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md)'s own logic.
### SpitOut
Performs the visual animations of spitting out the actor the `eater` ate (obtained through its `ate` field) and remove the eaten's Eaten condition and set their `eatenby` to null.
```cs
private IEnumerator SpitOut(EntityControl eater)
```
The details of this coroutine won't be detailed for the sake of brevety because most of it involves very verbose animations logic, but it essentially undo what Eat did and if the eater died as a result, [Death](../../../Entities/EntityControl/Notable%20methods/Death.md) is called on it.
What is important to mention is the circumstances in which this coroutine is called because it's done at very specific points:
- [EventDialogue](../../Battle%20flow/EventDialogue.md) 19: This is explained in the [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md) section above, but this event dialogue is responsible for spitting out the eater in the case the eaten just died as a result of the HP drain attack
- [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md): This is where the `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md) can decide to spit out the player party member on its own (under normal gameplay, it's after 3 turns, counted by the `Pitcher`'s action logic).
### `eatenby` influences
The real way the system treats a player party member that has the Eaten condition as if they were dead is through their `eatenby` field because while it is mainly used for [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md) to perform the HP drain, it is used in many places in the battle system.
It should always be null except when Eat is called until SpitOut is processed. When it is not null, it means the actor has been eaten and the system will explicitly treat them as if they were completely dead in some ways (it is usually treated similarly then as if their `hp` reached 0). Due to how much influence this field has, it's explicitly set to null on [StartBattle](../../StartBattle.md) to make doubly sure it's always null until Eat is called.
This implies that if the only player party member left is one that's eaten, the system will inevitably switch to a [terminal flow](../../Battle%20flow/Update%20flows/Terminal%20flow.md) because it will be treated as a dead party.
Unfortunately, this has to be done on a case by case basis: there is no universal way to treat a player party member as dead because the battle system was never designed to entirely disable (not just stop) a player party member during the battle.
The following details the places affected by having an `eatenby` of not null.
#### [DoItemEffect](../../../TextAsset%20Data/Items%20data.md#doitemeffect)
Being eaten prevents the `ReviveAll` and `CureParty` effects from healing or reviving the eaten member.
#### GetAlivePlayerAmmount
Beaing eaten counts as not being alive. This method is used all over the battle system in multiple places.
#### UpdateConditionBubbles
Not only will being eaten prevent the normal icons from being rendered, but it also specifically doesn't treat them as being dead for the purpose of rendering the icon involved with the `MiracleMatter` [medal](../../../Enums%20and%20IDs/Medal.md). This effectively prevents any icons to be rendered under any circumstances even if they would have fufilled the conditions required to render them.
#### [AdvanceMainTurn](../../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)
Being eaten prevents a [delproj](../Delayed%20projectile.md) from damaging the player party member. The delproj will still land like normal, but it will not do damages the same way a player party member with an `hp` at 0 would.
#### [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) (handling the [skills list type](../../Player%20UI/ItemList%20confirmation%20handling/Skills%20list%20type.md) confirmation)
Being eaten prevents [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md) to be called on the player party member. Instead, the `Cancel` sound is played on sourceid 10.
Also, it will deny the confirmation of a player party member when selecting who to relay to when handling the `Relay` choice for a `SelectPlayer` action.
#### CheckItemUse
Being eaten always makes this return false and prevents the [UseItem](../../Battle%20flow/Action%20coroutines/UseItem.md) call. This mainly impacts the handling of the `Item` [Action](../../Player%20UI/Actions.md) by [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) when [currentchoice](../../Player%20UI/Actions.md) is `SelectEnemy` or `SelectPlayer`.
Effectively, it's not possible to use an item from or to the eaten player party member.
#### [UseItem](../../Battle%20flow/Action%20coroutines/UseItem.md)
Being eaten prevents the following effects from processing on the actor:
- `HPRecoverAll`
- `ReviveAll`
- `CureParty`
- `CurePoisonAll`
- `GradualHPParty`
It covers healing effects targetting the whole player party.
#### [UseCharm](../../Battle%20flow/UseCharm.md)
Being eaten prevents the `DefenseUp` and `HealHP` charm types from processing on the actor. This covers the charm types that target the whole player party.
#### [GetRandomAvaliablePlayer](../Targetting/GetRandomAvaliablePlayer.md)
If `forceattack` is set to a player party member that is being eaten, the `forceattack` override that normally would have happened is ignored and instead, the method will select a random target as it normally would, but the eaten member is excluded from the possible selection.
If `forceattack` is -1, the method will select a random target as it normally would, but the eaten member is excluded from the possible selection.
NOTE: All this logic implies that if the only player party member remaining is being eaten, this will cause a softlock, but this can't happen because this is treated as a dead party leading to a certain [terminal flow](../../Battle%20flow/Update%20flows/Terminal%20flow.md).
#### [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md)
Being eaten prevents the following [skills](../../../Enums%20and%20IDs/Skills.md) from processing on the eaten player party member:
- `DefenseUpPlus`
- `SharingStash`
- `BubbleShield` (also `BubbleShieldLite`, but it's not possible to even select the eaten player party member in the first place)
It also prevents the `Abombhoney` [items](../../../Enums%20and%20IDs/Items.md) from processing on them.
For a `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md), his poison attack that targets the player party won't affect an eaten player party member.

View File

@@ -0,0 +1,30 @@
# EventStop
A stop condition specifically made for [event](../../../Enums%20and%20IDs/Events.md) 182 (trying to exit the room after approaching the tank in the last room of Upper Snakemouth) that simply disables a party member until it is manually removed (it is not meant to expire naturally).
## [IsStopped](../IsStopped.md)
This condition is considered a stop condition and will always make this method returns true (unless skipimmobile is false while the actor'a [actimmobile](../Enemy%20features.md#actimmobile) is true). This include the lite version used in the [enemy phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase). Being stopped makes the actor unable to act regardless of their `cantmove` as well as a bunch of feature they no longer get access to.
## [GetFreePlayerAmmount](../Player%20party%20members/GetFreePlayerAmmount.md)
This condition makes a player party member not count as free. This affects many logic such as knowing if a player can act.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) (`Relay` -> `SelectPlayer`)
This condition will deny the confirmation of a player party member when selecting who to relay to when handling the `Relay` choice for a `SelectPlayer` action.
## [Relay](../../Battle%20flow/Action%20coroutines/Relay.md)
This condition will not be transfered to the target of the relay if the relayer had a `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md). It should be noted that it is not possible to act with this condition on a player party member under normal gameplay so this clause does nothing in practice.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition just expired after decrementing its turn counter:
- [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md) is called on the actor's battleentity if its `icecube` exists
- The actor's `cantmove` is set to 1 (this will become 0 if their `hp` is above 0 since turn advancement has yet to happen)
If the condition didn't expire after the decrement, `cantmove` is set to 1 for an enemy party member or to 0 for a player party member instead of the normal actor turn advancement.
NOTE: This logic should normally never apply because the condition is made to not expire and be manually removed.
## [ClearStatus](../Conditions%20methods/ClearStatus.md)
This condition is excluded from removal meaning it will remain even after calling this method.
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
For all alive (`hp` above 0) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`).

View File

@@ -0,0 +1,34 @@
# Fire
A condition that deals non lethal damage (more than [Poison](Poison.md)) every actor turn while it is active that may be inflicted in [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) if property is `Fire` (without a resistance field) featuring a `Prefabs/Particles/Flame` as a `firepart`.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition, the turn counter is always increased by absolute value of the sent one / 2.0 ceiled (this means it stacks, but by around half of the sent turns amount).
When inflicted as a new condition, nothing special happens.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition may be inflicted if the property is `Fire`. This means it's also supported by the `StatusMirror` [medal](../../../Enums%20and%20IDs/Medal.md). It does not use a resistance field, check the method's documentation to learn more on the conditions needed for the infliction to work.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0 and there is at least one enemy party member):
- The `Flame` sound is played
- [DoDamage](../../Damage%20pipeline/DoDamage.md) is called to the actor with no attacker with a `NoExceptions` property without block. The damageammount is the player party member's `maxhp` / 7.5 ceiled - 1 and then clamped from 2 to 3. The call also has these overrides:
- `NoFall`,
- `NoIceBreak`,
- `FakeAnim`,
- `DontAwake`,
- `IgnoreNumb`
- If the actor's `hp` became 0, battleentity.`overrideanim` is set to false followed by an OverrideOver call being invoked on the battleentity in 1.0 seconds
- The actor's `hp` is clamped from 1 to its `maxhp`
- A yield of 0.75 seconds is set to happen after the method is done
## [UpdateEntities](../../Visual%20rendering/UpdateEntities.md)
This condition will have the battleentity.`sprite`.material.color to be set to a lerp from the existing one to 0xBF5919 (bright orange) with a factor of 1/5 of the frametime. Check the documentation of the method to learn more about how the alpha channel is determined.
This condition includes the initialisation of the actor's `firepart` as a new instance of `Prefabs/Particles/Flame` childed to the `sprite` with a `DelAftBtl` tag and a local position of Vector3.up.
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
This condition will cause the `currentturn` player party member to have its battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) set to 20 (`WeakPickAction`) instead of (`PickAction`) when its battleentity.`overrideanim` is false.
This condition may cause the other player party members to have their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) set to 17 (`WeakBattleIdle`) instead of 13 (`BattleIdle`). Check the method's documentation to learn more on the specifics.

View File

@@ -0,0 +1,41 @@
# Flipped
An ephemeral condition specific to enemy party members that is only inflicted with a `Flip` [AttackProperty](../../Damage%20pipeline/AttackProperty.md) to an enemy party member with a `Flip` [weakness](../../Damage%20pipeline/AttackProperty.md). It causes all the enemy party member's `def` to be ignored during damage calculation which is recognised by [TrueDef](../../Visual%20rendering/RefreshEnemyHP.md). This process can be hampered by [Topple](Topple.md)'s defense mechanism if it applies. NOTE: The condition logic has caveats, check the [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) documentation to learn more.
## [IsStopped](../IsStopped.md)
This condition is considered a stop condition and will always make this method returns true (unless skipimmobile is false while the actor'a [actimmobile](../Enemy%20features.md#actimmobile) is true). This include the lite version used in the [enemy phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase). Being stopped makes the actor unable to act regardless of their `cantmove` as well as a bunch of feature they no longer get access to.
NOTE: In practice, this being a stop condition doesn't do much because the battle system ensure it only has 1 turn on it and it gets removed manually before the enemy party member attacks.
## [Relay](../../Battle%20flow/Action%20coroutines/Relay.md)
This condition will not be transfered to the target of the relay if the relayer had a `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md). It should be noted that it is not possible to inflict this condition on a player party member under normal gameplay so this clause effectively does nothing.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition will cause the battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) to be set to 25 (`SleepFallen`) instead of 14 (`Sleep`) if a [Sleep](Sleep.md) infliction occurs.
If property is `Flip` while the target has this condition, it will change the logic to call DefaultDamageCalc instead of the standard 1 `def` ignore logic that the property normally has. In DefaultDamageCalc, this condition will actually prevent the damage to be decreased by the target's `def` which means the overall effect is this condition causes the `def` to be ignored (but not other forms of defenses). This is recognised by [TrueDef](../../Visual%20rendering/RefreshEnemyHP.md#truedef), but this comes with caveats, check the method's documentation to learn more.
If this condition wasn't present, but property is `Flip` while the target has a `Flip` [weakness](../../Damage%20pipeline/AttackProperty.md), a weaknesshit is recognised and the condition will be inflicted for 1 turn unless the target has the `ToppleFirst` [weakness](../../Damage%20pipeline/AttackProperty.md) without a [Topple](Topple.md) condition (since this is where [Topple](Topple.md) is inflicted instead as a defensive mechanism). In the case where `ToppleFirst` exists AND it already has [Topple](Topple.md), Topple is removed and `Flipped` is added in its place. For more information, check the method's documentation.
## [AdvanceTurnEntity](../../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)
When the condition is processed (when `hp` is above 0), if there's more than 1 turn left on it, the actor turn count is decremented. Otherwise, this condition isn't processed in any way meaning it exceptionally doesn't feature a normal actor turn decrease (it is always manually removed).
## [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md)
Before an enemy party member acts, if it has this condition or [Topple](Topple.md) for exactly 1 actor turn left, both are removed alongside the following logic:
- [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called on the enemy party member with a height of 10.0
- entity.`overrideanim` is set to false
- entity.`basestate` and entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 0 (`Idle`)
- startstate is set to 0 (`Idle`)
- 0.1 seconds are yielded
## [ClearStatus](../Conditions%20methods/ClearStatus.md)
This condition is excluded from removal meaning it will remain even after calling this method.
## [DoDamageAnim](../../Visual%20rendering/DoDamageAnim.md)
This condition may cause the actor's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) and `basestate` to be set to 15 (`Fallen`) alongside setting `overrideanim` to false. Check the method's documentation to learn more.
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
For all alive (`hp` above 0) enemy party members with this condition and whose `droproutine` isn't in progress, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 15 (`Fallen`) (or 25 (`SleepFallen`) if they also have the [Sleep](Sleep.md) condition).
## [Numb](../../../Entities/EntityControl/EntityControl%20Methods.md#numb)
For every enemy party member with this condition, every 60 frames, their [animstate](../../../Entities/EntityControl/Animations/animstate.md) gets set to 16 (`HurtFallen`) instead of 11 (`Hurt`).

View File

@@ -0,0 +1,102 @@
# Freeze
A stopping condition that encases the actor in a block of ice. Most attacks will remove this condition and thaw out the ice, but with a +1 damage to the attack. It also allows the target to process a `FrostBite` [medal](../../../Enums%20and%20IDs/Medal.md) when attacked.
## Resistance
This condition has a dedicated resistance field for actors to use: `freezeres`. If it's 100 or above, the actor is immune to it. Inflictions that requires a resistance check will use this field.
## Resistance increases for player party members
For player party member, the resistance can only be increased by processing the `FreezeRes` [BadgeEffects](../../../TextAsset%20Data/Medals%20data.md#medal-effects) with the value acting as the amount to increase it by. This only matters for enemy inflicting the player party member, it does not matter for user infliction using [items](../../../Enums%20and%20IDs/Items.md).
## Resistance increases for enemy party members
Here are the potential increases for the resistance associated (only applies to enemy party members):
- On [StartBattle](../../StartBattle.md):
- If the calledfrom.entity or the battleentity is `inice` while it's a `Krawler` or `CursedSkull` [enemy](../../../Enums%20and%20IDs/Enemies.md), the enemy party member's `freezeres` is increased by 70
- If battleentity.`forcefire` or we are in the `GiantLair` [area](../../../Enums%20and%20IDs/librarystuff/Areas.md) except for the `GiantLairFridgeInside` [map](../../../Enums%20and%20IDs/Maps.md) while the enemy is a `Krawler`, `CursedSkull` or `Cape`, the enemy party member's `freezeres` is set to 110 making them immune (this override the clause above if it applied)
- On [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) when sucessfully inflicting this condition when property is `Freeze` (mutually exclusive, only the first that applies):
- If the corresponding [endata](../../../TextAsset%20Data/Entity%20data.md#entity-data) of the target's `hasiceanim` is true and we are either at the `GiantLairFridgeInside` [map](../../../Enums%20and%20IDs/Maps.md) or in any maps outside of the `GiantLair` area, target.`freezeres` is increased by 70
- Otherwise, if target.`frozenlastturn` is true, target.`freezeres` is increased by 25
- Otherwise, target.`freezeres` is increased by 13. The increase is 18 instead if [HardMode](../../Damage%20pipeline/HardMode.md) returns true
## [IsStopped](../IsStopped.md)
This condition is considered a stop condition and will always make this method returns true (unless skipimmobile is false while the actor'a [actimmobile](../Enemy%20features.md#actimmobile) is true). This include the lite version used in the [enemy phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase). Being stopped makes the actor unable to act regardless of their `cantmove` as well as a bunch of feature they no longer get access to.
## [GetFreePlayerAmmount](../Player%20party%20members/GetFreePlayerAmmount.md)
This condition makes a player party member not count as free. This affects many logic such as knowing if a player can act.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition:
- If the actor is an enemy party member, [isdefending](../Enemy%20features.md#isdefending) is set to false and the infliction overwrites the turn counter to the new one (meaning it won't stack)
- If the actor is a player party member, the infliction overwrites the turn counter if the new one is higher (meaning it won't stack, it can just reset it to a higher amount). An exception to this is when using an item that inflicted it which makes it stack
When inflicted as a new condition, if the actor is an enemy party member, its [isdefending](../Enemy%20features.md#isdefending) is set to false.
## [AddDelayedCondition](../Delayed%20condition.md)
This condition supports delayed infliction via AddDelayedCondition. Check its documentation to learn more.
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it might be inflicted to the actor when called.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) (`Relay` -> `SelectPlayer`)
This condition will deny the confirmation of a player party member when selecting who to relay to when handling the `Relay` choice for a `SelectPlayer` action.
## [DoDamage](../../Damage%20pipeline/DoDamage.md)
This condition overrides block to be false meaning blocking is always denied for a player party member with this condition.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition may be inflicted if the property is `Freeze`. This means it's also supported by the `StatusMirror` [medal](../../../Enums%20and%20IDs/Medal.md).
This condition prevents toppling on enemy party members with a `ToppleFirst` or `ToppleAirOnly` [AttackProperty](../../Damage%20pipeline/AttackProperty.md) in their [weakness](../Enemy%20features.md#weakness).
This condition also implicates entire logic related to it unless the `NoIceBreak` [override](../../Damage%20pipeline/DamageOverride.md) is present. Check the CalculateBaseDamage documentation to learn more, but in summary:
- Special calculation logic when the target has the `FrostBite` [medal](../../../Enums%20and%20IDs/Medal.md)
- A +1 damage when `FrostBite` didn't apply followed by the removal of this condition alongside some other ice thawing logic
## [EndPlayerTurn](../../Battle%20flow/EndPlayerTurn.md)
All enemy party members who still have this condition on EndPlayerTurn without [actimmobile](../Enemy%20features.md#actimmobile) will have their `cantmove` set to 1. NOTE: It means removing the condition on the same main turn it was inflicted may leave the `cantmove` at 1 even if the enemy party member should have been able to act during their phase.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0):
- The `Freeze` sound is played on the battleentity at 1.5 pitch
- battleentity.`shakeice` is set to true
- A yield of 0.75 seconds is set to happen after the method is done
- The turn counter of the condition is decremented
- If the turn counter still hasn't reached 0:
- `frozenlastturn` is set to true which affects [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) if property is `Freeze` since it will increase target.`freezeres` by 25 instead of 13 (18 when HardMode returns true). NOTE: while the `FrigidCoffin` [skill](../../../Enums%20and%20IDs/Skills.md) inflicts this condition outside of the damage pipeline, it still explicitly follow this logic and is therefore affected the same way
- The `cantmove` of the actor is set to 1 if it's an enemy party members and to 0 if it's a player party members. NOTE: It means removing the condition for enemy party members may leave the `cantmove` at 1 even if the enemy party member should have been able to act during their phase
- Otherwise (the condition just expired)
- `frozenlastturn` is set to false
- [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md) is called on the actor's battleentity if its `icecube` exists
- The actor's `cantmove` is set to 1 (this will become 0 if their `hp` is above 0 since turn advancement has yet to happen)
## [RemoveCondition](../Conditions%20methods/RemoveCondition.md)
Removing this condition via this method will have [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md) called on the entity if it exists (not the battleentity).
## [HealConditions](../Conditions%20methods/HealConditions.md)
This condition is supported by this method and it will be removed when called.
## [ClearStatus](../Conditions%20methods/ClearStatus.md)
When this method is called while the actor has this condition, [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md) is called on the battleentity.
## GetBlock
For all alive (`hp` above 0 and not `dead`) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`).
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
For all alive (`hp` above 0) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`).
## [AddExperience](../../Battle%20flow/Terminal%20coroutines/AddExperience.md)
All player party members who still had this condition when AddExperience occurs will have [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md) called on their battleentity.
## GetEnemySize
This condition causes this method to return the enemy party member's [sizeonfreeze](../Enemy%20features.md#sizeonfreeze) if it is above 0.1 instead of its `size`. This can affect the following [skills](../../../Enums%20and%20IDs/Skills.md) and player party members' attacks where the attacker will move to a slightly different position towards the target during the action:
- `firststrike` action (when the [animid](../../../Enums%20and%20IDs/AnimIDs.md) is `Beetle`)
- `Beetle`'s basic attack (when the [animid](../../../Enums%20and%20IDs/AnimIDs.md) is `Beetle`)
- `HeavyStrike`
- `NeedlePincer`
## [Drop](../../../Entities/EntityControl/EntityControl%20Methods.md#drop)
The entity will drop to 0.0 instead of its `minheight` when it has this condition.

View File

@@ -0,0 +1,16 @@
# GradualHP
A condition that increases the actor's `hp` by 2 (clamped from 0 to `maxhp`) every actor turn while active.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition, the turn amount is always increased by the existing one (meaning it stacks).
When inflicted as a new condition, nothing special happens.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0, but less than `maxhp`):
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 1 (HP) with the amount being 2 with a start of the actor position + its `cursoroffset` and an end of Vector3.up
- The actor's `hp` is incremented by 2 clamped from 0 to the actor's `maxhp`
- The `Heal` sound is played
- A yield of 0.75 seconds is set to happen after the method is done
- The turn counter of the condition is decremented

View File

@@ -0,0 +1,16 @@
# GradualTP
A condition that increases instance.`tp` by 2 (clamped from 0 to instance.`maxtp`) every actor turn while active.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition, the turn amount is always increased by the existing one (meaning it stacks).
When inflicted as a new condition, nothing special happens.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when instance.`tp` is above 0, but less than instance.`maxtp`):
- The `Heal2` sound is played
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 2 (TP) with the amount being 2 with a start of the actor position + its `cursoroffset` and an end of Vector3.up
- instance.`tp` is incremented by 2 clamped from 0 to instance.`maxtp`
- A yield of 0.75 seconds is set to happen after the method is done
- The turn counter of the condition is decremented

View File

@@ -0,0 +1,16 @@
# Inked
A condition that prevents a player party member from using a [skill](../../../Enums%20and%20IDs/Skills.md) that may be inflicted in [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) if property is `Ink` or `InkOnBlock` (without a resistance field) featuring a `Prefabs/Particles/InkDrip` as a `firepart`.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md)
This condition prevents the `Skill` [Actions](../../Player%20UI/Actions.md) option (the buzzer is played instead).
## [SetMaxOptions](../../Player%20UI/SetMaxOptions.md)
This condition causes the vine icons for the `Skill` [Actions](../../Player%20UI/Actions.md) to render with the MainManager.`grayscale` material instead of MainManager.`spritedefaultunity`.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition may be inflicted if the property is `Ink` or `InkOnBlock`. This means it's also supported by the `StatusMirror` [medal](../../../Enums%20and%20IDs/Medal.md). It does not use a resistance field, check the method's documentation to learn more on the conditions needed for the infliction to work.
## [UpdateEntities](../../Visual%20rendering/UpdateEntities.md)
This condition will have the battleentity.`sprite`.material.color to be set to a lerp from the existing one to 0x7200D8 (bright purple) with a factor of 1/5 of the frametime. Check the documentation of the method to learn more about how the alpha channel is determined.
This condition includes the initialisation of the actor's `firepart` as a new instance of `Prefabs/Particles/InkDrip` childed to the `sprite` with a `DelAftBtl` tag and a local position of Vector3.up.

View File

@@ -0,0 +1,79 @@
# Numb
A stopping condition that gives the actor a point of defense (with caveats, see [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) documentation for details). It also allows the target to process a `ShockTrooper` [medal](../../../Enums%20and%20IDs/Medal.md) which can bypass damage calculation.
## About `isnumb`
This condition feature a field that tells if it's present or not called `isnumb`. However, it's redundant: a [HasCondition](../Conditions%20methods/HasCondition.md) call gives the same information. It is nonetheless used in very specific edgecases instead of calling this method. The field is frequently updated to match the presence of the condition so in practice, this field can be ignored and treated as if a HasCondition returns above 0.
It is mentioned here because it remains important to make sure this field is updated if the condition's presence changes.
## Resistance
This condition has a dedicated resistance field for actors to use: `numbres`. If it's 100 or above, the actor is immune to it. Inflictions that requires a resistance check will use this field.
## Resistance increases for player party members
For player party member, the resistance can only be increased by processing the `NumbRes` [BadgeEffects](../../../TextAsset%20Data/Medals%20data.md#medal-effects) with the value acting as the amount to increase it by. This only matters for enemy inflicting the player party member, it does not matter for user infliction using [items](../../../Enums%20and%20IDs/Items.md).
## Resistance increases for enemy party members
For player party member target when property is `Numb` or `Numb1Turn` and when successfully inflicting this condition, [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md), target.`numbres` is increased by 17. The increase is 22 instead if [HardMode](../../Damage%20pipeline/HardMode.md) returns true
## [IsStopped](../IsStopped.md)
This condition is considered a stop condition and will always make this method returns true (unless skipimmobile is false while the actor'a [actimmobile](../Enemy%20features.md#actimmobile) is true). This include the lite version used in the [enemy phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase). Being stopped makes the actor unable to act regardless of their `cantmove` as well as a bunch of feature they no longer get access to.
## [GetFreePlayerAmmount](../Player%20party%20members/GetFreePlayerAmmount.md)
This condition makes a player party member not count as free. This affects many logic such as knowing if a player can act.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition:
- If the actor is an enemy party member, [isdefending](../Enemy%20features.md#isdefending) is set to false and the infliction overwrites the turn counter to the new one (meaning it won't stack)
- If the actor is a player party member, the infliction overwrites the turn counter if the new one is higher (meaning it won't stack, it can just reset it to a higher amount). An exception to this is when using an item that inflicted it which makes it stack
When inflicted as a new condition, if the actor is an enemy party member, its [isdefending](../Enemy%20features.md#isdefending) is set to false.
Any method call updates `isnumb` accordingly.
## [AddDelayedCondition](../Delayed%20condition.md)
This condition supports delayed infliction via AddDelayedCondition. Check its documentation to learn more.
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it might be inflicted to the actor when called.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) (`Relay` -> `SelectPlayer`)
This condition will deny the confirmation of a player party member when selecting who to relay to when handling the `Relay` choice for a `SelectPlayer` action.
## [DoDamage](../../Damage%20pipeline/DoDamage.md)
This condition overrides block to be false meaning blocking is always denied for a player party member with this condition.
This condition allows a target with a `ShockTrooper` [medal](../../../Enums%20and%20IDs/Medal.md) to be considered Invulnerable and bypass damage calculation completely. In such case, the damage ammount is overriden to 0 unless property is `NoExceptions` where it's overriden by the original damageammount sent to the method.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition may be inflicted if the property is `Numb` or `Numb1Turn` (it's the same as `Numb`, but it always inflict for 1 turn). This means it's also supported by the `StatusMirror` [medal](../../../Enums%20and%20IDs/Medal.md).
This condition prevents toppling on enemy party members with a `ToppleFirst` or `ToppleAirOnly` [AttackProperty](../../Damage%20pipeline/AttackProperty.md) in their [weakness](../Enemy%20features.md#weakness).
This condition gives a point of defense recognised by [TrueDef](../../Visual%20rendering/RefreshEnemyHP.md#TrueDef) and will result in a -1 damage. NOTE: this has several caveats, check CalculateBaseDamage's documentation to learn more.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0):
- The `ElecFast` particles are played at the battleentity position + Vector3.up
- A ShakeSprite coroutine is started on the battleentity with the intensity being (0.1, 0.15, 0.0) for 40.0 frames
- The `Shock` sound is played on the battleentity at 1.25 pitch
- A yield of 0.75 seconds is set to happen after the method is done
- The turn counter of the condition is decremented
- If the condition just expired, the actor's `cantmove` is set to 1 (this will become 0 if their `hp` is above 0 since turn advancement has yet to happen)
- `isnumb` is updated accordingly with the new status of the condition and if it's still true, the `cantmove` of the actor is set to 1 if it's an enemy party members and to 0 if it's a player party members. NOTE: It means removing the condition for enemy party members may leave the `cantmove` at 1 even if the enemy party member should have been able to act during their phase
## [RemoveCondition](../Conditions%20methods/RemoveCondition.md)
Removing this condition via this method will have the actor's `isnumb` set to false.
## [HealConditions](../Conditions%20methods/HealConditions.md)
This condition is supported by this method and it will be removed when called on top of setting the actor's `isnumb` to false.
## GetBlock
For all alive (`hp` above 0 and not `dead`) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`).
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
For all alive (`hp` above 0) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`).
## EntityControl.[LateUpdate](../../../Entities/EntityControl/Update%20process/Unity%20events/LateUpdate.md)
For any battle entities that isn't `dead` or `iskill` while not in a [terminal flow](../../Battle%20flow/Update%20flows/Terminal%20flow.md), [Numb](../../../Entities/EntityControl/EntityControl%20Methods.md#numb) is called if `isnumb` is true which plays the periodic numbing visual effects.

View File

@@ -0,0 +1,72 @@
# Poison
A condition that either deals non lethal damage or heals the actor each actor turn depending on if they have a `ReversePoison` [medal](../../../Enums%20and%20IDs/Medal.md) or not. It also allows several poison specific medals to take effect.
## Resistance
This condition has a dedicated resistance field for actors to use: `poisonres`. If it's 100 or above, the actor is immune to it. Inflictions that requires a resistance check will use this field.
## Resistance increases for player party members
For player party member, the resistance can only be increased by processing the `PoisonRes` [BadgeEffects](../../../TextAsset%20Data/Medals%20data.md#medal-effects) with the value acting as the amount to increase it by. This only matters for enemy inflicting the player party member, it does not matter for user infliction using [items](../../../Enums%20and%20IDs/Items.md).
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition:
- If the actor is a player party member with an `EternalPoison` [medal](../../../Enums%20and%20IDs/Medal.md), the turn amount is overriden to be 99999 and the infliction overwrites the turn counter to the new one (meaning it won't stack)
- Otherwise, the inflicting is ammended by adding the turn amount to the existing one (meaning it will stack)
When inflicted as a new condition, the same `EternalPoison` logic occurs (the turn ammount is overriden to 99999).
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it might be inflicted to the actor when called.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition may be inflicted if the property is `Poison`. This means it's also supported by the `StatusMirror` [medal](../../../Enums%20and%20IDs/Medal.md).
This condition allows the `PoisonAttacker` [medal](../../../Enums%20and%20IDs/Medal.md) to take effect by increasing the damage amount by the amount of `PoisonAttacker` equipped for a player attacker while not in `demomode`.
A variation of the `PoisonAttacker` logic is also enforced (except the `demomode` check) outside of the damage pipeline in GetMultiDamage with the only difference being that the increase is by (amount of attacker's `PoisonAttacker` - amount of attacker's `ReversePoison`). That method is used by the following [skills](../../../Enums%20and%20IDs/Skills.md):
- `IceSphere`
- `IceDrill`
- `BeeFly`
### [DefaultDamageCalc](../../Damage%20pipeline/CalculateBaseDamage.md#defaultdamagecalc)
This condition allows the `PoisonDefender` and `ReversePoison` [medals](../../../Enums%20and%20IDs/Medal.md) to take effect by decreasing the damage amount by (amount of target's `PoisonDefender` - amount of target's `ReversePoison`).
## [DoDamage](../../Damage%20pipeline/DoDamage.md)
This condition allows the The `PoisonTouch` [medal](../../../Enums%20and%20IDs/Medal.md) to take effect is equipped on the target if the following are all true:
- The attacker is an enemy party member
- The attacker's `poisonres` is less than 100 (it's not immune)
- `nonphysical` is false
If all of the above are fufilled, [SetCondition](../Conditions%20methods/SetCondition.md) is called to set the [Poison](Poison.md) condition on the corresponding enemy party member of the attacker for 2 turns.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0 and there is at least one enemy party member):
- If the actor is a player party member with a `ReversePoison` [medal](../../../Enums%20and%20IDs/Medal.md) equipped:
- The actor's `hp` is increased by the actor's `maxhp` * 0.1 rounded to nearest clamped from 1 to 3. NOTE: the nearest rounding has a quirk where if it ends in .5, the even number will be chosen over the odd one no matter if it is actually the lower or higher bound that is correct mathematically
- If the `Heal` sound isn't playing or its more than halfway done player, it is played
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 1 with the damage amount as the amount healed earlier with the start being the battleentity position + (0.0, 1.0, 0.0) and the end being (0.0, 2.0, 0.0)
- Otherwise, [DoDamage](../../Damage%20pipeline/DoDamage.md) is called with target being the actor with no attacker with a `NoExceptions` property without block. The damageammount is the actor's `maxhp` / 10.0 ceiled - 1 and then clamped from 1 to 3 for a player party member and from 1 to 2 for an enemy party member. The call also has these overrides:
- `NoFall`
- `NoIceBreak`
- `FakeAnim`
- `DontAwake`
- `IgnoreNumb`
- If the actor's `hp` became 0, battleentity.`overrideanim` is set to false followed by an OverrideOver call being invoked on the battleentity in 1.0 seconds
- The actor's `hp` is clamped from 1 to its `maxhp` (this implies it can't be lethal)
- A yield of 0.75 seconds is set to happen after the method is done
Exceptionally, the turn counter of the condition won't decrement if the actor has an `EternalPoison` [medal](../../../Enums%20and%20IDs/Medal.md).
## [HealConditions](../Conditions%20methods/HealConditions.md)
This condition is supported by this method and it will be removed when called.
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
This condition will cause the `currentturn` player party member to have its battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) set to 20 (`WeakPickAction`) instead of (`PickAction`) when its battleentity.`overrideanim` is false.
This condition may cause the other player party members to have their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) set to 17 (`WeakBattleIdle`) instead of 13 (`BattleIdle`). Check the method's documentation to learn more on the specifics.
## [UpdateEntities](../../Visual%20rendering/UpdateEntities.md)
This condition will have the battleentity.`sprite`.material.color to be set to a lerp from the existing one to 0xD800D8 (bright magenta) with a factor of 1/5 of the frametime. Check the documentation of the method to learn more about how the alpha channel is determined.

View File

@@ -0,0 +1,14 @@
# Reflection
A condition that causes a player party member to sustain less damage from [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) with the reduction amount being the amount of `Reflection` [medal](../../../Enums%20and%20IDs/Medal.md) equipped. It always expire on the next actor turn, but the turn counter is used to visually show the amount of the damage reduction.
## [Relay](../../Battle%20flow/Action%20coroutines/Relay.md)
This condition will not be transfered to the target of the relay if the relayer had a `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md).
## Choosing [DoNothing](../../Player%20UI/ItemList%20confirmation%20handling/Battle%20strategy%20list%20type.md#2-do-nothing) in the [Battle strategy list type](../../../ItemList/List%20Types%20Group%20Details/Battle%20Strategy%20List%20Type.md)
If the `currentturn` player party member has a `Reflection` [medal](../../../Enums%20and%20IDs/Medal.md), this condition is inflicted via [SetCondition](../Conditions%20methods/SetCondition.md) with the turn amount being the amount of `Reflection` equipped (this isn't a true turn counter and more a visual to show the amount of damage reduction that will happen when attacked).
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition will cause a decrease of the damage for a player party member. The reduction amount is the amount of `Reflection` [medal](../../../Enums%20and%20IDs/Medal.md) equipped on the target.
## [AdvanceTurnEntity](../../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)
When the condition is processed (when `hp` is above 0), the turn counter is always set to 0. This is because this condition is meant to expire immediately since the actual turn counter is semantically used to show the amount of damages any attacks will be reduced by.

View File

@@ -0,0 +1,21 @@
# Shield
A condition that encases the acotr in a shield by controlling its battleentity.`shieldenabled` which allows it to bypass damage calculation and not loose its `plating`.
## [Relay](../../Battle%20flow/Action%20coroutines/Relay.md)
This condition will not be transfered to the target of the relay if the relayer had a `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md).
## [SetCondition](../Conditions%20methods/SetCondition.md)
When inflicting or amending the condition:
- battleentity.`shieldenabled` gets set to true
- If the actor is a player party member, the turn counter is overriden to 1
## [DoDamage](../../Damage%20pipeline/DoDamage.md)
This condition allows a target to be considered Invulnerable and bypass damage calculation completely. In such case, the damage ammount is overriden to 0 unless property is `NoExceptions` where it's overriden by the original damageammount sent to the method.
This condition will prevent target.`plating` from being set to false after damage calculation.
This condition prevents the `DefDownOnBlock` and `AtkDownOnBlock` from taking effect after damage calculation which effectively prevents their ensuing [DefenseDown](DefenseDown.md) and [AttackDown](AttackDown.md).
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition has just expired, battleentity.`shieldenabled` gets set to false.

View File

@@ -0,0 +1,82 @@
# Sleep
A stopping condition that will heal the attacker on each actor turn and be removed on most attacks due to waking up (with caveats, see [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) documentation for details). It also allows the target to process a `HeavySleeper` [medal](../../../Enums%20and%20IDs/Medal.md) which can prevent waking up, halve the damage amount and heal for more per actor turn.
## About `isasleep`
This condition feature a field that tells if it's present or not called `isasleep`. However, it's redundant: a [HasCondition](../Conditions%20methods/HasCondition.md) call gives the same information. It is nonetheless used in very specific edgecases instead of calling this method. The field is frequently updated to match the presence of the condition so in practice, this field can be ignored and treated as if a HasCondition returns above 0. Calling HasCondition also may set `isasleep` to true if it has the condition (only if it is the condition seeked or it occurs before the seeked one).
It is mentioned here because it remains important to make sure this field is updated if the condition's presence changes.
## Resistance
This condition has a dedicated resistance field for actors to use: `sleepres`. If it's 100 or above, the actor is immune to it. Inflictions that requires a resistance check will use this field.
## Resistance increases for player party members
For player party member, the resistance can only be increased by processing the `SleepRes` [BadgeEffects](../../../TextAsset%20Data/Medals%20data.md#medal-effects) with the value acting as the amount to increase it by. This only matters for enemy inflicting the player party member, it does not matter for user infliction using [items](../../../Enums%20and%20IDs/Items.md).
## Resistance increases for enemy party members
For player party member target when property is `Sleep` and when successfully inflicting this condition, [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md), target.`sleepres` is increased by 9. The increase is 13 instead if [HardMode](../../Damage%20pipeline/HardMode.md) returns true
## [IsStopped](../IsStopped.md)
This condition is considered a stop condition and will always make this method returns true (unless skipimmobile is false while the actor'a [actimmobile](../Enemy%20features.md#actimmobile) is true). This include the lite version used in the [enemy phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase). Being stopped makes the actor unable to act regardless of their `cantmove` as well as a bunch of feature they no longer get access to.
## [GetFreePlayerAmmount](../Player%20party%20members/GetFreePlayerAmmount.md)
This condition makes a player party member not count as free. This affects many logic such as knowing if a player can act.
## [SetCondition](../Conditions%20methods/SetCondition.md)
When amending the condition:
- If the actor is an enemy party member, [isdefending](../Enemy%20features.md#isdefending) is set to false and the infliction overwrites the turn counter to the new one (meaning it won't stack)
- If the actor is a player party member, the infliction overwrites the turn counter if the new one is higher (meaning it won't stack, it can just reset it to a higher amount). An exception to this is when using an item that inflicted it which makes it stack
When inflicted as a new condition, if the actor is an enemy party member, its [isdefending](../Enemy%20features.md#isdefending) is set to false.
## [AddDelayedCondition](../Delayed%20condition.md)
This condition supports delayed infliction via AddDelayedCondition. Check its documentation to learn more.
## [StatusEffect](../Conditions%20methods/StatusEffect.md)
This condition is supported by this method and it might be inflicted to the actor when called.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) (`Relay` -> `SelectPlayer`)
This condition will deny the confirmation of a player party member when selecting who to relay to when handling the `Relay` choice for a `SelectPlayer` action.
## [DoDamage](../../Damage%20pipeline/DoDamage.md)
This condition overrides block to be false meaning blocking is always denied for a player party member with this condition.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition may be inflicted if the property is `Sleep`. This means it's also supported by the `StatusMirror` [medal](../../../Enums%20and%20IDs/Medal.md).
This condition prevents toppling on enemy party members with a `ToppleFirst` or `ToppleAirOnly` [AttackProperty](../../Damage%20pipeline/AttackProperty.md) in their [weakness](../Enemy%20features.md#weakness).
In [DefaultDamageCalc](../../Damage%20pipeline/CalculateBaseDamage.md#defaultdamagecalc), this condition allows the `HeavySleeper` [medal](../../../Enums%20and%20IDs/Medal.md) to process by dividing the damage amount by 2 floored.
This condition my be removed during [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) or after its return in DoDamage damage calculation from a target with it after when sustaining damages under certain conditions (with caveats, check the methods's documentation to learn more). Notably, it won't happen if the target has the `HeavySleeper` [medal](../../../Enums%20and%20IDs/Medal.md). NOTE: If DoDamage decides to wake up the target, there is a known issue when setting their `cantmove` value. Check DoDamage's documentation to learn more.
## [EndPlayerTurn](../../Battle%20flow/EndPlayerTurn.md)
All enemy party members who still have this condition on EndPlayerTurn without [actimmobile](../Enemy%20features.md#actimmobile) will have their `cantmove` set to 1. NOTE: It means removing the condition on the same main turn it was inflicted may leave the `cantmove` at 1 even if the enemy party member should have been able to act during their phase.
## [AdvanceTurnEntity](../../Battle%20flow/AdvanceTurnEntity.md)
When the condition is processed (when `hp` is above 0, but less than `maxhp`):
- A heal amount is determined with a starting value of the actor's `maxhp` * 0.1 ceiled. If the `HeavySleeper` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped on the actor, the amount is tripled. On top of this, if it's not a player party member, the amount is clamped from 0 to 4
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 1 (HP) with the amount determined earlier with a start of the actor position + its `cursoroffset` and an end of Vector3.up
- The actor's `hp` is incremented by the amount determined earlier clamped from 0 to the actor's `maxhp`
- The `Heal` sound is played
- A yield of 0.75 seconds is set to happen after the method is done
- The turn counter of the condition is decremented
- If the condition just expired, the actor's `cantmove` is set to 1 (this will become 0 if their `hp` is above 0 since turn advancement has yet to happen)
- `isasleep` is updated accordingly with the new status of the condition and if it's still true, the `cantmove` of the actor is set to 1 if it's an enemy party members and to 0 if it's a player party members. NOTE: It means removing the condition for enemy party members may leave the `cantmove` at 1 even if the enemy party member should have been able to act during their phase
## [RemoveCondition](../Conditions%20methods/RemoveCondition.md)
Removing this condition via this method will have the actor's `isasleep` set to false.
## GetBlock
For all alive (`hp` above 0 and not `dead`) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 14 (`Sleep`).
## [DoDamageAnim](../../Damage%20pipeline/DoDamage.md)
This condition may cause the actor's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) to be set to 14 (`Sleep`). Check the method's documentation for more details.
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
For all alive (`hp` above 0) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) may set to 14 (`Sleep`).
For all alive (`hp` above 0) enemy party members with this condition alongside [Flipped](Flipped.md) and whose `droproutine` isn't in progress, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 25 (`SleepFallen`) instead of 15 (`Fallen`). If they don't have [Flipped](Flipped.md), it may be set to 14 (`Sleep`).
Check the method's documentation to learn more.

View File

@@ -0,0 +1,14 @@
# Sticky
A condition that prevents a player party member from using an [item](../../../Enums%20and%20IDs/Items.md) that may be inflicted in [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) if property is `Sticky` (without a resistance field) featuring a `Prefabs/Particles/StickyDrip` as a `firepart`.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md)
This condition prevents the `Item` [Actions](../../Player%20UI/Actions.md) option (the buzzer is played instead).
## [SetMaxOptions](../../Player%20UI/SetMaxOptions.md)
This condition causes the vine icons for the `Item` [Actions](../../Player%20UI/Actions.md) to render with the MainManager.`grayscale` material instead of MainManager.`spritedefaultunity`.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition may be inflicted if the property is `Sticky`. This means it's also supported by the `StatusMirror` [medal](../../../Enums%20and%20IDs/Medal.md). It does not use a resistance field, check the method's documentation to learn more on the conditions needed for the infliction to work.
## [UpdateEntities](../../Visual%20rendering/UpdateEntities.md)
This condition includes the initialisation of the actor's `firepart` as a new instance of `Prefabs/Particles/StickyDrip` childed to the `sprite` with a `DelAftBtl` tag (gets destroyed on [ReturnToOverworld](../../Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)) and a local position of Vector3.up.

View File

@@ -0,0 +1,21 @@
# Sturdy
A condition that prevents other conditions from being inflicted (even through using an [item](../../../Enums%20and%20IDs/Items.md)) while also getting a -3 damage effect applied in [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) at the expense that the actor cannot be relayed to.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) (`Relay` -> `SelectPlayer`)
This condition will deny the confirmation of a player party member when selecting who to relay to when handling the `Relay` choice for a `SelectPlayer` action.
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition prevents the infliction of any other conditions during damage calculation when the target has it except for [Flipped](Flipped.md) if applicable.
This condition also gives a -3 damage effect if the target has it.
## [DoItemEffect](../../../TextAsset%20Data/Items%20data.md#doitemeffect)
This condition prevents the following effects from doing anything:
- `AddPoison`
- `AddNumb`
- `AddFreeze`
- `AddSleep`
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
For all alive (`hp` above 0) player party members with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) may be set to 24 (`Block`). Check the method's documentation to learn more.

View File

@@ -0,0 +1,31 @@
# Taunted
A condition that prevents a player party member from selecting the `Skill`, `Item` and `Relay` vine menu [Actions](../../Player%20UI/Actions.md) and prevents other player party member from relaying to them.
## [GetChoiceInput](../../Player%20UI/GetChoiceInput.md)
This condition prevents the following [Actions](../../Player%20UI/Actions.md) option (the buzzer is played instead):
- `Skill`
- `Item`
- `Relay`
This condition will also deny the confirmation of another player party member's choice when selecting who to relay to when handling the `Relay` choice for a `SelectPlayer` action. Effectively, it means not only the condition prevents the player party member from relaying, it also prevents them to be relayed to.
## [SetMaxOptions](../../Player%20UI/SetMaxOptions.md)
This condition causes the vine icons for these [Actions](../../Player%20UI/Actions.md) to render with the MainManager.`grayscale` material instead of MainManager.`spritedefaultunity`:
- `Skill`
- `Item`
- `Relay`
## [ClearStatus](../Conditions%20methods/ClearStatus.md)
This condition is excluded from removal meaning it will remain even after calling this method.
## [UpdateAnim](../../Visual%20rendering/UpdateAnim.md)
For all player party members with an `hp` above 4 with this condition and whose battleentity.`overrideanim` is false, their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) may be set to AngryAnim which depends on the [animid](../../../Enums%20and%20IDs/AnimIDs.md): 10 (`Flustered`) for `Bee`, 5 (`Angry`) for `Beetle` and 102 for `Moth`. Check the method's documentation for the exact conditions.
## About enemy party members
The `BeetleTaunt` [skill](../../../Enums%20and%20IDs/Skills.md) allows to inflict this condition to an enemy party member, but it effectively doesn't do anything on its own for enemy party members because the effects described above only concerns the player party.
Instead, the skill itself has logic to affect enemy party members: it sets the `forceattack` field to `currentturn` (the player party member using the `BeetleTaunt` skill). This has the only effect of changing the logic of [GetRandomAvaliablePlayer](../Targetting/GetRandomAvaliablePlayer.md) to override its return to `forceattack` if `playerdata[forceattack].eatenby` is null (otherwise, it generates a random target ignoring the eaten player party member).
The overall effect is enemy party members using this method in their action logic will be forced to target whoever used the skill. It implies the conditions doesn't make them do that, only the skill's action logic does.

View File

@@ -0,0 +1,32 @@
# Topple
A 1 hit defensive mechanism in the form of a condition for an enemy party member where if it has a `ToppleFirst` or `ToppleAirOnly` (if their `position` is `Flying`) [weakness](../../Damage%20pipeline/AttackProperty.md) it won't get dropped or [Flipped](Flipped.md) immediately when it was supposed to otherwise. Instead, this condition will be inflicted without the drop or flip featuring a `Woobly` [animstate](../../../Entities/EntityControl/Animations/animstate.md) and it will be removed after most attacks which allows the drop or flip to occur on any subsequent hit.
## [Relay](../../Battle%20flow/Action%20coroutines/Relay.md)
This condition will not be transfered to the target of the relay if the relayer had a `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md). It should be noted that it is not possible to inflict this condition on a player party member under normal gameplay so this clause effectively does nothing.
## [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md)
Before an enemy party member acts, if it has this condition or [Flipped](Flipped.md) for exactly 1 actor turn left, both are removed alongside the following logic:
- [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called on the enemy party member with a height of 10.0
- entity.`overrideanim` is set to false
- entity.`basestate` and entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 0 (`Idle`)
- startstate is set to 0 (`Idle`)
- 0.1 seconds are yielded
## [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md)
This condition prevents toppling an enemy party members with a `ToppleFirst` or `ToppleAirOnly` [AttackProperty](../../Damage%20pipeline/AttackProperty.md) in their [weakness](../Enemy%20features.md#weakness) (because it would be redundant).
This condition is removed if [Freeze](Freeze.md) is inflicted.
This condition is removed if the target has it, property is `Flip` while the target has a `Flip` and `ToppleFirst` [weakness](../../Damage%20pipeline/AttackProperty.md) without the [Flipped](Flipped.md) condition. It essentially acts as replacing `Topple` with `Flipped` in this case since it also inflicts [Flipped](Flipped.md). However, if the condition isn't present while the other conditions are fufilled, it is inflicted for 1 turn and on top of this, if the the target.`position` is `Ground`, battleentity.`basestate` is set to 21 (`Woobly`).
This condition is removed if the damage calculation logic needs to drop the enemy party member. Check the method documentation to learn about the conditions for that to happen.
## [Drop](../../../Entities/EntityControl/Notable%20methods/Drop.md)
For any enemy party member entity with this condition after the drop, it is removed alongside setting its `basestate` to 0 (`Idle`).
## [DoDamageAnim](../../Visual%20rendering/DoDamageAnim.md)
This condition may cause the actor's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) and `basestate` to be set to 21 (`Woobly`) alongside setting `overrideanim` to false. Check the method's documentation to learn more.
## Note about [ClearStatus](../Conditions%20methods/ClearStatus.md)
This method will clear this condition, but it's not supposed to: it was mistakenly left out of the exclusion list. This means that when the condition gets cleared, the actor's [animstate](../../../Entities/EntityControl/Animations/animstate.md) and `basestate` may still be left on 21 (`Woobly`) since this condition normally would cause reverting that upon removal, but this removal isn't supposed to happen.

View File

@@ -0,0 +1,230 @@
# BattleData
This is defined in MainManager, but it is primarily used for the battle system. It contains all the data associated with an actor, but it primarily augments an [EntityControl](../../Entities/EntityControl/EntityControl.md) which is stored in the battleentity field (or the entity field for the overworld version for player party members).
Fields can be intended to be used for only player party members, only enemy party members or any actors depending on the specific field.
## Player party members fields
These fields only applies to player party members.
### Addressing
|Name|Type|Description|
|---:|---|---|
|trueid|int|The [animid](../../Enums%20and%20IDs/AnimIDs.md#animids) of the player party member (learn more why this is equivalent to the `animid` in the [playerdata addressing](../playerdata%20addressing.md) documentation)|
### Stats
|Name|Type|Description|
|---:|---|---|
|basehp|int|The max HP after applying all the `statbonus` from the initial one (this is initially 7 except for the `Beetle` [animid](../../Enums%20and%20IDs/AnimIDs.md#animids) where it's 9)|
|hpt|int|The displayed HUD value of the `hp`|
|baseatk|int|The attack after applying all the `statbonus` from the initial one (initially 2)|
|basedef|int|The defense after applying all the `statbonus` from the initial one (initially 0)|
### Abilities
|Name|Type|Description|
|---:|---|---|
|skills|List<int>|The list of available [skills](../../Enums%20and%20IDs/Skills.md), set to the return of [RefreshSkills](../RefreshSkills.md) for this player party member|
|lockskills|bool|If true, prevents [skills](../../Enums%20and%20IDs/Skills.md) to be used|
|lockitems|bool|If true, prevents [items](../../Enums%20and%20IDs/Items.md) to be used|
|locktri|bool|If true, prevents relay to be used|
|haspassed|bool|If true, this player party member has already relayed which prevents it to relay again|
|lockrelayreceive|bool|If true, prevents to be relayed to from another player party member|
|lockcantmove|bool|If true, prevents `cantmove` to be set to 0 (one action available) whenever the `MiracleMatter` [medal](../../Enums%20and%20IDs/Medal.md) triggers. It is set to false after the medal triggers|
|didnothing|bool|Tells if the player party member already has chosen to [do nothing](../Player%20UI/ItemList%20confirmation%20handling/Battle%20strategy%20list%20type.md#2-do-nothing) on a previous action in the same main turn which prevents to benefits from some [medals](../../Enums%20and%20IDs/Medal.md)'s effects|
### Special states
|Name|Type|Description|
|---:|---|---|
|plating|bool|Tells if the `Plating` [medal](../../Enums%20and%20IDs/Medal.md) is equipped on this player party member and it is active|
|eatenby|EntityControl|If not null, this player party member is trapped via [eating](BattleCondition/Eaten.md) by the entity corresponding to the value (this is only used when a `Pitcher` [enemy](../../Enums%20and%20IDs/Enemies.md) eats a player party member and it not being null is treated the same as having an `hp` of 0 or below which is death)|
## Enemy party members fields
These fields only applies to enemy party members. Some of them are relayed to specific [enemy features](Enemy%20features.md) which are documented separately.
### Core state
|Name|Type|Description|
|---:|---|---|
|weakness|List<[AttackProperty](../Damage%20pipeline/AttackProperty.md)>|The list of properties that applies on this enemy party member during the damage pipeline|
|position|[BattlePosition](BattlePosition.md)|The logical battle position frequently used to determine target availability|
|[delayedcondition](Delayed%20condition.md)|List<int>|A list of [conditions](Conditions.md) (only the `BattleCondition` part) added by the damage pipeline that will be inflicted later un [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md)|
### Stats
|Name|Type|Description|
|---:|---|---|
|hardatk|int|The attack gained when the [hard dfficulty scaling](../../TextAsset%20Data/Enemies%20data.md#stats-difficulty-scaling) applies (this is 0 if it doesn't)|
### Rewards
|Name|Type|Description|
|---:|---|---|
|exp|int|The amount of EXP given when defeated (see the [EXP documentation](../../TextAsset%20Data/Enemies%20data.md#exp-logic) for details)|
|fixedexp|bool|Tells if the exp field should not be scaled and is a fixed number (see the [EXP documentation](../../TextAsset%20Data/Enemies%20data.md#exp-logic) for details)|
|money|int|The base amount of berries this enemy party member drops|
### Action features
|Name|Type|Description|
|---:|---|---|
|[moves](Enemy%20features.md#moves)|int|The amount of actions allowed per turn|
|[actimmobile](Enemy%20features.md#actimmobile)|bool|When true, it allows the enemy party member to act even if they have a stopping [condition](Conditions.md). Check the feature documentation to learn more|
|[hitaction](Enemy%20features.md#hitaction)|bool|When set to true, the enemy party member will perform a hitation on the next controlled update flow|
|[onhitaction](Enemy%20features.md#onhitaction)|int|If it's 1, [hitaction](Enemy%20features.md#hitaction) will be set to true when hit. If it's 2, it will only if [position](BattlePosition.md#battleposition) is `Flying` and if it's 3, only if it's `Ground`|
|[chargeonotherenemy](Enemy%20features.md#chargeonotherenemy)|int\[\]|The list of [enemy](../../Enums%20and%20IDs/Enemies.md) ids that when hit, will cause this enemy to have its [hitaction](Enemy%20features.md#hitaction) set to true|
### Guard feature
|Name|Type|Description|
|---:|---|---|
|[defenseonhit](Enemy%20features.md#defenseonhit-and-isdefending)|int|The amount to increase the defense when [isdefending](Enemy%20features.md#isdefending) is true|
|[isdefending](Enemy%20features.md#isdefending)|bool|Tells if the enemy party member is guarding which increases its effective defense by [defenseonhit](Enemy%20features.md#defenseonhit-and-isdefending) (It can also affect [hitaction](Enemy%20features.md#hitaction) if it's -1, check the feature documentation to learn more)|
### Conditional [EventDialogue](../Battle%20flow/EventDialogue.md)
|Name|Type|Description|
|---:|---|---|
|[eventondeath](Enemy%20features.md#eventondeath)|int|The [EventDialogue](../Battle%20flow/EventDialogue.md) id to trigger during [CheckDead](../Battle%20flow/Action%20coroutines/CheckDead.md) when it detects that the enemy party member died. -1 means no EventDialogue will occur|
|[eventonfall](Enemy%20features.md#eventonfall)|int|The [EventDialogue](../Battle%20flow/EventDialogue.md) to trigger when the enemy party member falls to the ground when sustaining damage (meaning [Drop](../../Entities/EntityControl/Notable%20methods/Drop.md#drop) is called on the battleentity as a result of sustaining damage). -1 means no EventDialogue will occur|
### Override features
|Name|Type|Description|
|---:|---|---|
|[cantfall](Enemy%20features.md)|bool|If true, the enemy party member cannot fall to the ground as a result of sustaining damage in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md)|
|lockposition|bool|Similar to [cantfall](Enemy%20features.md#cantfall) for [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) specifically, but it takes effect even if the enemy party member's [position](BattlePosition.md) isn't `Flying`|
|[notaunt](Enemy%20features.md#notaunt)|bool|If true, the enemy party member cannot be inflicted by the [Taunted](BattleCondition/Taunted.md) condition from the player party (this doesn't remove the logic, see the documentation of the feature to learn more)|
|[notattle](Enemy%20features.md#notattle)|bool|Tells if the enemy party member is not spy-able (this can be overriden to true, see the documentation about [special fields logic](../../TextAsset%20Data/Enemies%20data.md#special-fields-logic) for details)|
### Death behavior
|Name|Type|Description|
|---:|---|---|
|[fled](Enemy%20features.md#fled)|bool|If true, it indicates the enemy party member fled the battle which is seen the same way than if the `hp` reached 0 during [CheckDead](../Battle%20flow/Action%20coroutines/CheckDead.md) which means it's the same than dying, but with less logic involved to kill the enemy party member|
|notired|bool|If true, the enemy party member will not cumulated any `tired` (meaning it can't gain exhaustion) whenever the `DoublePain` [medal](../../Enums%20and%20IDs/Medal.md) is not equipped. NOTE: This doesn't cover HARDEST correctly, see the [EndEnemyTurn](../Battle%20flow/EndEnemyTurn.md) documentation to learn more|
|[deathtype](Enemy%20features.md#deathtype)|int|Dictates the manner in which the enemy party member dies|
|[diebyitself](Enemy%20features.md#diebyitself)|bool|If true, it means the enemy party member will die if all of the ones left have this field set to true automatically when [CheckDead](../Battle%20flow/Action%20coroutines/CheckDead.md) detects this situation after it had killed any other enemy party members. This is done by setting the `hp` to 0 manually before running a second check on all enemy party members which will kill them|
|alreadycounted|bool|Indicates to [CheckDead](../Battle%20flow/Action%20coroutines/CheckDead.md) that the enemy party member was already killed prior and therefore, shouldn't cause another increment of the [bestiary entry](../../Enums%20and%20IDs/librarystuff/Bestiary%20entry.md)'s defeat counter the next time the enemy party member dies|
|destroyentity|bool|If the enemy party member `fled` and this is true while the fleeing is found by [CheckDead](../Battle%20flow/Action%20coroutines/CheckDead.md), the battleentity will be disabled as part of the killing process|
### Size calculation
|Name|Type|Description|
|---:|---|---|
|size|float|The width used for calculating positioning in battle|
|initialsize|float|The initial `size` value of the enemy party member. `size` will be set to this value when [BreakIce](../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#breakice) is called on the battleentity|
|[sizeonfreeze](Enemy%20features.md#sizeonfreeze)|float|The size returned by GetEnemySize when the enemy party member has the [Freeze](BattleCondition/Freeze.md#freeze) condition instead of its `size`|
### Visual modifiers
|Name|Type|Description|
|---:|---|---|
|[hidehp](Enemy%20features.md#hidehp)|bool|Tells if its battleentity.`hpbar` should always be hidden even after spying|
|[weight](Enemy%20features.md#weight)|float|A visual modifier to apply when animating the enemy when it gets hurt by certain attacks|
### General purpose
|Name|Type|Description|
|---:|---|---|
|[data](Enemy%20features.md#data)|int\[\]|General purpose data array for use in [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md)|
|[extrastuff](Enemy%20features.md)|Transform\[\]|A general purspose transforms array for use in [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md)|
### Visual rendering
|Name|Type|Description|
|---:|---|---|
|battlepos|Vector3|The resting battle position of the enemy party members used only in an [EventDialogue](../Battle%20flow/EventDialogue.md)|
|entityname|string|The [SetText](../../SetText/SetText.md) string of its name|
### [Conditions](Conditions.md) specific
|Name|Type|Description|
|---:|---|---|
|ate|EntityControl|The entity this enemy party member is trapping via [eating](BattleCondition/Eaten.md) (this is only used for the `Pitcher` [enemy](../../Enums%20and%20IDs/Enemies.md))|
|frostbitep|ParticleSystem|An instance of `Prefabs/Particles/Snowflakes` childed to the battleentity that is initialised whenever the [Freeze](BattleCondition/Freeze.md) condition is added as a [delayed condition](Delayed%20condition.md#delayed-condition)|
## Common actor fields
These fields applies to actors from either parties.
### [EntityControl](../../Entities/EntityControl/EntityControl.md)
|Name|Type|Description|
|---:|---|---|
|battleentity|EntityControl|The entity used during the battle|
|entity|EntityControl|For a player party member, the overworld entity. For an enemy party member, the same than `battleentity`|
### Identification
|Name|Type|Description|
|---:|---|---|
|animid|int|For an enemy, the [enemy](../../Enums%20and%20IDs/Enemies.md) id. For a player, the same as the `trueid` (learn more in the [playerdata addressing](../playerdata%20addressing.md) documentation)|
### Stats
|Name|Type|Description|
|---:|---|---|
|hp|int|The HP, (for a player party member, this is clamped from 0 to `maxhp`)|
|maxhp|int|The maximum amount of HP (for a player party member, this is `basehp` after all [medal](../../Enums%20and%20IDs/Medal.md) effects applied)|
|atk|int|The attack (for a player party member, this is `baseatk` after all [medal](../../Enums%20and%20IDs/Medal.md) effects applied)|
|def|int|The base defense (for a player party member, this is `basedef` after all [medal](../../Enums%20and%20IDs/Medal.md) effects applied)|
### Actor turn tracking
|Name|Type|Description|
|---:|---|---|
|cantmove|int|The amount of actor turns that needs to pass until an action is possible. 0 Means one action is possible and anything negative further adds possible actions on the same main turn|
|moreturnnextturn|int|When above 0, on the next main turn, the actor's `cantmove` will be decreased by it which gives it this amount of additional actor turns available|
### [Conditions](Conditions.md) tracking
|Name|Type|Description|
|---:|---|---|
|[condition](Conditions.md#conditions)|List<int\[\]>|The list of condition applied. Each element is an array of 2 elements, the first being the `BattleCondition` id and the second being the amount of actor turns it is in effect|
|freezeres|int|The [Freeze](BattleCondition/Freeze.md) resistance|
|poisonres|int|The [Poison](BattleCondition/Poison.md) resistance|
|numbres|int|The [Numb](BattleCondition/Numb.md) resistance|
|sleepres|int|The [Sleep](BattleCondition/Sleep.md) resistance|
|isasleep|bool|Tells if the actor has a [Sleep](BattleCondition/Sleep.md) condition, updated at multiple places|
|isnumb|bool|Tells if the actor has a [Numb](BattleCondition/Numb.md) condition, updated at multiple places|
|frozenlastturn|bool|Tells if the actor still had the [Freeze](BattleCondition/Freeze.md) condition after their last actor turn advance via [AdvanceTurnEntity](../Battle%20flow/AdvanceTurnEntity.md)|
|atkdownonloseatkup|bool|If true, the actor will get an [AttackDown](BattleCondition/AttackDown.md) condition inflicted the next time an [AttackUp](BattleCondition/AttackUp.md) condition runs out of main turns|
### Damage modifiers
|Name|Type|Description|
|---:|---|---|
|tired|int|The amount of exhaustion cumulated which have an impact in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md)|
|charge|int|The amount of charges cumulated which have an impact in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md)|
### [Item](../../Enums%20and%20IDs/Items.md) holding
|Name|Type|Description|
|---:|---|---|
|holditem|int|The [item](../../Enums%20and%20IDs/Items.md) id the actor is holding. Defaults to -1 which is no item held. For enemy party members, see the [holditem](Enemy%20features.md#holditem-and-helditem) feature documentation|
|helditem|SpriteRenderer|The `sprite` of the [item](../../Enums%20and%20IDs/Items.md) held by the actor whose id is `holditem`||cursoroffset|Vector3|The offset to apply to the cursor when selecting this actor|
|itemoffset|Vector3|The offset to render the item relative to the entity|
### Alive and death turn tracking
|Name|Type|Description|
|---:|---|---|
|turnssincedeath|int|The amount of main turns since death, 0 if the actor is alive|
|turnsalive|int|The amount of main turns since the battle started or their last death if any occured|
## Unused fields
These fields are never referenced or never used in any meaningful ways.
|Name|Type|Description|
|---:|---|---|
|tiredpart|ParticleSystem|UNUSED|
|noblock|bool|UNUSED|
|pointer|int|UNUSED, This field is maintained to be the same value as `partypointer`, but by indexing `playerdata` instead. This means that `playerdata[X].pointer` is the same than `partypointer[X]` where `X` is a valid `playerdata` index. In practice, this field is only written into making it unused|
|turnsnodamage|int|UNUSED|
|hardhp|int|UNUSED|
|harddef|int|UNUSED|
|lv|int|UNUSED|
|id|int|UNUSED (only read from [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md), but never written to so it stays at 0)|
|noexpatstart|bool|UNUSED (intended for enemy party members only, only read during damage pipeline, but never written to so it always have the value false)|

View File

@@ -0,0 +1,12 @@
# BattlePosition
This is an enum that influences the ability for an enemy party member to be targetted in battle. It can be thought of as the logical position of the enemy party member.
On [BattleData](BattleData.md), the position of the enemy party member is stored in the `position` field.
|Value|Name|Description|
|-----|----|-----------|
|0|Ground|The enemy party member is grounded and a [GetAvaliableTargets](Targetting/GetAvaliableTargets.md) call with onlyground to true will include the target. This is also the position when the battleentity.`height` isn't above `minheight` + 0.5|
|1|Flying|The enemy party member isn't grounded and a [GetAvaliableTargets](Targetting/GetAvaliableTargets.md) call with onlyground to true will exclude the target. This is also the position when the battleentity.`height` is above `minheight` + 0.5. Depending on many factors such as [cantfall](Enemy%20features.md#cantfall) or having a topple [weakness](Enemy%20features.md#weakness), the enemy party member may be subject to a [Drop](../../Entities/EntityControl/Notable%20methods/Drop.md) during [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md)|
|2|OutOfReach|The enemy party member cannot be targeted and [GetAvaliableTargets](Targetting/GetAvaliableTargets.md) will always exclude it|
|3|Random|A value only used during [GetEnemyData](../../TextAsset%20Data/Enemies%20data.md#getenemydata) where the position will get changed to `Ground` or `Flying` so this value is never used in battle, only during data loading|
|4|Underground|The enemy party member is underground which imposes restrictions for the target to be included in [GetAvaliableTargets](Targetting/GetAvaliableTargets.md) and for using [items](../../Enums%20and%20IDs/Items.md)|

View File

@@ -0,0 +1,16 @@
# CenterPos
A method that returns an intuitive center position to render effects on an actor, but can also be used for logic involving the positions of actors.
```cs
private Vector3 CenterPos(MainManager.BattleData entity, bool world)
```
## Parameters
- `entity`: The actor to get the center position of
- `world`: Whether or not to add `entity`.battleentity's position to the final result
### Procedure
- If the actor's `position` is `Underground`, return Vector3.up with entity.battleentity's position added if world is true
- Otherwise, return entity.`cursoroffset` + (0.0, entity.battleentity.`height` - 1.0, 0.0) with entity.battleentity's position added if world is true

View File

@@ -0,0 +1,18 @@
# ClearStatus
This method will clear almost all [conditions](../Conditions.md) off an actor. The actor's [BattleData](../BattleData.md) is received as a ref to allow to reset the entire `condition` list.
Before resetting the `conditions` list, `isnumb`, `isasleep` and [isdefending](../Enemy%20features.md#isdefending) are all set to false.
The method then resets the `condition` list by removing everything except any of the following:
- [EventStop](../BattleCondition/EventStop.md)
- [Eaten](../BattleCondition/Eaten.md)
- [Flipped](../BattleCondition/Flipped.md)
- [Taunted](../BattleCondition/Taunted.md)
- Any condition whose turn count is above 99 (which only happens if the game manually placed it with the intent of being practically infinite), but this doesn't apply to [Poison](../BattleCondition/Poison.md) (meaning the condition inflicted as a result of the `EternalPoison` [medal](../../../Enums%20and%20IDs/Medal.md#medal--badge) is removed despite this exception)
After the reset:
- battleentity.`shieldenabled` is set to false
- `charge` is set to 0
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)

View File

@@ -0,0 +1,22 @@
# HasCondition
This methods checks the presence of a [condition](../Conditions.md) and returns the amount of actor turns left on it if it exist or -1 if it doesn't. It belongs to MainManager. This is the main way to check the presence of any conditions in the battle system.
```cs
public static int HasCondition(BattleCondition condition, BattleData entity)
```
### Parameters
- `condition`: The `BattleCondition` to check the presence of
- `entity`: The actor to check the condition for
### Procedure
The method goes over all `condition` elements of entity and if one is found with the condition sent, true is returned, false otherwise.
There is a side effect to this method: if the actor has the [Sleep](../BattleCondition/Sleep.md) condition, it may set its `isasleep` to true. Here is all the circumstances that will have that happen:
- [Sleep](../BattleCondition/Sleep.md) was sent in as the condition
- We aren't looking for `Sleep`, but the condition we are looking for occurs after a `Sleep` one
- We are looking for a condition that doesn't exist
This means that it is possible to have `isasleep` not be set to true if we are looking for a condition that occurs before a [Sleep](../BattleCondition/Sleep.md) one. In that case, the method returns true without leaving a chance for `isasleep` to be set to true. In practice however, this doesn't cause any problems.

View File

@@ -0,0 +1,9 @@
# HealConditions
A method that receives an actor's [BattleData](../BattleData.md) as ref and does the following:
- Calls [RemoveCondition](RemoveCondition.md) with the [Freeze](../BattleCondition/Freeze.md) condition on the actor
- Calls [RemoveCondition](RemoveCondition.md) with the [Poison](../BattleCondition/Poison.md) condition on the actor
- Calls [RemoveCondition](RemoveCondition.md) with the [Numb](../BattleCondition/Numb.md) condition on the actor
- Calls [RemoveCondition](RemoveCondition.md) with the [Numb](../BattleCondition/Numb.md) condition on the actor (it is done a second time)
- Set the actor's `isasleep` to false
- Set the actor's `isnumb` to false

View File

@@ -0,0 +1,22 @@
# RemoveCondition
This method removes a [condition](../Conditions.md) and also perform the associated side effects involved with removing it. It belongs to MainManager.
NOTE: If multiple occurences of the condition exists, only the first one is removed.
```cs
public static void RemoveCondition(BattleCondition condition, BattleData entity)
```
## Parameters
- `condition`: The condition to remove if it exists
- `entity`: The actor to remove the condition from
## Procedure
The condition is searched and if it's not found, nothing happens.
If it's found, some specific `BattleCondition` has a side effect for its removal that will be performed:
- [Numb](../BattleCondition/Numb.md) or [Sleep](../BattleCondition/Sleep.md): RefreshCondition is called on the actor's battleentity which updates the actor's `isasleep` and `isnumb` fields according to an [HasCondition](HasCondition.md) call for [Numb](../BattleCondition/Numb.md) and [Sleep](../BattleCondition/Sleep.md) respectively.
- [Freeze](../BattleCondition/Freeze.md): The actor's entity (not its battleentity) has [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#breakice) called on it. NOTE: This is technically wrong because it calls the method on the overworld entity instead of the battle one, but this will effectively not do anything destructive since the `icecube` of the entity is null. It however means that the caller is instead responsible for calling the method correctly which the game does in every circumstances under normal gameplay.

View File

@@ -0,0 +1,80 @@
# SetCondition
This method is the prefered way to add or amend an existing [condition](../Conditions.md). The vast majority of conditions are inflicted or amended using this method with some narrow exceptions. It belongs to MainManager.
```cs
public static void SetCondition(BattleCondition condition, ref BattleData entity, int turns, int fromplayer)
```
### Parameters
- `condition`: The condition to add/amend
- `entity`: The actor to apply the condition
- `turns`: The amount of main turns to set/amend the condition
- `fromplayer`: UNUSED (there is an overload without it that sends -1)
### Adding a condition
Adding a new condition is a simpler operation as it will be added regardless of the resistance to said condition with only some conditions having special effects. This means that for adding a condition, the caller is responsible for verifying the resistence check.
Here are all the special effects for adding a condition (if the actor's battleentity has a `Player` tag, it is assumed to be a player party member, it is assumed to be an enemy party member otherwise):
|Condition|Additional effect|
|--------:|-----------------|
|Shield|battleentity.`shieldenabled` is set to true. Also, If it's a player party member, the turn amount of the condition is set to 1|
|Poison|If it's a player party member with a `EternalPoison` [medal](../../../Enums%20and%20IDs/Medal.md) equipped, the turn amount of the condition is set to 99999|
|Freeze|If it's not a player party member while [isdefending](../Enemy%20features.md#isdefending) is true, it is set to false|
|Numb|If it's not a player party member while [isdefending](../Enemy%20features.md#isdefending) is true, it is set to false. Also, `isnumb` is set to true|
|Sleep|If it's not a player party member while [isdefending](../Enemy%20features.md#isdefending) is true, it is set to false|
|Any other conditions|None|
After the condition has been added, Abs is done on its actor turn amount forcing the amount to not be negative.
### Amending a condition
Amending a condition requires the requested turns value to be above 0.
If the turns value is negative, there's a different requirement and it is passing a ressitance test for the following conditions (it always pass for any other):
- [Freeze](../BattleCondition/Freeze.md): uses `freezeres`
- [Numb](../BattleCondition/Numb.md): uses `numbres`
- [Poison](../BattleCondition/Poison.md): uses `poisonres`
- [Sleep](../BattleCondition/Sleep.md): uses `sleepres`
The test is performed by generating a number between 0.0 and 100.0 inclusive. For the test to pass, the number bust be strictly above the corresponding resistance. If the test fails, the condition won't be amended.
#### Problems with the resistance test
However, this negative turns resistance test is in practice UNUSED and broken. The UNUSED part is because the only time SetCondition is called with a negative turns is when processing certain [item](../../../Enums%20and%20IDs/Items.md)'s [effects](../../../TextAsset%20Data/Items%20data.md):
- `ShavedIce` (its `AddFreeze`)
- `HoneyIceCream` (its `AddFreeze`)
- `IceCream` (its `AddFreeze`)
- `FrozenSalad` (its `AddFreeze`)
- `FrostPie` (its `AddFreeze`)
- `DrowsyCake` (its `AddPoison`)
But DoItemEffect won't actually allow the SetCondition call for these effects if any of the appropriate resistance [medals](../../../Enums%20and%20IDs/Medal.md) are equipped and it turns out this is the only way in practice to increase the resistance fields of a player party member. What this means is in any cases, even if the turns count was negative, the test always passes. This only matters if a negative turns value is passed to SetCondition in other cases than DoItemEffect outside of normal gameplay.
But if it does, there's several problems where the logic is incorrect. Most of the issues is this resistance test differs greatly from [CalculateBaseDamage](../../Damage%20pipeline/CalculateBaseDamage.md) because ONLY the resistance check is performed while the damage pipeline performs several other checks.
It is speculated that this feature was left unfinished as an older attempt of implementing user infliction and it can be considered broken in its current state. While the game can run into it with some specific item use, in practice, it doesn't do anything of note by coincidence. Still, in essence, negative turns amount should be considered invalid.
#### When turns is above 0 or the negative turns test pass
If the requirements are met, the condition will be amended, but how this occurs depends on the condition itself. Some may allow stacking the actor turns, some conditionally and some never. Also, some conditions implicates special side effects.
The following table summarises the logic for all conditions (stacking means increasing the existing actor turn amount by the requested one unless otherwise specified and not stacking means to set the amount to the requested one unless otherwise specified):
|Condition|Stacked for a `Player`?|Stacked for a non `Player`?|Other effects|
|--------:|----------------------|---------------------------|------------|
|[AttackUp](../BattleCondition/AttackUp.md)|Yes|Yes|None|
|[DefenseUp](../BattleCondition/DefenseUp.md)|Yes|Yes|None|
|[AttackDown](../BattleCondition/AttackDown.md)|Yes|Yes|None|
|[DefenseDown](../BattleCondition/DefenseDown.md)|Yes|Yes|None|
|[GradualHP](../BattleCondition/GradualHP.md)|Yes|Yes|None|
|[GradualTP](../BattleCondition/GradualTP.md)|Yes|Yes|None|
|[Fire](../BattleCondition/Fire.md)|Yes (by half the requested amount of actor turns ceiled)|Yes (by half the requested amount of actor turns ceiled)|None|
|[poison](../BattleCondition/Poison.md)|Yes if it has the `EternalPoison` [medal](../../../Enums%20and%20IDs/Medal.md) equipped which makes it set to 99999 regardless of the requested amount of actor turns|Yes|None|
|[Freeze](../BattleCondition/Freeze.md)|Only if [currentchoice](../../Player%20UI/Actions.md) is `Item` (meaning the player party used an item on itself), the condition isn't amended if it already had the requested amount of actor turns or more|No|For an enemy party member, [isdefending](../Enemy%20features.md#isdefending) is set to false|
|[Numb](../BattleCondition/Numb.md)|Only if [currentchoice](../../Player%20UI/Actions.md) is `Item` (meaning the player party used an item on itself), the condition isn't amended if it already had the requested amount of actor turns or more|No|For an enemy party member, [isdefending](../Enemy%20features.md#isdefending) is set to false. Also, `isnumb` is set to true|
|[Sleep](../BattleCondition/Sleep.md)|Only if [currentchoice](../../Player%20UI/Actions.md) is `Item` (meaning the player party used an item on itself), the condition isn't amended if it already had the requested amount of actor turns or more|No|For an enemy party member, [isdefending](../Enemy%20features.md#isdefending) is set to false|
|[Shield](../BattleCondition/Shield.md)|No, the turn amount is always set to 1 regardless of the requested one|No|battleentity.`shieldenabled` is set to true|
|Any other conditions|No|No|None|
After the condition has been amended, its turn amount is clamped from 0 to 999999.

View File

@@ -0,0 +1,41 @@
# StatusEffect
This method is kind of a wrapper around [SetCondition](SetCondition.md) because it does end up calling it after a resistance check if applicable, but it also renders visually the [conditions](../Conditions.md) being applied by a colored arrow thanks to [StatEffect](../../Visual%20rendering/StatEffect.md).
```cs
private void StatusEffect(MainManager.BattleData data, MainManager.BattleCondition status, int turns, bool effect)
```
### Parameters
- `data`: The actor to attempt to inflict the condition
- `status`: The condition to attempt to inflict the actor
- `turns`: The amount of actor turns to inflict the condition
- `effect`: Whether the infliction should include a visual render. There is an overload where this can be ommited and it will send false
### Procedure
If applicable, a resistence check will be performed. The test will be performed by generating a random integer in the range \[0, 100\[ and check if the number is strictly higher than the matching resistance. However, if the resistance is 100 or above, the test always fails.
> NOTE: this test is off by one numerically: a 50 resistance actually means a 49% change to inflict for example. This is because doing a strictly higher than comparison splits the ranges like such that the fail group is \[0, resistance\] and the success group is \]resistance, 100\[, but they should be split to \[0, resistance\[ and \[resistance, 100\[ respectively. This means for a given resistance, the chance to inflict in percentage is 100 - resistance - 1 instead of 100 - resistance.
Here are the statuses where the test is applicable and which resistance will be used for each:
- [Freeze](../BattleCondition/Freeze.md): `freezeres`
- [Numb](../BattleCondition/Numb.md): `numbres`
- [Poison](../BattleCondition/Poison.md): `poisonres`
- [Sleep](../BattleCondition/Sleep.md): `sleepres`
If the test fails, nothing happens and a return happens immediately.
If it succeeds, [SetCondition](SetCondition.md) is called with the actor, condition and amount of actor turns.
The method is done if effect is false.
If it's true, a [StatEffect](../../Visual%20rendering/StatEffect.md) coroutine will be started if applicable with a type followed by a certain sound being played if it wasn't already depending on the condition.
Here are the conditions and how the visual effect is done (other conditions don't have visual effects):
- [AttackUp](../BattleCondition/AttackUp.md): Type 0 with the `StatUp` sound
- [AttackDown](../BattleCondition/AttackDown.md): Type 2 with the `StatDown` sound
- [DefenseUp](../BattleCondition/DefenseUp.md): Type 1 with the `StatUp` sound
- [DefenseDown](../BattleCondition/DefenseDown.md): Type 3 with the `StatDown` sound

View File

@@ -0,0 +1,47 @@
# Conditions
A condition is a temporary effect applied for a limited amount of main turns on an actor. They are tracked in the actor's `condition` array.
A `condition` element contains an int\[\] of 2 elements:
- 0: The BattleCondition (in int form) representing the kind of effects this condition involves
- 1: The amount of actor turns left for the effects to apply. 0 and below values are technically allowed, but frequently causes the whole condition to be removed and they are not considered to be present in the actor
It is considered invalid to have duplicate conditions in the list. An existing condition should be amended if it exist already instead of adding a new element to the list.
Some conditions are tested for resistance before being added to `condition`. This usually involves the actor's resistance compared to a random number with immunity starting at a resistance of 100 and a certainty of infliction being 0 with everything in between being (100 - resistance) / 100 chance to inflict. The presence of this test, its methodology and its accuracy (not all have the correct odds) depends on the specific method used to add the condition.
Conditions are used heavily throughout the battle system and even come with a set of utility methods to inflict / amend one, check the presence of one and remove one. Here are links to learn more about these methods:
- MainManager.[SetCondition](Conditions%20methods/SetCondition.md)
- [StatusEffect](Conditions%20methods/StatusEffect.md)
- MainManager.[HasCondition](Conditions%20methods/HasCondition.md)
- MainManager.[RemoveCondition](Conditions%20methods/RemoveCondition.md)
- [HealCondition](Conditions%20methods/HealConditions.md)
- [ClearStatus](Conditions%20methods/ClearStatus.md)
## BattleCondition table
Here are the different BattleCondition that exists in the game and a summary of what they do (with links to further documentations):
|ID|Name|Summary|
|-:|----|-------|
|0|[Freeze](BattleCondition/Freeze.md)|A stopping condition that encases the actor in a block of ice. Most attacks will remove this condition and thaw out the ice, but with a +1 damage to the attack. It also allows the target to process a `FrostBite` [medal](../../Enums%20and%20IDs/Medal.md) when attacked|
|1|[Poison](BattleCondition/Poison.md)|A condition that either deals non lethal damage or heals the actor each actor turn depending on if they have a `ReversePoison` [medal](../../Enums%20and%20IDs/Medal.md) or not. It also allows several poison specific medals to take effect|
|2|[Numb](BattleCondition/Numb.md)|A stopping condition that gives the actor a point of defense (with caveats, see [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) documentation for details). It also allows the target to process a `ShockTrooper` [medal](../../Enums%20and%20IDs/Medal.md) which can bypass damage calculation|
|3|[Sleep](BattleCondition/Sleep.md)|A stopping condition that will heal the attacker on each actor turn and be removed on most attacks due to waking up (with caveats, see [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) documentation for details). It also allows the target to process a `HeavySleeper` [medal](../../Enums%20and%20IDs/Medal.md) which can prevent waking up, halve the damage amount and heal for more per actor turn|
|4|[AttackUp](BattleCondition/AttackUp.md)|A condition that gives a +1 damage bonus on attacks by the actor while it is active when the [AttackProperty](../Damage%20pipeline/AttackProperty.md) isn't `NoExceptions`|
|5|[DefenseUp](BattleCondition/DefenseUp.md)|A condition that gives a -1 damage on attacks to the actor as a point of defense recognised by [TrueDef](../Visual%20rendering/RefreshEnemyHP.md#truedef) while the condition is active and property isn't `NoExceptions` NOTE: This has several caveats, check the [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) documentation to learn more|
|6|[AttackDown](BattleCondition/AttackDown.md)|A condition that gives a -1 damage malus on attacks by the actor while it is active when the [AttackProperty](../Damage%20pipeline/AttackProperty.md) isn't `NoExceptions`|
|7|[DefenseDown](BattleCondition/DefenseDown.md)|A condition that removes a point of defense recognised by [TrueDef](../Visual%20rendering/RefreshEnemyHP.md#truedef) which can result in a +1 damage effects while it is active when the [AttackProperty](../Damage%20pipeline/AttackProperty.md) isn't `NoExceptions`. NOTE: This has several caveats, check the [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) documentation to learn more|
|8|[Topple](BattleCondition/Topple.md)|A 1 hit defensive mechanism in the form of a condition for an enemy party member where if it has a `ToppleFirst` or `ToppleAirOnly` (if their `position` is `Flying`) [weakness](../Damage%20pipeline/AttackProperty.md) it won't get dropped or [Flipped](BattleCondition/Flipped.md) immediately when it was supposed to otherwise. Instead, this condition will be inflicted without the drop or flip featuring a `Woobly` [animstate](../../Entities/EntityControl/Animations/animstate.md) and it will be removed after most attacks which allows the drop or flip to occur on any subsequent hit|
|9|[Flipped](BattleCondition/Flipped.md)|An ephemeral condition specific to enemy party members that is only inflicted with a `Flip` [AttackProperty](../Damage%20pipeline/AttackProperty.md) to an enemy party member with a `Flip` [weakness](../Damage%20pipeline/AttackProperty.md). It causes all the enemy party member's `def` to be ignored during damage calculation which is recognised by [TrueDef](../Visual%20rendering/RefreshEnemyHP.md). This process can be hampered by [Topple](BattleCondition/Topple.md)'s defense mechanism if it applies. NOTE: The condition logic has caveats, check the [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) documentation to learn more|
|10|[Shield](BattleCondition/Shield.md)|A condition that encases the acotr in a shield by controlling its battleentity.`shieldenabled` which allows it to bypass damage calculation and not loose its `plating`|
|11|[Taunted](BattleCondition/Taunted.md)|A condition that prevents a player party member from selecting the `Skill`, `Item` and `Relay` vine menu [Actions](../Player%20UI/Actions.md) and prevents other player party member from relaying to them|
|12|[Sturdy](BattleCondition/Sturdy.md)|A condition that prevents other conditions from being inflicted (even through using an [item](../../Enums%20and%20IDs/Items.md)) while also getting a -3 damage effect applied in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) at the expense that the actor cannot be relayed to|
|13|[GradualHP](BattleCondition/GradualHP.md)|A condition that increases the actor's `hp` by 2 (clamped from 0 to `maxhp`) every actor turn while active|
|14|[GradualTP](BattleCondition/GradualTP.md)|A condition that increases instance.`tp` by 2 (clamped from 0 to instance.`maxtp`) every actor turn while active|
|15|[Eaten](BattleCondition/Eaten.md)|A special stopping condition specific to the `Pitcher` [enemy](../../Enums%20and%20IDs/Enemies.md) that allows through unorthodox methods to treat a player party member as if they were dead alongside having their `eatenby` not null|
|16|[EventStop](BattleCondition/EventStop.md)|A stop condition specifically made for [event](../../Enums%20and%20IDs/Events.md) 182 (trying to exit the room after approaching the tank in the last room of Upper Snakemouth) that simply disables a party member until it is manually removed (it is not meant to expire naturally)|
|17|[Fire](BattleCondition/Fire.md)|A condition that deals non lethal damage (more than [Poison](BattleCondition/Poison.md)) every actor turn while it is active that may be inflicted in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) if property is `Fire` (without a resistance field) featuring a `Prefabs/Particles/Flame` as a `firepart`|
|18|[Inked](BattleCondition/Inked.md)|A condition that prevents a player party member from using a [skill](../../Enums%20and%20IDs/Skills.md) that may be inflicted in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) if property is `Ink` or `InkOnBlock` (without a resistance field) featuring a `Prefabs/Particles/InkDrip` as a `firepart`|
|19|[Sticky](BattleCondition/Sticky.md)|A condition that prevents a player party member from using an [item](../../Enums%20and%20IDs/Items.md) that may be inflicted in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) if property is `Sticky` (without a resistance field) featuring a `Prefabs/Particles/StickyDrip` as a `firepart`|
|20|[Reflection](BattleCondition/Reflection.md)|A condition that causes a player party member to sustain less damage from [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) with the reduction amount being the amount of `Reflection` [medal](../../Enums%20and%20IDs/Medal.md) equipped. It always expire on the next actor turn, but the turn counter is used to visually show the amount of the damage reduction|

View File

@@ -0,0 +1,47 @@
# Delayed condition
A delayed condition is a [condition](Conditions.md) placed on an enemy party member that whose infliction attempt occurs during the [post action](../Battle%20flow/Action%20coroutines/DoAction.md#post-action) phase of [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md) when the actionid isn't -555 (a dummy value to perform a blank call), it's an enemy action that didn't cause them to flee and it didn't cause them to kill themselves (`selfsacrifice` is false).
NOTE: Only [Freeze](BattleCondition/Freeze.md), [Numb](BattleCondition/Numb.md) and [Sleep](BattleCondition/Sleep.md) are supported because they are the only ones that gets processed.
The list of them is tracked in the `delayedcondition` field of the enemy party member and are ephemeral in nature: once processed, they are removed so they are only valid per action.
## AddDelayedCondition
Adding a delayed condition involves calling the AddDelayedCondition method.
```cs
private void AddDelayedCondition(int enid, MainManager.BattleCondition cond)
```
enid is the `enemydata` index and `cond` is the condition to add to the corresponding `delayedcondition` list. The method will ensure the list isn't null and if the condition didn't already exist (duplicates aren't allowed), it will be added.
Specifically, if a [Freeze](BattleCondition/Freeze.md) condition is added via this method, the `frostbitep` of the enemy party member is initialised to be the ParticleSystem of a new instance of the `Prefabs/Particles/Snowflakes` prefab childed to the battleentity and with a local position of the enemy party member's non world [CenterPos](CenterPos.md#centerpos).
## Delayed conditions's processing
As mentioned above, they are processed during the post action phase of DoAction for the enemy party member that was performing its action. Only [Freeze](BattleCondition/Freeze.md), [Numb](BattleCondition/Numb.md) and [Sleep](BattleCondition/Sleep.md) are supported.
### `Freeze` processing
- `frostbitep` position is set offscreen at (0.0, 999.0, 0.0)
- `frostbitep` is destroyed in 3.0 seconds
- The rest depends on the `freezeres`:
- If it's 100 or above (it's immune), the `IceShatter` particles are played at the enemy party member's world's [CenterPos](CenterPos.md) and the condition isn't inflicted
- Otherwise (it's not immune):
- [Freeze](../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#freeze) is called on the entity
- `mothicenormal` particles are played without sound at the enemy party member's world's [CenterPos](CenterPos.md) with a scale of (1.5, 1.5, 1.5)
- [SetCondition](Conditions%20methods/SetCondition.md) is called with the `Freeze` condition on the enemy party member for 3 turns
### `Numb` processing
There's only logic if the `numbres` is below 100 (it's not immune). If it is:
- The `Numb` sound is played
- [SetCondition](Conditions%20methods/SetCondition.md) is called with the `Numb` condition on the enemy party member for 2 turns
- `isnumb` is set to true
### `Sleep` processing
There's only logic if the `sleepres` is below 100 (it's not immune). If it is:
- The `Sleep` sound is played
- DeathSmoke particles are played at the world's [CenterPos](CenterPos.md) of the enemy party member with a size of (2.0, 2.0, 2.0)
- [SetCondition](Conditions%20methods/SetCondition.md) is called with the `Numb` condition on the enemy party member for 2 turns
- `isasleep` is set to true
- battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is set to 14 (`Sleep`)

View File

@@ -0,0 +1,76 @@
# Delayed projectile
A delayed projectile, also known as a delproj, is a projectile an enemy can launch, but that will only land on a player party member after a predetermined amount of main turns passed. The projecile will cause damage with an optional property attached. The visual and audio effects are all configurable.
The delprojs currently scheduled are tracked by the `delprojs` field which is an array of `DelayedProjectileData`, a struct documented in the section below. The actual logic of the delprojs are defined in [AdvanceMainTurn](../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md#delprojs-advance) with their main turn advances done very early in the coroutine.
## DelayedProjectileData
This struct defines the entirety of a delproj, here are all the fields and their semantics:
|Name|Type|Description|
|----|----|-----------|
|turns|int|Amount of main turns left before the projectile lands|
|damage|int|The amount of damage to deal to the target|
|position|int|The player party member position to target|
|areadamage|int|UNUSED|
|framestep|float|The amount of frames to move the projectile before landing completely|
|obj|GameObject|The projectile object|
|deathparticle|string|A `Resources/prefabs/particles` name that will play when the projectile fully lands|
|deathsound|string|A `Resources/audio/sounds` audio clip's name that will play when the projectile fully lands|
|whilesound|string|A `Resources/audio/sounds` audio clip's name that will be play while the projectile is landing on loop. For the clip to play only once instead of looping, the name needs to be prepended by `@`|
|args|string|`@` separated strings containing optional configurations, see the section below for details|
|calledby|MainManager.BattleData|UNUSED|
|property|[AttackProperty](../Damage%20pipeline/AttackProperty.md)?|The property of the damage dealt (null means no property applies)|
### `args` field
The `args` of the `DelayedProjectileData` are a list of commands which is `@` separated while each command is a list of string that is `,` separated.
Each command's first element is the name of the command while every strings after are parameters. Here is a table that shows all the vailable commands, their parameters meaning if any and the overall effect of the commmand if applied:
|Name|Parameters|Description|
|---:|------|-----------|
|partoff|First 3 params are float forming a Vector3|Offsets the `deathparticle` position to play by the Vector3 in parameters relative to the `obj` position upon landing|
|move|First 3 params are float forming a Vector3|Offsets the position to land on by the Vector3 in parameters relative to the `partypos` of the delproj's `position`|
|noshadow|None|Prevent a ShadowLite to be added to the delproj's `obj`|
## Delprojs methods
To manage delprojs, there are 2 methods that exists that allows to add or remove them:
- AddDelayedProjectile
- RemoveDelayedProjectile
Both methods converts the array to list, performs the necessary modifications and then converts the list back to array and assigns it to `delprojs`.
The sections below details the methods's signatures and parameters details.
### AddDelayedProjectile
Adds a delproj to `delprojs` with all the parameters needed to initialise one.
```cs
private void AddDelayedProjectile(GameObject obj, int targetpos, int damage, int turnstohit, int areadamage, AttackProperty? property, float framespeed, MainManager.BattleData summonedby, string hitsound, string hitparticle, string whilesound)
```
#### Parameters
Each parameters directly maps to a field in `DelayedProjectileData` of the delproj to add. Here is the mapping:
- `obj`: `obj`
- `targetpos`: `position`
- `damage`: `damage`
- `turnstohit`: The value + 1 is mapped to `turns` (this is because the main turn that the projectile is fired is excluded from `turns` so the first [AdvanceMainTurn](../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) will remove it after its launch and the [enemy phase](../Battle%20flow/Main%20turn%20life%20cycle.md#enemy-phase) is done)
- `areadamage`: `areadamage` (this field is UNUSED because it is never read)
- `property`: `property`
- `framespeed`: `framestep`
- `summonedby`: `calledby` (this field is UNUSED because it is never read)
- `hitsound`: `deathsound`
- `hitparticle`: `deathparticle`
- `whilesound`: `whilesound`
### RemoveDelayedProjectile
Removes an existing delproj from `delprojs` by its array index.
```cs
private void RemoveDelayedProjectile(int arraypos)
```
#### Parameters
- `arraypos`: The `delprojs` array index to remove the delproj from the array

View File

@@ -0,0 +1,187 @@
# Enemy features
Certain [enemies](../../Enums%20and%20IDs/Enemies.md) can opt in to some features by having some of their [enemy data](../../TextAsset%20Data/Enemies%20data.md) fields setup in a certain way or simply in their [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md)'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](../Battle%20flow/EventDialogue.md) when the enemy party member dies.
If the value isn't -1 and the enemy party member was detected dead (without `flee`) by [CheckDead](../Battle%20flow/Action%20coroutines/CheckDead.md) while `inevent` is false, an [EventDialogue](../Battle%20flow/EventDialogue.md) whose id is the `eventondeath` will be triggered.
## `eventonfall`
This feature allows to trigger an [EventDialogue](../Battle%20flow/EventDialogue.md) when the enemy party member drops.
When set to any non negative value, whenever [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) 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](../Battle%20flow/Update%20flows/Controlled%20flow.md), the [EventDialogue](../Battle%20flow/EventDialogue.md) whose id was `eventonfall` will be triggered.
## `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](../Battle%20flow/AdvanceTurnEntity.md) of the enemy party member, unless there is a specific [condition](Conditions.md) 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](../../Entities/EntityControl/Notable%20methods/Death.md). It maps to a [DestroyType](../../Entities/EntityControl/Notable%20methods/Death.md#the-destroy) 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](../Battle%20flow/Action%20coroutines/CheckDead.md) 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](../Damage%20pipeline/DoDamage.md) after sustaining lethal damage and it ends by setting the battleentity's tag to `DestroyTurn` which destroys it on the next [AdvanceMainTurn](../Battle%20flow/AdvanceTurnEntity.md). It is very specific to the following [enemies](../../Enums%20and%20IDs/Enemies.md):
- `KeyR`
- `KeyL`
- `Tablet`
## Difficulty scaling
This feature is documented extensively in the appropriate [section](../../TextAsset%20Data/Enemies%20data.md#stats-difficulty-scaling) 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](../../TextAsset%20Data/Enemies%20data.md#exp-logic) 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](../../Enums%20and%20IDs/Items.md). `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](Enemy%20party%20members/DropItem.md).
## `hitaction`
This field tells if an enemy wants to performa an action immediately on the next [controlled flow](../Battle%20flow/Update%20flows/Controlled%20flow.md) update. These actions are performed out of the main turn flow because they are ran during the [player phase](../Battle%20flow/Main%20turn%20life%20cycle.md#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](../Battle%20flow/Update.md), 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](IsStopped.md) returns true, their `hitaction` gets set to false and nothing happens as it gets skipped
- Otherwise, `enemy` is set to true and a [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md) 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](../Battle%20flow/Action%20coroutines/DoAction.md). 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](../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-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](../Damage%20pipeline/DoDamage.md) 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](../Battle%20flow/Main%20turn%20life%20cycle.md#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](BattlePosition.md) is `Flying`
- If it's 3, it's only fufilled if target.[position](BattlePosition.md) 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](../Damage%20pipeline/DoDamage.md), 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](../../Enums%20and%20IDs/Enemies.md) ids.
How it works is when the target sustains the damage, every other enemy party members who has the target.`animid` (their [enemy](../../Enums%20and%20IDs/Enemies.md) id) in their `chargeonotherenemy` has their `hitaction` set to !`enemy` (false during the [enemy phase](../Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase), true during the [player phase](../Battle%20flow/Main%20turn%20life%20cycle.md#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](../Damage%20pipeline/DoDamage.md). That was is by having `isdefending` be -1 and the [position](BattlePosition.md) 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](../../Enums%20and%20IDs/Enemies.md) 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](../Damage%20pipeline/CalculateBaseDamage.md) when piercing doesn't apply with the amount corresponding to the value and those defense points are recognised by [TrueDef](../Visual%20rendering/RefreshEnemyHP.md#truedef). They will apply when `isdefending` is true unless the enemy party member is [Flipped](BattleCondition/Flipped.md). This also enables `isdefending`'s toggling during [DoDamage](../Damage%20pipeline/DoDamage.md) (See the section below for more details). NOTE: There are several caveats with this, check the [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) 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](../StartBattle.md).
Guarding is the only way to gain the `defenseonhit` points of defenses and the main way it's done is by [DoDamage](../Damage%20pipeline/DoDamage.md) 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](IsStopped.md) is false (if it's true, `isdefending` is set to false instead which breaks guard)
It's also possible to manually guard from [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md)'s action logic.
The guarding is visually represented by having [UpdateAnim](../Visual%20rendering/UpdateAnim.md) 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](Conditions%20methods/SetCondition.md): When inflicting (or amending) a [Freeze](BattleCondition/Freeze.md), [Numb](BattleCondition/Numb.md) or [Sleep](BattleCondition/Sleep.md) condition
- [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md): When hit with an attack that has a `Flip` property, guard is broken
- [ClearStatus](Conditions%20methods/ClearStatus.md): Breaking guard is part of the procedure of this method
- [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md): 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](BattleCondition/Freeze.md) 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](../Battle%20flow/Action%20coroutines/DoAction.md)'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](../../Entities/EntityControl/Notable%20methods/CheckSpecialID.md) for a `BeeBot` [animid](../../Enums%20and%20IDs/AnimIDs.md) 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](../Battle%20flow/Action%20coroutines/DoAction.md)'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](../Damage%20pipeline/AttackProperty.md) that can change the damage pipeline, especially during [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md).
## `cantfall`
When this field is true, it will never be dropped by [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) when its [position](BattlePosition.md) is `Flying`.
It will also prevent having its [position](BattlePosition.md) set to `Ground` by RefreshEnemyPos (used by [GetAvailableTargets](Targetting/GetAvaliableTargets.md) or [Chompy](../Battle%20flow/Action%20coroutines/Chompy.md)).
`lockposition` is a field that does the same logic in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) specifically, but it doesn't require the [position](BattlePosition.md) to be `Flying`. It doesn't include the other logic `cantfall` has.
## `notaunt`
When this field is true, it specifically affects the `BeetleTaunt` [skill](../../Enums%20and%20IDs/Skills.md) by preventing the [Taunted](BattleCondition/Taunted.md) 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](Conditions%20methods/SetCondition.md) calls which is still desired for [enemies](../../Enums%20and%20IDs/Enemies.md) 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](../../Enums%20and%20IDs/Medal.md).
## `notired`
When this is true, enemy party members will not have their `tired` (exhaustion) field incremented during [EndEnemyTurn](../Battle%20flow/EndEnemyTurn.md) like it would normally if the `DoublePain` [medal](../../Enums%20and%20IDs/Medal.md) isn't equipped.
NOTE: This applies even if [flags](../../Flags%20arrays/flags.md) 614 is true (HARDEST is active) because it still requires the `DoublePain` [medal](../../Enums%20and%20IDs/Medal.md) to be equipped for enemy exhaustion to be disabled.
## `hidehp`
When this is true, [RefreshEnemyHP](../Visual%20rendering/RefreshEnemyHP.md) 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](../Battle%20flow/Action%20coroutines/CheckDead.md) 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](../Damage%20pipeline/DoDamage.md)).
## `notattle`
Setting this to true will prevent GetTattleable from including the enemy party member in the return which prevents [Tattle](../Battle%20flow/Action%20coroutines/Tattle.md) to work on it.
This is used in [SetItem](../Player%20UI/SetItem.md) when handling a [Battle strategy list type](../Player%20UI/ItemList%20confirmation%20handling/Battle%20strategy%20list%20type.md#battle-strategy-list-type-confirmation-handling) 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](Conditions.md) and it will almost always have [IsStopped](IsStopped.md) 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](../../Enums%20and%20IDs/Enemies.md) 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](../Battle%20flow/Action%20coroutines/CheckDead.md) 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.

View File

@@ -0,0 +1,44 @@
# AddNewEnemy
This is a method that will initialise add a new enemy and add it to `enemydata`.
There are 3 overloads available:
(1)
```cs
private Transform AddNewEnemy(int id, Vector3 position)
```
(2)
```cs
private Transform AddNewEnemy(int id, Vector3 position, SpawnAnim animation)
```
Ends up doing (1) if animation is `None` (0)
(3)
```cs
private Transform AddNewEnemy(int id, EntityControl entity)
```
NOTE: This method is unused under normal gameplay. It is similar to (1), but it will not be documented due to older logic
## Parameters
- `id`: The [enemy](../../../Enums%20and%20IDs/Enemies.md) id to add
- `position`: Where the enemy should initialy be spawned
- `animation`: If it's not `None` (0), [NewEnemy](NewEnemy.md) will be called instead followed by a frame yield (the method ends up calling (1), but it has more logic afterwards). If it's `None` (0), it ends up being the same as (1)
## Procedure
Since all overloads ends up doing (1), this is the procedure that will be documented. Null is returned immediately if `enemydata` already has 4 elements or more (it's full, this doesn't handle `extraenemies`).
- A new `BattleData` is obtained from [GetEnemyData](../../../TextAsset%20Data/Enemies%20data.md#getenemydata) with createentity. From now own, the enemy refered to is the new one
- battleentity's position is set to the sent position
- battleentity.`battleid` is set to the length of `enemydata`
- battleentity is childed to `battlemap`
- battleentity.`hologram` is set to the value of [flags](../../../Flags%20arrays/flags.md) 162 (Using the B.O.S.S system or during a Cave of Trials session)
- If the current [map](../../../Enums%20and%20IDs/Maps.md) is `CaveOfTrials` and the matching [bestiary entry](../../../Enums%20and%20IDs/librarystuff/Bestiary%20entry.md) has a seen counter of 0:
- battleentity.`cotunknown` is set to true
- ForceCOT is called on the battleentity
- RefreshCOT is invoked in 0.1 seconds on the battleentity
- The new enemy is added to `enemydata` at the end
- If `animid` (the [enemy](../../../Enums%20and%20IDs/Enemies.md) id) is less than the length of instance.`enemyencounter` (normally 256) and battleentity.`cotunknown` is false, the view count of the matching [bestiary entry](../../../Enums%20and%20IDs/librarystuff/Bestiary%20entry.md) is incremented
- `lastaddedid` is set to the the `enemydata` index matching the enemy that was just added
- The enemy's battleentity.transform is returned

View File

@@ -0,0 +1,22 @@
# DropItem
This method will make an enemy party member drop its `helditem` and reset `holditem` accordingly. Check the [feature](../Enemy%20features.md#holditem-and-helditem) documentation to learn more.
```cs
private void DropItem(ref MainManager.BattleData target, bool additem)
```
## Parameters
- `target`: The enemy party member to have its `helditem` dropped. NOTE: it is invalid to send a player party member
- `additem`: Whether or not the `holditem` should be added to `items[0]` (standard items inventory) before its drop
## Procedure
- The `Fall` sound is played
- If additem is true, the enemy party member has a `holditem` and the amount of `items[0]` (standard items) is less than instance.`maxitems`, the `holditem` is added to `items[0]`
- The enemy party member's `holditem` is set to -1
- ItemDrop is called with the enemy party member's `helditem` which does the following:
- Root `helditem` to the scene
- Add a RigidBody to `helditem` with a velocity of RandomItemBounce(5.0, 12.5)
- `helditem` gets destroyed in 1.0 second
- `helditem` is set to null

View File

@@ -0,0 +1,38 @@
# NewEnemy
This coroutine is a wrapper around [AddNewEnemy](AddNewEnemy.md) in syntax (1) that ends up doing more spawn logic after.
```cs
private IEnumerator NewEnemy(int id, Vector3 pos, SpawnAnim animation)
```
## Parameters
- `id`: The [enemy](../../../Enums%20and%20IDs/Enemies.md) id to add
- `position`: Where the enemy should initialy be spawned
- `animation`: If it's not `None` (1 or 2), the spawn animation to use for the new enemy. If it's `None` (0), the coroutine only calls [AddNewEnemy](AddNewEnemy.md) and set `checkingdead` to null
## Procedure
[AddNewEnemy](AddNewEnemy.md) is called with the id and position and store the entity locally.
If animation is `None` (0), the coroutine is done as it only sets `checkingdead` to null before ending
Otherwise, the following occurs (the entity refered to is the new enemy just added):
- The `Charge` sound is played
- If entity.`cotunknown` is true:
- ForceCOT is called on the entity
- `spritebasecolor` is set to be pure black at 50% opacity
- The entity local scale is zeroed out
- `spin` is set to (0.0, 25.0, 0.0)
- During the course of 60.0 frames tracked with a local frame counter (incremented by the game's frametime):
- entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`)
- entity's local scale is set to a lerp from Vector3.zero to a target that depends on the animation with a factor of the ratio of the amount of frames cumulated over 60.0 frames. The target is Vector3.one for an animation of `Seed` (1) and (0.75, 0.75, 0.75) for `SeedMini` (2)
- The local framecounter is advanced
- A frame is yielded
- `startscale` is set to Vector3.one
- `sprite` local scale is set to the same target used for the lerping above
- `spin` is zeroed out
- [animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 0 (`Idle`)
- If animation is `SeedMini` (2), `hpbar` local scale is increased by (0.25, 0.25, 0.25)
- `tempslot` is set to the last `enemydata`
- `checkingdead` is set to null and the coroutine ends

View File

@@ -0,0 +1,48 @@
# ReorganizeEnemies
This is a method that will reorder `enemydata` to a specific list of [enemy](../../../Enums%20and%20IDs/Enemies.md) ids or remove `dead` or [fled](../Enemy%20features.md#fled) enemy party members as well as perform other sanitisation on `enemydata`.
There are 4 overloads available:
(1)
```cs
private void ReorganizeEnemies()
```
Ends up doing (2) with a skip of -1
(2)
```cs
private void ReorganizeEnemies(int skip)
```
(3)
```cs
private void ReorganizeEnemies(bool order)
```
If order is false, it ends up being the same as (1)
(4)
```cs
private void ReorganizeEnemies(int[] order)
```
This reorders `enemydata` instead of sanitizing it
## Parameters
- `skip`: The `enemydata` to skip adding no matter what, -1 to not skip any elements. NOTE: -1 is always sent under normal gameplay
- `order`: This depends on the overload used:
- For (3), if true, `enemydata` will be ordered by battleentity's x position and the only ones kept are the one where EnemyAlive returns true (the index is valid, the `hp` is above 0, battleentity isn't `dead` or `kill` and battleentity.`deathcoroutine` isn't in progress)
- For (4), the new desired ordering of the [eneny](../../../Enums%20and%20IDs/Enemies.md) ids. The array must be the same length as `enemydata` or nothing happens
## Procedure
(1) / (2) removes all enemy party members whose `hp` is 0 or below, their index isn't skip and they haven't [fled](../Enemy%20features.md#fled). This is followed by calling SetBEntityIDs which updates all the `enemydata`'s battleentity.`battleid` to their new one.
(3) does the same as (1) if order is false. If it's true, it removes all enemy party members where EnemyAlive returns false which happens if any of the following is true:
- The `enemydata` index is invalid
- The `hp` is 0 or below
- battleentity is `dead` or `kill`
- battleentity.`deathcoroutine` is in progress
From there, `enemydata` is ordered by battleentity's x position.
(4) doesn't sanitize `enemydata`, but rather reorders it. The order is given by order and it's done by [enemy](../../../Enums%20and%20IDs/Enemies.md) ids. If the length of order isn't the same than `enemydata`, nothing happens.

View File

@@ -0,0 +1,130 @@
# SummonEnemy
This is a coroutine that allows to create an [enemy](../../../Enums%20and%20IDs/Enemies.md) and to add it to `enemydata` during the battle.
There are 2 overloads:
(1)
```cs
private IEnumerator SummonEnemy(SummonType type, int enemyid, Vector3 position)
```
This one ends end starting (2) with cantmove as false followed by a frame yield.
(2)
```cs
private IEnumerator SummonEnemy(SummonType type, int enemyid, Vector3 position, bool cantmove)
```
## Parameters
- `type`: The type of summon to use which describes the method the enemy should appear
- `enemyid`: The [enemy](../../../Enums%20and%20IDs/Enemies.md) id to summon
- `position`: The position the enemy should appear in battle
- `cantmove`: If true, the starting `cantmove` value of the new enemy will be 1 (meaning one actor turn will need to pass for the enemy to act)
## SummonType
This is an enum that tells the behavior to have when summoning in this method (see the procedure for details):
|Value|Name|Description|
|-----|----|-----------|
|0|FromGround|The screen is shook twice followed by the enemy appears from the ground with a final `startscale` of (1.15, 1.15, 1.15)|
|1|Offscreen|The enemy appears by a [movetowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) call from the right offscreen|
|2|OffscreenNoAnim|The same than `Offscreen`, but the position is lerped instead of a [movetowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) call|
|3|None|No specific summoning logic occurs|
|4|FromGroundInstant|An alias of `FromGround`|
|5|Raise|The same than `OffscreenNoAnim`, but the enemy appears from the bottom of the screen|
|6|FromGroundKeepScale|The same than `FromGround`, but the final `startscale` is the one from [endata](../../../TextAsset%20Data/Entity%20data.md#animid-data)|
|7|Tablet|The position to summon is overriden to (50.0, 50.0, 0.0)|
## Procedure
There's 3 sections to this coroutine:
- `SummonType` pre add logic
- Adding the enemy
- `SummonType` post add logic
- Last adjustements
### `SummonType` pre logic
The logic depends on the sent type:
#### `FromGround` / `FromGroundKeepScale`
- ShakeScreen is called for 0.5 seconds
- 0.5 seconds are yielded
- ShakeScreen is called again with an ammount of (0.2, 0.2, 0.2) for 0.1 seconds
### `Offscreen` / `OffscreenNoAnim`
- The x/y position is overriden to 20.0 and 0.0 respectively
### `Raise`
- The y position is overriden to position.y - 20.0
### `Tablet`
- The position is overriden to (50.0, 50.0, 0.0)
### Adding the enemy
[AddNewEnemy](AddNewEnemy.md) is called with the enemyid and the position (or the overriden one if applicable). The [EntityControl](../../../Entities/EntityControl/EntityControl.md) of the new enemy is tracked locally.
### `SummonType` post add logic
The logic depends on the sent type (all position refers to the original sent value, not the overriden one unless stated otherwise. Additionally, the entity reffered to is the new enemy entity stored locally):
#### `Tablet`
- `TabletSpawn` particles are played at the position + (0.0, entity.`height`, 0.0) for 0.5 seconds
- 0.5 seconds are yielded
- The `Woosh6` sound is played
- DeathSmoke particles are played at the position + (0.0, entity.`height`, 0.0)
- ShakeScreen is called with an ammount of 0.1 for 0.5 seconds with dontreset
- The position is set to the sent position
- SlowSpinStop is called on the entity with a spinammount of (0.0, 30.0, 0.0) for 60.0 frames
- A second is yielded
#### `FromGround` / `FromGroundInstant`
- DeathSmoke paricles are played at the entity position
- entity.`startscale` is zeroed out
- entity.`sprite` local scale is set to entity.`startscale`
- A frame is yielded
- If the entity has a [model](../../../Entities/EntityControl/Notable%20methods/AddModel.md), entity.`model` local scale is set to entity.`modelscale`
- If enemyid isn't a `PitcherFlytrap` [enemy](../../../Enums%20and%20IDs/Enemies.md), entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 101
- entity.`spin` is set to (0.0, 20.0, 0.0)
- During the course of 30.0 frames tracked with a local frame counter (incremented by the game's frametime):
- entity.`startscale` is set to a lerp from Vector3.zero to (1.15, 1.15, 1.15) with a factor of the ratio of the amount of frames cumulated over 30.0 frames
- entity.`sprite` local scale is set to entity.`localscale`
- The local framecounter is advanced
- A frame is yielded
- entity.`startscale` is set to (1.15, 1.15, 1.15)
- entity.`spin` is zeroed out
- 0.5 seconds are yielded
- entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 0 (`Idle`)
#### `FromGroundKeepScale`
The same than `FromGround` / `FromGroundInstant`, but instead of having a final scale of (1.15, 1.15, 1.15) grown smoothly, the target scale is the `startscale` from [endata](../../../TextAsset%20Data/Entity%20data.md#animid-data)
#### `Offscreen`
- A frame is yielded
- entity.`rigid` has its gravity disabled
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the entity to the sent position with a 2.0 multiplier
- All frames are yielded while the entity is in a `forcemove`
- entity.`rigid` has its gravity enabled
- entity position is set to the sent position
#### `OffscreenNoAnim` / `Raise`
- A frame is yielded
- entity.`rigid` has its gravity disabled
- During the course of 101.0 frames tracked with a local frame counter (incremented by the game's frametime):
- entity's position is set to a lerp from the position (or the overriden one if applicable) to the sent position (not the overriden one) with a factor of the ratio of the amount of frames cumulated over 101.0 frames
- The local framecounter is advanced
- A frame is yielded
- entity.`rigid` has its gravity enabled
- entity's position is set to the sent position
### Last adjustements
- If the sent cantmove is true, `enemydata[lastaddedid].cantmove` is set to 1 (one actor turn will need to pass for the enemy party member to act)
- If `summonnewenemy` is false, `checkingdead` is set to null
- `summonnewenemy` is set to false

View File

@@ -0,0 +1,20 @@
# Heal
This method increases an actor's `hp` alongside some visual effects.
```cs
private void Heal(ref MainManager.BattleData entity, int? ammount, bool nosound)
```
## Parameters
- `entity`: The actor to heal
- `amount`: The amount to heal. If null, it heals by 999
- `nosound`: If true, the `Heal` sound won't be played. There is an overload without this parameter that sends false
## Procedure
- MainManager.HealParticle is called on the battleentity with a size of Vector3.one and an offset of Vector3.up * the battleentity.`height`
- If `nosound` is false and the `Heal` sound isn't playing or its more than halfway done player, it is played
- The actor's `hp` is increased by amount (or 999 if it's null) clamped from 0 to the actor's `maxhp`
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 1 with the damage amount as the amount healed earlier with the start being the battleentity position + (2.0, 2.0, 2.0) and the end being (5.0, 5.0, 5.0)

View File

@@ -0,0 +1,25 @@
# IsStopped
This is a method that determines if an actor is unable to act.
```cs
private bool IsStopped(MainManager.BattleData entity, bool skipimmobile)
```
## Parameters
- `entity`: The actor to check
- `skipimmobile`: Whether or not to exclude the [actimmobile](Enemy%20features.md#actimmobile) check. There is an overload without this parameter that sends false
## Procedure
If skipimmobile is false and the actor's [actimmobile](Enemy%20features.md#actimmobile) is true, the result is false.
Otherwise, the result is only true if any of the following are true (it's false otherwise):
- The actor has a [Freeze](BattleCondition/Freeze.md) condition
- The actor has a [Numb](BattleCondition/Numb.md) condition (or `isnumb` is true)
- The actor has a [Flipped](BattleCondition/Flipped.md) condition
- The actor has a [Sleep](BattleCondition/Sleep.md) condition (or `isasleep` is true)
- The actor has a [Eaten](BattleCondition/Eaten.md) condition
- The actor has a [EventStop](BattleCondition/EventStop.md) condition
- The actor's `hp` is 0 or below

View File

@@ -0,0 +1,13 @@
# GetFreePlayerAmmount
This method returns the amount of `playerdata` that are considered free. It belongs to MainManager.
This amount includes all player party members have the following criteria:
- `cantmove` is 0 or below (at least one action is available)
- `hp` is above 0 (the player isn't dead)
- It does not have any of the following [conditions](../Conditions.md):
- [Sleep](../BattleCondition/Sleep.md)
- [Numb](../BattleCondition/Numb.md)
- [Freeze](../BattleCondition/Freeze.md)
- [EventStop](../BattleCondition/EventStop.md)
- [Eaten](../BattleCondition/Eaten.md)

View File

@@ -0,0 +1,41 @@
# RevivePlayer
This method properly revive a player party member.
```cs
private void RevivePlayer(int id, int hp, bool showcounter)
```
## Parameters
- `id`: The `playerdata` index to revive
- `hp`: The `hp` to set the player party member. If it's negative, the `hp` will not be changed. NOTE: this should only be done when something else is guaranteed to heal the player party member as failure to do so will lead the `hp` left dangling at 0 while the actor isn't fully dead
- `showcounter`: Whether to call [Heal](../Heal.md) or not as part of the `hp` increase
## Procedure
- battleentity.`dead` is set to false
- battleentity.`iskill` is set to false
- battleentity has [LockRigid(false)](../../../Entities/EntityControl/EntityControl%20Methods.md) called on it which unlocks its `rigid`
- battleentity.`shadow` is enabled
- battleentity.`nocondition` is set to false
- The `playerdata`'s `turnssincedeath` is set to 0
- If the player party member is included in `deadmembers`:
- The `playerdata`'s `cantmove` is set to 0 (one action available) unless `enemy` is true (we are in the [enemy phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#enemy-phase) or later) where it's set to 1 instead (one actor turn is needed for an action to be available)
- [ClearStatus](../Conditions%20methods/ClearStatus.md) is called on the player party member
- The `playerdata`'s `moreturnnextturn` is set to 0
- The `playerdata`'s `tired` is set to 0
- battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 13 (`BattleIdle`)
- If the sent hp isn't negative:
- If showcounter is false, the player party member's `hp` is increased by the sent hp clamped from 0 to its `maxhp`
- Otherwise, [Heal](../Heal.md) is called on the player party member with the sent hp amount to heal
- If battleentity.`deathcoroutine` is in progress, it is stopped
- battleentity.`deathcoroutine` is set to null
- A ReviveFix coroutine is started with the id sent which will do the following:
- 0.5 seconds are yielded
- If battleentity.`deathcoroutine` is in progress, it is stopped
- battleentity.`deathcoroutine` is set to null
- battleentity.`dead` is set to false
- battleentity.`iskill` is set to false
- battleentity has [LockRigid(false)](../../../Entities/EntityControl/EntityControl%20Methods.md) called on it which unlocks its `rigid`
- battleentity.`shadow` is enabled
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called

View File

@@ -0,0 +1,33 @@
# RefreshEntities
This method performs some reset on some entity fields. It belongs to MainManager.
```cs
public static void RefreshEntities(bool forceanim, bool refreshmap, bool onlyplayer)
```
## Parameters:
- `forceanim`: Tells if ForceAnim will be called on each entity which will call Play on the entity's `anim` using its the current [animstate](../../Entities/EntityControl/Animations/animstate.md) (`f` is appended if the entity's `height` is aboe 0.1 and it has the same meaning than its normal argument)
- `refreshmap`: Tells if the [NPCControl](../../Entities/NPCControl/NPCControl.md) specific logic will apply
- `onlyplayer`: Tells if only the `playerdata` entities part will have their fields reset
There are 3 overloads: one where `onlyplayer` is ommited and false is sent, one without parameter where all the parameters will have false sent and one where the only parameter is `onlyplayer` and the other 2 will have false sent.
## Procedure
- All `playerdata` entities have their `hitwall` set to false and their [animid](../../Enums%20and%20IDs/AnimIDs.md) set to their corresponding BattleData.`animid`. If forceanim is true, ForceAnim is called which will call Play on the entity's `anim` using its the current [animstate](../../Entities/EntityControl/Animations/animstate.md) (`f` is appended if the entity's `height` is aboe 0.1 and it has the same meaning than its normal argument)
- We return immediately if `onlyplayer` is true
- All [EntityControl](../../Entities/EntityControl/EntityControl.md) have the following happen:
- `oldid` is set to -1
- `oldstate` is set to -1
- `emoticoncooldown` is set to 0.0
- `hitwall` is set to false
- If `height` is above 0.1, `oldfly` is set to `flyinganim`
- If it's an [item entity](../../Entities/EntityControl/Item%20entity.md), [UpdateItem](../../Entities/EntityControl/Update%20process/UpdateItem.md) is called
- If forceanim is true, ForceAnim is called which will call Play on the entity's `anim` using its the current [animstate](../../Entities/EntityControl/Animations/animstate.md) (`f` is appended if the entity's `height` is aboe 0.1 and it has the same meaning than its normal argument)
- If refreshmap is true and the entity has an `npcdata`, further logic are done about the corresponding [NPCControl](../../Entities/NPCControl/NPCControl.md) for the following:
- [Disguise](../../Entities/NPCControl/ActionBehaviors/Disguise.md) and its derivatives
- [Dropplet](../../Entities/NPCControl/ObjectTypes/Dropplet.md)
- [PushRock](../../Entities/NPCControl/ObjectTypes/PushRock.md)
- [Geizer](../../Entities/NPCControl/ObjectTypes/Geizer.md)
- If refreshmap is true and the map exists, all TrailRenderer has Clear called on them which clears all the wind trails currently active

View File

@@ -0,0 +1,31 @@
# GetAvaliableTargets
This method updates `avaliabletargets` and refreshes the enemy positions when applicable
```cs
private void GetAvaliableTargets(bool onlyground, bool onlyfront, int attackid, bool excludeunderground)
```
## Parameters
- `onlyground`: Only include enemy party members with a [position](../BattlePosition.md) of `Ground` (or `Underground` if excludeunderground is false)
- `onlyfront`: Only the first eligible enemy party member will be included
- `attackid`: The [skill](../../../Enums%20and%20IDs/Skills.md) id or a negative number denoting a player party member's basic attack (-1 is `Bee`'s, -2 is `Beetle`'s and -3 is `Moth`'s)
- `excludeunderground`: Excludes all enemies with a [position](../BattlePosition.md) of `Underground` when `onlyground` is true. There is an overload without this parameter that sends false
## Procedure
There is a simpler case that is checked first.
If [currentaction](../../Player%20UI/Pick.md) is `SkillList` and the [AttackArea](../../Player%20UI/AttackArea.md) of the [skill](../../../Enums%20and%20IDs/Skills.md) from [skilldata](../../../TextAsset%20Data/Skills%20data.md#skilldata) is `AllParty` or `SingleAlly`, `availabletargets` is set to `playerdata` which ends the method.
Otherwise:
- RefreshEnemyPos is called which checks all enemy party members whose `hp` is above 0, whose [cantfall](../Enemy%20features.md#cantfall) is false and whose [position](../BattlePosition.md) is `Ground` or `Flying`. If the enemy battleentity.`height` is above battleentity.`minheight` + 0.5, the [position](../BattlePosition.md) is set to `Flying`, `Ground` otherwise
- Each enemy party members is checked if it should be included in `avaliabletargets`. In order for the enemy to be included, all of the following must be true (on top of this, if onlyfront is true, only the first one found is included and the rest skipped):
- Its [position](../BattlePosition.md) isn't `OutOfReach`
- UndergroundCheck returns true for the attackid and the enemy [position](../BattlePosition.md) which only happens if the `position` isn't `Underground` or the attackid is among the following: -3 (`Moth`'s basic attack), 21 (`FrigidCoffin`), 6 (`BeetleDig`), 27 (`IceDrill`), 18 (`HurricaneBeemerang`)
- The parameters clauses are fufillfed which is checked using the following rules in order:
- If onlyground is false, it is included
- Otherwise, if the [position](../BattlePosition.md) is `Ground`, it is included
- Otherwise, excludeunderground must be false while [position](../BattlePosition.md) is `Underground`
- `avaliabletargets` is initialised to all the enemy party members included earlier

View File

@@ -0,0 +1,64 @@
# GetRandomAvaliablePlayer
This method obtains a suitable player party member index using the regular targetting rules.
```cs
private int GetRandomAvaliablePlayer(bool nullable)
```
## Parameters
- `nullable`: If true, this will use an alternative targetting scheme that may return -1 meaning to not target anyone. There is an overload without this that behaves the same as if false was sent. NOTE: The true version has broken logic, see the section below for details.
## Procedure
The logic depends on nullable's value
### nullable is true
If `forceattack` isn't -1, it is returned.
Otherwise, there will be attempts to find a random player party member to target. Each attempt involves generating a random one using uniformly random probabilities between each of them. For the target to be accepted, its `hp` must be above 0. The amount of times this is attempted is the amount of player party members. If a target is accepted it is returned, otherwise, -1 is returned and the caller has to handle this logic since no one will be targetted.
#### Problems with nullable true logic
There are some issues with this logic compared to the nullable false version which are bad enough to be considered broken:
- This scheme fails to account for the front player party member meaning it does not matter who is in the front
- This scheme fails to account for the `LeafCloak` [medal](../../../Enums%20and%20IDs/Medal.md) even when it is equipped meaning it does not matter if it is equipped on someone or not
- This scheme may not return a valid target which may force the caller to abort the attack or to try again, but there is never a guarantee that an accepted target is returned
- This scheme fails to account for the [eatenby](../BattleCondition/Eaten.md#eatenby-influences) (Only would have mattered for a `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md), but they do not use this targetting scheme under normal gameplay)
However, some enemies intentionally uses it in their action codes. The following enemies involves it at least once as part of their [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md) logic:
- `WildChomper` (via SpitSeed)
- `ChomperBrute` (via SpitSeed)
- `VenusBoss` (called directly and via ShakeSeed)
- `TANGYBUG` (via ShakeSeed)
- `SeedlingKing` (via ShakeSeed)
- `BeeTurret`
- `BeeBoss`
- `FalseMonarch`
- `MidgeBroodmother`
- `UltimaxTank`
- `MotherChomper`
Despite the game using it under normal gameplay, it is highly recommended to never pass true to the nullable parameter. It fails to account for too much and it can lead to undesired logic where the caller might not be able to find a suitable target.
### nullable is false
If `forceattack` isn't -1 and the player party member coresponding to it doens't have an `eatenby`, it is returned.
Otherwise, there is an infinite loop that starts:
- A random `partypointer` element (a `playerdata` index) is generated by generating a number from -2 (inclusive) to the amount of player party members (exclusive) clamped from 0 to the amount of player party members (this essentially biases to target the first party member more)
- If the player party member's `hp` is 0 or its `eatenby` exists, the target is rejected and the loop restarts
- Otherwise, if the player party member has the `LeafCloak` [medal](../../../Enums%20and%20IDs/Medal.md) equipped, the target is rejected, but this can only happen once: if another target passes the `hp` and `eatenby` checks, it is automatically accepted and returned
- Otherwise, the target is accepted and returned
The overall targetting odds are as follows:
|Amount of player party members|Who has `LeafCloak`?|Odds front|Odds second|Odds third|
|-----------------------------:|--------------------|----------|----------|----------|
|2|No one|3/4|1/4|N/A|
|2|Front|9/16|7/16|N/A|
|2|Second|15/16|1/16|N/A|
|3|No one|3/5|1/5|1/5|
|3|Front|9/25|8/25|8/25|
|3|Second|18/25|1/25|6/25|
|3|Third|18/25|6/25|1/25|

View File

@@ -0,0 +1,8 @@
# SetTargets
This method updates `availabletargets` and `helpboxid` according to the `playerdata[currentturn].battleentity`.[animid](../../../Enums%20and%20IDs/AnimIDs.md)`.
- If `currentturn` is negative (no player is currently selected), `helpboxid` is set to -1
- Otherwise, `helpboxid` is set to `playerdata[currentturn].battleentity.animid` and [GetAvaliableTargets](GetAvaliableTargets.md) is called according to that [animid](../../../Enums%20and%20IDs/AnimIDs.md):
- 0 (`Bee`): without onlyground and onlyfront with attackid of -1
- 1 (`Beetle`): with onlyground and onlyfront with attackid of -2
- 2 (`Moth`): with onlyground and without onlyfront with attackid of -3

View File

@@ -0,0 +1,24 @@
# ApplyBadges
This method applies all the static [medals](../Enums%20and%20IDs/Medal.md) effects defined in their data for the whole player party. It belongs to MainManager.
It first starts by resetting instance.`speedup` (an UNUSED field) to true and instance.`maxtp` to instance.`basetp`.
ResetPlayerStats is called on player party member which resets fields to defaults:
|Field|Value set|
|----:|-----|
|`lockitems`|false|
|`lockskills`|false|
|`locktri`|false|
|`lockrelayreceive`|false|
|`maxhp`|`basehp`|
|`atk`|`baseatk`|
|`def`|`basedef`|
|`poisonres`|0|
|`sleepres`|0|
|`freezeres`|0|
|`numbres`|0|
After, all the `BadgeEffects` of every applicable medals are applied just as described in the [medal effects data documentation](../TextAsset%20Data/Medals%20data.md#medal-effects).
Finally, instance.`tp` is clamped from 0 to instance.`maxtp` and every player party member's `hp` is clamped from 0 to their `maxhp`.

View File

@@ -0,0 +1,20 @@
# ApplyStatBonus
This method's purpose is to recalculate all player party member's stats based on all the bonuses that was accumulated so far. It belongs to MainManager.
It starts by calling ResetStats which resets all the stats to their starting value which are the following:
- `basehp`: 7 except for the `Beetle` [animid](../Enums%20and%20IDs/AnimIDs.md) where it's 9
- `baseatk`: 2
- `basedef`: 0
- Additionally, it also resets instance.`basetp` to 10
From there, the method only does anything if there's any `statbonus` (NOTE: This means the ApplyBadges call at the end is also skipped if there's none).
The method will then go through each `statbonus` and apply them as described in [stat bonus save file line](../External%20data%20format/Save%20File.md#line-10-array-line-stats-bonuses) by using the following fields (all player party members are impacted by the bonus if it targets the party):
- `basehp` for HP bonuses
- `baseatk` for attack bonuses
- `basedef` for defense bonuses
- instance.`basetp` for TP bonuses
After this, [ApplyBadges](ApplyBadges.md) is called.

View File

@@ -0,0 +1,133 @@
# AIAttack
This action coroutine involves the `aiparty` doing its attack which is hardcoded according to its [animid](../../../Enums%20and%20IDs/AnimIDs.md).
When the coroutine starts, all frames will be yielded as long as any enemy party member is in a [forcemove](../../../Entities/EntityControl/EntityControl%20Methods.md#forcemove). Once they are all done, the actual logic starts.
## Preparation
- `action` is set to true switching to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- `combo` is set to 1
- [ReorganizeEnemies(true)](../../Actors%20states/Enemy%20party%20members/ReorganizeEnemies.md) is called which sets `enemydata` to be all the alive enemies ordered by their x position
- The position of the `aiparty` is saved locally as the starting position
## Attack
This section depends on the [animid](../../../Enums%20and%20IDs/AnimIDs.md) of `aiparty`.
### `KungFuMantis`
- The first enemy party member whose [position](../../Actors%20states/BattlePosition.md) is `Ground` will be set as the target (`enemydata[0]` is set as falback if no grounded enemies exists)
- aiparty.`overrideflip` is set to true
- CameraFocus is called on the targetted enemy's battleentity's position which changes instance.`camoffset` to (0.0, 2.6, -6.0), instance.`camtarget` to null and instance.`camtargetpos` to the position of the targetted enemy
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the targetted enemy's battleentity's position + (-1.25 * the targetted enemy's `size`, 0.0, -0.1) with a multiplier of 2.0 using [animstate](../../../Entities/EntityControl/Animations/animstate.md) 1 (`Walk`) and stopping at animstate 100
- All frames are yielded while aiparty is in a `forcemove`
- 0.25 seconds are yielded
- Damages is only dealt if the targetted enemy's [position](../../Actors%20states/BattlePosition.md) was indeed `Ground` via a [DoDamage](../../Damage%20pipeline/DoDamage.md) call without attacker to the targetted enemy for 1 damage without properties and block. No damage is dealt if the enemy wasn't grounded (meaning none existed in the first place)
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the starting position saved earlier with a multiplier of 2.0 using [animstate](../../../Entities/EntityControl/Animations/animstate.md) 1 (`Walk`) and stopping at animstate 5 (`Angry`)
- All frames are yielded while aiparty is in a `forcemove`
- aiparty's position is set to the starting position saved earlier
### `AntCapitain`
- The first enemy party member whose [position](../../Actors%20states/BattlePosition.md) is `Ground` or `Flying` will be set as the target (`enemydata[0]` is set as falback if no enemies exists in either `position`)
- aiparty.`overrideflip` is set to true
- aiparty.`overridejump` is set to true
- MainManager.SetCamera is called with no target, the targetted enemy's battleentity's position as the targetpos, 0.03 as the speed and (0.0, 2.85, -7.5) as the offset
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the targetted enemy's battleentity's position + (-2.5, 0.0, -0.15) with a multiplier of 2.5
- All frames are yielded while aiparty is in a `forcemove`
- aiparty.`overrideanim` is set to true
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 100
- [LockRigid(false)](../../../Entities/EntityControl/EntityControl%20Methods.md#lockrigid) is called to unlock the `rigid`
- 0.33 seconds are yielded
- If the targetted enemy's [position](../../Actors%20states/BattlePosition.md) was `Flying`, [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called on the aiparty with aiparty.`jumpheight` * 1.2 as the height followed by the `Jump` sound being played
- 0.33 seconds are yielded
- The `Woosh3` sound is played
- [DoDamage](../../Damage%20pipeline/DoDamage.md) is called without attacker to the targgeted enemy for 3 damage without properties and block
- 0.5 seconds are yielded
- aiparty.`overrideanim` is set to false
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the starting position saved earlier with a multiplier of 2.0 using [animstate](../../../Entities/EntityControl/Animations/animstate.md) 1 (`Walk`) and stopping at animstate 13 (`BattleIdle`)
- All frames are yielded while aiparty is in a `forcemove`
- aiparty's position is set to the starting position saved earlier
- A frame is yielded
- aiparty.`flip` is set to true
- aiparty.`overrideflip` is set to false
### `Madeleine`
- aiparty.`overrideflip` is set to true
- The first enemy party member whose [position](../../Actors%20states/BattlePosition.md) is `Ground` will be set as the target (`enemydata[0]` is set as falback if no grounded enemies exists)
- If the targetted enemy's [position](../../Actors%20states/BattlePosition.md) isn't `Ground` (meaning none was found), the attack won't do any damage and its logic will end after doing the following:
- aiparty.`overrideanim` is set to false
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 8 (`Happy`)
- 0.5 seconds are yielded
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 0 (`Idle`)
- The logic proceed, starting by calling MainManager.SetCamera is called with no target, the targetted enemy's battleentity's position as the targetpos, 0.03 as the speed and (0.0, 2.85, -7.5) as the offset
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the targetted enemy's battleentity's position + (-1.5, 0.0, -0.15) with a multiplier of 2.5
- All frames are yielded while aiparty is in a `forcemove`
- aiparty.`overrideanim` is set to true
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 100
- The `Woosh3` sound is played at 0.9 pitch
- 0.5 seconds are yielded
- The `Woosh4` sound is played
- The following happens twice in sucession (the `Woosh4` sound is played at 1.1 pitch between the 2 iterations):
- [DoDamage](../../Damage%20pipeline/DoDamage.md) is called without attacker to the targgeted enemy for 2 damage with a `NoExceptions` property without block
- If the targetted enemy's `weight` is less than 100, [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called on its battleentity
- The targetted enemy's battleentity.`spin` is set to (0.0, 15.0, 0.0)
- 0.5 seconds are yielded
- All frames are yielded while the targetted enemy's battleentity's y position is above 0.15
- The targetted enemy's battleentity.`spin` is zeroed out
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- aiparty.`overrideanim` is set to false
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the starting position saved earlier with a multiplier of 2.0 using [animstate](../../../Entities/EntityControl/Animations/animstate.md) 1 (`Walk`) and stopping at animstate 0 (`Idle`)
- All frames are yielded while aiparty is in a `forcemove`
- aiparty's position is set to the starting position saved earlier
### `Maki`
- aiparty.`overrideflip` is set to true
- aiparty.`overridejump` is set to true
- The first enemy party member whose [position](../../Actors%20states/BattlePosition.md) is `Ground` or `Flying` will be set as the target (`enemydata[0]` is set as falback if no enemies exists in either `position`)
- MainManager.SetCamera is called with no target, the targetted enemy's battleentity's position as the targetpos, 0.03 as the speed and (0.0, 2.85, -7.5) as the offset
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the targetted enemy's battleentity's position + (-2.5, 0.0, -0.1) with a multiplier of 2.5
- All frames are yielded while aiparty is in a `forcemove`
- aiparty.`overrideanim` is set to true
- [LockRigid(true)](../../../Entities/EntityControl/EntityControl%20Methods.md#lockrigid) is called to lock the `rigid`
- The `MakiJump1` sound is played
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 114
- 0.45 seconds are yielded
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 112
- The `MakiJump2` sound is played
- instance.`campspedd` is set to 0.1
- instance.`camoffset` is incremented by (0.0, 1.25, -1.25)
- Over the course of 11 frames (tracked by the game's frametime with a local counter), aiparty's position is lerped from the one it had before the first iteration to the same position incremented by (1.0, 4.0, 0.0) with the factor being the progression of those 11 frames. This essentially makes maki move upward and slightly to the right
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 106
- The `MakiJump3` sound is played
- Over the course of 11 frames (tracked by the game's frametime with a local counter), aiparty's position is lerped from the one it had before the first iteration to the same position incremented by (0.0, -4.0, 0.0) with the factor being the progression of those 11 frames. This essentially makes maki move down to the position he had before the previous 11 frames lerp
- DeathSmoke is called with the targgeted enemy's battleentity's position with a size of (2.0, 2.0, 2.0)
- ShakeScreen is called with an amount of 0.2 for 0.5 frames
- If the targetted enemy's [position](../../Actors%20states/BattlePosition.md) isn't `Underground` (which can only happen if no `Ground` or `Flying` enemy party member existed and the first one happened to be `Underground`), [DoDamage](../../Damage%20pipeline/DoDamage.md) is called without attacked to the targgeted enemy for 6 damages with a `NoException` property and no block
- aiparty.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 107
- 0.65 seconds are yielded
- aiparty.`overrideanim` is reset to false
- [LockRigid(false)](../../../Entities/EntityControl/EntityControl%20Methods.md#lockrigid) is called to unlock the `rigid`
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the aiparty to the starting position saved at the start of the coroutine with a multiplier of 2.0 using [animstate](../../../Entities/EntityControl/Animations/animstate.md) 1 (`Walk`) and stopping at animstate 13 (`BattleIdle`)
- All frames are yielded while aiparty is in a `forcemove`
- aiparty's position is set to the starting position saved at the start of the coroutine
- A frame is yielded
- aiparty.`flip` is set to true
- aiparty.`overrideflip` is set to false
## Enemy drop
This section only occurs if a non zero amount of damages was dealt to an enemy party member whose [position](../../Actors%20states/BattlePosition.md) was `Flying` while its [cantfall](../../Actors%20states/Enemy%20features.md#cantfall) is false:
- `startdrop` is set to true
- If the targetted enemy party member doesn't have the `ToppleAirOnly` in its [weakness](../../Actors%20states/Enemy%20features.md#weakness) or it does, but with a [Topple](../../Actors%20states/BattleCondition/Topple.md) condition, the following happens on the enemy:
- StopAllCoroutines is called on the battleentity
- battleentity.`droproutine` is set to a new [Drop](../../../Entities/EntityControl/EntityControl%20Methods.md#drop) coroutine starting on the battleentity
- All frames are yielded while battleentity.`droproutine` is in progress
- The enemy party member's [position](../../Actors%20states/BattlePosition.md) is set to `Ground`
- `startdrop` is set to false
## Ending
`aiattacked` is set to true followed by a [CheckDead](CheckDead.md) starting.

View File

@@ -0,0 +1,171 @@
# AdvanceMainTurn
This is an action coroutine that runs at the very end of every main turn when both parties no longer can act for this turn.
## Procedure
- `commandsuccess` is reset to false
- `blockcooldown` is reset to 0.0
- `action` is set to true which changes to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- If the following conditions are met, [delprojs](../../Actors%20states/Delayed%20projectile.md) are processed (see the section below for details):
- `delprojs` isn't empty
- There are at least one player party member who has their `hp` above 0 while not `eatenby`
- There are at least one enemy party member who has their `hp` above 0
- `gameover` isn't in progress
- `nonphyscal` is set to false
- Each player party member gets their actor turn advanced (see the section below for details)
- A frame is yielded
- `availableplayers` is set to the amount of player party members whose `hp` is above 0
- If `availableplayers` is 0, [DeadParty](../Terminal%20coroutines/DeadParty.md) is started followed by an abrupt yield break. This will change to a [terminal flow](../Update%20flows/Terminal%20flow.md) as it is a terminal coroutine.
- If there is at least one enemy party member, the enemy party section of the turn advancement is performed alongside some end of main turn process (see the section below for details)
- Otheriwse if `gameover` was already in progress, a yield break is issued because it means we already changed to a [terminal flow](../Update%20flows/Terminal%20flow.md) and nothing is left to do
- Otherwise:
- `cancelupdate` is set to true changing to a [terminal flow](../Update%20flows/Terminal%20flow.md)
- A second is yielded
- If `inevent` is false (we weren't in an [EventDialogue](../EventDialogue.md)), [AddExperience](../Terminal%20coroutines/AddExperience.md) is started changing to a [terminal flow](../Update%20flows/Terminal%20flow.md). NOTE: the coroutine still continues, but in practice, it can't race against AddExperience
- If `actedthisturn` is false, `noaction` is incremented
- If `gameover` isn't in progress while `noaction` is 5 (meaning 5 main turns passed without the ability for the player party to act), the inaction failsafe is done (see the section below for more details)
- `actedthisturn` is set to false
- `forceattack` is set to -1
- `playertargetID` is set to -1
- If `damagethisturn` is higher than [flagvar](../../../Flags%20arrays/flagvar.md) 41 (highest damage in one turn), the flagvar value is set to `damagethisturn`
- `damagethisturn` is set to 0
- RefreshAllData is called which sets `alldata` to a new list which consists of all the `playerdata` followed by all the `enemydata` appended together
- [UpdateEntities](../../Visual%20rendering/UpdateEntities.md) is called
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- `option` is set to `lastaction`
- If there is at least one enemy party member, [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is invoked again in 0.75 seconds
- If `charmcooldown` is above 0, it is decremented
- `chompyattacked` is set to false
- `hideenemyhp` is set to false
- `mainturn` is set to null (which signals the coroutine is no longer in progress as no yield will be done from now on)
- All GameObjects with tag `DestroyTurn` have their tag set to `Untagged` followed by their destruction in 5.0 seconds
### `delprojs` advance
`delprojs` (or [delayed projectiles](../../Actors%20states/Delayed%20projectile.md#delayedprojectiledata)) are projectiles that an enemy can launch and the projectile will only hit the targetted player party member after a certain amount of main turns passed. This section processes them.
The first thing that happens is `nonphysical` is set to true (it will be set to false after this section).
From there, for each `delprojs` (going from last to start), the delproj's `turns` gets decremented and if it reached 0, it will land by doing the following:
- instance.`camtarget` is set to null
- instance.`camtargetpos` is set to (-4.25, 0.0, 0.0)
- instance.`camoffset` is set to (0.0, 4.0, -8.5)
- `enemy` is set to true
- `blockcooldown` is set to 0.0
- `commandsuccess` is set to false
- If the delproj has a `whilesound` set, it is played on loop unless the first character is `@` in which case, it will play the sound only once where name is the one without the `@`
- The `args` of the delproj are parsed as explained in the [delayed projectile documentation](../../Actors%20states/Delayed%20projectile.md#args-field)
- Unless a `noshadow` command was parsed, a ShadowLite is added to the delproj's `obj`
- For delproj's `framestep` amount of frames, the projectile is moved (kept track with a local frame counter starting at 0.0 and getting incremented by MainManager.`framestep` each iteraction):
- The delproj's `obj` psotion is set to a lerp from the initial one to the `partypos` of the delproj's `position` + the `move` command offset if it was parsed with a factor of the ratio between the amount of frames spent so far on this loop vs delproj's `framestep`
- A frame is yielded
- If the delproj had a `whilesound`, it is stopped. NOTE: if this wasn't a looped sound, the call won't work, but the sound will stop on its own
- If the delproj has a `deathsound`, it is played
- If the delproj has `deathparticle`, they are played at the `obj` position + the `partoff` command offset if it was parsed
- The delproj's `obj` is destroyed
- If the player party member whose index is the `partypointer` corresponding to the delproj's `position` has an `hp` above 0 and doesn't have an `eatenby`, some logic is performed on this player party member:
- [DoDamage](../../Damage%20pipeline/DoDamage.md) is called targetting the player party memmber without an attacker for delproj's `damage` damageammount with delproj's `property` as the property and `commandsuccess` as the block
- If the `hp` of the player party member reached 0 or below, their `turnssincedeath` is set to -1
- [RemoveDelayedProjectile](../../Actors%20states/Delayed%20projectile.md#removedelayedprojectile) is called on the delproj which removes it from `delprojs`
- `enemy` is set to false
- 0.6 seconds are yielded
If any `delprojs` landed:
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- `checkingdead` is set to a [CheckDead](CheckDead.md) action coroutine starting
- All frames are yielded while `checkingdead` is in progress
- `action` is set again to true
- A frame is yielded
- All actors from both parties with a `cantmove` below 1 (at least one action available) gets their `cantmove` clamped from 1 to 99 (forcing at least one turn needed before an action is available). This in practice doesn't do anything destructive because `moreturnnextturn` is granted later correctly and it's not possible to have a meaningul `cantmove` above 0 by this point (if it happened, it likely means the player party member [IsStopped](../../Actors%20states/IsStopped.md) which imply that when the stopping [condition](../../Actors%20states/Conditions.md) gets removed, the `cantmove` will reset anyway).
- `currentturn` is set to 1 (deselects any previously selected player party member)
- 0.5 seconds are yielded
### Player party advance
This section happens for each player party member.
- The corresponding `receivedrelay` of the player party member index is set to false
- [AdvanceTurnEntity](../AdvanceTurnEntity.md) is called on the player party member with hasdelay starting at false
- If the turn advancement resulted in hasdelay becoming true, 0.75 seconds are yielded
- If `eatenkill` is true (meaning a player party member died as a result of an eating attack) the game needs to properly kill the player party member that died by doing the following:
- `eatenkill` is set to false
- All frames are yielded while [spitout](../../Actors%20states/BattleCondition/Eaten.md#spitout) is in progress
- `checkingdead` is set to a new [CheckDead](CheckDead.md) coroutine starting
- All frames are yielded while `checkingdead` is in progress
- battleentity.`shakeice` is set to false
Finally, if the `MiracleMatter` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped on the player party member, a revival process will occur, but it can only happen if on top of the medal being equipped, all the following are true:
- This isn't a `firststrike` from the enemy party
- At least one player party member has its `hp` above 0 without being `eatenby`
- `lockmmater` is false
- The player party member has its `turnssincedeath` be at least (2 - amount of `MiracleMatter` equipped - 1) after clamping from 1 to 3 (essentially, at least 2 if only one is equipped, at least 1 if 2, at least 0 if more is equipped, but this case isn't possible under normal gameplay)
If all the conditions are met, the revive occurs as follows:
- `turnssincedeath` is set to 0
- [RevivePlayer](../../Actors%20states/Player%20party%20members/RevivePlayer.md) is called on the player party member index with 2 hp and with showcounter
- 0.5 seconds are yielded
- If the player party member's `lockcantmove` is false, their `cantmove` is set to 0 (this gives them one action available)
- The player party member's `lockcantmove` is set to false
### Enemy party advance and end of main turn process
This section not only manages enemy turn advance, but it also does some end of main turn process because being in this section means the battle is not going to end.
The first thing that happens is relating to the `FavoriteOne` [medal](../../../Enums%20and%20IDs/Medal.md) which is tracked by `attackedally`. If it's not negative, it means the player party member with the matching `trueid` was attacked and the other members should receive the medal's benefits. This is only done if there is more than 1 player party member's `hp` above 0 while not being `eatenby`. The process to apply the medal is as follows:
- For each player party member whose `trueid` isn't `attackedally` with an `hp` above 0 and without the [Eaten](../../Actors%20states/BattleCondition/Eaten.md) condition:
- battleentity.`emoticoncooldown` is set to 40.0
- `didnothing` is set to false
- battleentity.`emoticonid` is set to 2 (red ! mark)
- If at least one player party member had an emote set, the `Wam` sound is played
- All frames are yielded while the last player party member's battleentity.`emoticoncooldown` is above 0.0
- For each player party member whose `trueid` isn't `attackedally` with an `hp` above 0 with a `charge` less than 3 and without the [Eaten](../../Actors%20states/BattleCondition/Eaten.md) condition:
- A [StatEffect](../../Visual%20rendering/StatEffect.md) of type 4 (green up arrow) coroutine is started on the player party member
- `charge` is incremented
- If at least one player party member gained a `charge`, the `StatUp` sound is played at 1.25 pitch
- 0.5 seconds are yielded
- `attackedally` is reset to -1
From there, each enemy party members gets their turn advanced by having the following logic apply to each of them:
- [AdvanceTurnEntity](../AdvanceTurnEntity.md) is called on the eneny party member with hasdelay starting at false which advances their actor turn
- If hasdelay got a value of true after the turn advancement, 0.75 seconds are yielded
- battleentity.`shakeice` is set to false
- If `cantmove` is 0 (they would have only 1 action available after the actor turn), `cantmove` is set to -`moves` + 1 (this resets the available actions counter to the base one set from the normal amount being [moves](../../Actors%20states/Enemy%20features.md#moves))
- battleentity.`spin` is zeroed out
- `turnsnodamage` is incremented (this value is only written to, but never read so it's UNUSED)
Finally, some end of main turn process logic occurs:
- SetLastTurns is called which resets `lastturns` elements to be all -1 which resets the player party member selection cycle
- A frame is yielded
- `turns` is incremented
- `checkingdead` is set to a EndOfTurnMedals coroutine starting followed by all frames being yielded while the coroutine is in progress. This is what the coroutine does:
- Every 2 `turns`, for each player party member with the `HappyHeart` [medal](../../../Enums%20and%20IDs/Medal.md) equipped and whose `hp` is above 0:
- [Heal](../../Actors%20states/Heal.md) is called on the player party member with the amount being 2 * the amount of `HappyHeart` medals equipped
- 0.5 seconds are yielded
- Every 2 `turns` (same cycle as the one above), if the `HappyTP` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped:
- HealTP is called which plays a `Heal2` sound followed by a heal of instance.`tp` by 2 * the amount of `HappyTP` medals equipped clamped from 0 to instance.`maxtp` followed by a [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) with type 2 (TP), the amount being the amount of tp healed, the start position being `playerdata[`[GetRandomAvaliablePlayer()](../../Actors%20states/Targetting/GetRandomAvaliablePlayer.md)`].battleentity` position + (2.0, 2.0, 2.0) and the end position being (5.0, 5.0, 5.0)
- 0.5 seconds are yielded
- `checkingdead` is set to null which informs the caller the coroutine has ended so it can stop yielding
- `option` is set to 0
- `currentturn` is set to -1 (this unselects any players party members previously selected)
- `enemy` is set to false (this resets the [controlled flow](../Update%20flows/Controlled%20flow.md) to be in the [player phase](../Main%20turn%20life%20cycle.md#player-phase))
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- `action` is set to false changing to a [controlled flow](../Update%20flows/Controlled%20flow.md#controlled-flow)
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
### Inaction failsafe
There is a failsafe in the game where if after 5 main turns, [PlayerTurn](../PlayerTurn.md) was never called meaning the player party could in no way perform any actions, the game will forcefully allow the player party to act again. This is tracked by `actedthisturn` being false reporting no action could be taken and the total amount of main turn is tracked by `noaction`. This failsafe exists presumably to mitigate a situation where the player party is stopped for too long notably through the results of stopping [conditions](../../Actors%20states/Conditions.md).
The failsafe is applied by doing the following:
- `noaction` is reset to 0
- For each player party member that [IsStopped](../../Actors%20states/IsStopped.md) without skipimmobile while their `hp` is above 0:
- `MagicUp` particles are played at the battleentity position
- [ClearStatus](../../Actors%20states/Conditions%20methods/ClearStatus.md) is called on the player party member
- Their `cantmove` is set to 0 making them able to act again
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- If at least one player party member had ClearStatus called on them earlier, the `Heal3` sound is played followed by a 0.5 seconds yield

View File

@@ -0,0 +1,92 @@
# CheckDead
This is an action coroutine that runs at specific points during the battle to check the health of every actors and if any are found dead when they weren't before, the coroutine performs the process to kill them properly mainly by calling [Death](../../../Entities/EntityControl/Notable%20methods/Death.md#death) on their battleentity. The coroutine is usually stored on the `checkingdead` field which tracks whether or not a CheckDead is in progress, but other coroutines may use this field.
NOTE: This field is shared by other coroutines, but as long as care is taken such that no collisions happens, this is fine. Under normal gameplay, this is normally safe.
The coroutine does nothing if `gameover` is in progress. In that case, `checkingdead` is set to null followed by a yield break.
Here's the CheckDead procedure:
- `deadenemypos` is reset to a new list
- `action` is set to true which changes to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- For player party member whose `hp` is 0 or below while their battleentity.`death` is false (meaning this member should be dead, but isn't currently), the player death process occurs (see the section below for more details)
- From there, if there are no longer any player party members with an `hp` above 0 while not `eatenby`, a [DeadParty](../Terminal%20coroutines/DeadParty.md) terminal coroutine is started changing to a [terminal flow](../Update%20flows/Terminal%20flow.md) followed by a yield break which abruptly ends this CheckDead
- If any player party member were killed, SetLastTurns is called which resets `lastturns` to a new aray with the length being the amount of free players - 1 and all elements being -1 (this resets the player selection cycle)
- The enemy death checks occurs (see the section below for details)
- If `deadenemypos` isn't empty (meaning at least one enemy party member died or fled during this CheckDead), `extraenemies` isn't empty and there are still player party members with an `hp` above 0 while not being `eatenby`, the `extraenemies` summons procedure is performed (check the section below for details)
- If there are no longer any enemy party members left while `mainturn` isn't in progress, `mainturn` is set to a new [AdvanceMainTurn](AdvanceMainTurn.md) call which will take care of detecting the terminal case of winning the battle and act accordingly
- Otherwise:
- A frame is yielded
- If EnemyDropping reports that all enemy party members's battleentity.`droproutine` isn't in progress while `mainturn` isn't in progress, `action` is set to false which will change to a [controlled flow](../Update%20flows/Controlled%20flow.md) once CheckDead completes
- If we aren't `inevent`, [ReorganizeEnemies](../../Actors%20states/Enemy%20party%20members/ReorganizeEnemies.md) is called with order
- `checkingdead` is set to null which reports to the rest of BattleControl that CheckDead is no longer in progress
## Player party member death process
- `tired` is set to 0 (removes all exhaustions)
- `charge` is set to 0
- StartDeath is called on the battleentity which starts a [Death](../../../Entities/EntityControl/Notable%20methods/Death.md) process on it
- If `enemy` is true (the player party member died during the [enemy phase](../Main%20turn%20life%20cycle.md#enemy-phase), a [hitaction](../../BattleControl.md#hitactions) or a [delproj advance](AdvanceMainTurn.md#delprojs-advance)), `turnssinedeath` is set to -1 (this is so it gets incremented to 0 on their [AdvanceTurnEntity](../AdvanceTurnEntity.md) later).
- [ClearStatus](../../Actors%20states/Conditions%20methods/ClearStatus.md) is called on the player party member
- battleentity.`dead` is set to true (the Death process already does that)
- If the battleentity.[animid](../../../Enums%20and%20IDs/AnimIDs.md) matches the battle's `forceattack`, it is reset to -1 (since the target is no longer valid)
## Enemy party death checks
The following is enclosed in an infinite while loop, but in practice, it will only be iterated a maximum of 2 times.
An enemy party member is considered dead if they have [fled](../../Actors%20states/Enemy%20features.md#fled) or their `hp` isn't above 0 while their battleentity isn't `dead` yet. For each that are found:
- The battleentity position is added to `deadenemypos`
- DestroyConditionIcons is called on the battleentity
From there, the dying process depends if the enemy party member `fled` or not.
### Die by fleeing
The following happened if CheckDead found the enemy party member [fled](../../Actors%20states/Enemy%20features.md#fled):
- battleentity's position is set to offscreen at (0.0, -1000.0, 0.0)
- If `destroyentity` is true, the battle entity gets disabled
### Die by `hp` not being above 0
The following happens if CheckDead found the enemy hasn't [fled](../../Actors%20states/Enemy%20features.md#fled) meaning they were found dead because their `hp` wasn't above 0:
- `charge` is set to 0
- [condition](../../Actors%20states/Conditions.md) is reset to a new list
- [LockRigid(false)](../../../Entities/EntityControl/EntityControl%20Methods.md#lockrigid) is called on the battleentity to unlock its `rigid`
- If [holditem](../../Actors%20states/Enemy%20features.md#holditem-and-helditem) wasn't -1, [DropItem](../../Actors%20states/Enemy%20party%20members/DropItem.md) is called on the enemy party member with additem true
- If `animid` (the [enemy](../../../Enums%20and%20IDs/Enemies.md) id) is less than the amount of instance.`enemyencounter` (normally 256), `alreadycounted` is false and battleentity.`cotunknown` is false (this isn't a Cave Of Trials's shadow), the corresponding [bestiary entry](../../../Enums%20and%20IDs/librarystuff/Bestiary%20entry.md)'s defeated counter is incremented followed by setting `alreadycounted` to true
- The EXP amount is obtained by performing a [GetEXP](../../../TextAsset%20Data/Enemies%20data.md#exp-logic) call on the `exp`, `fixedexp` and the `animid` (the [enemy](../../../Enums%20and%20IDs/Enemies.md) id) clamped from 0 to instance.`neededexp` unless battleentity is a `hologram` in which case, it's clamped from 0 to 5 instead
- `expreward` is increased by the amount determined above and then clamped from 0 to instance.`neededexp`
- `moneyreward` is increased by the return of GetMoney using `money` which is a uniform random number between 0 and `money` inclusive
- `exp` is set to 0
- If [eventondeath](../../Actors%20states/Enemy%20features.md#eventondeath) is -1:
- [Death](../../../Entities/EntityControl/Notable%20methods/Death.md) is called on the battleentity
- entity.`spitexp` is set to the amount of EXP determined earlier
- `money` is set to 0
- Otherwise if `inevent` is false, `inevent` is set to true followed by an [EventDialogue](../EventDialogue.md) starting with [eventondeath](../../Actors%20states/Enemy%20features.md#eventondeath) as the id
- If the current enemy party member index is still valid (protects against an edgecase that can involve [EventDialogue](../EventDialogue.md) 9 which involves the `Acolyte` [enemy](../../../Enums%20and%20IDs/Enemies.md)):
- If [deathtype](../../Actors%20states/Enemy%20features.md#deathtype) is 2, 3, 4 or 5, the enemy party member is added to `reservedata`
- The `animid` (the [enemy](../../../Enums%20and%20IDs/Enemies.md) id) is added to instance.`lastdefeated`
### Cleanup and [diebyitself](../../Actors%20states/Enemy%20features.md#diebyitself) rechecks
The following happens after all checks are done:
- UpdateConditionIcons is called which calls UpdateConditionBubbles on the battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- If any enemy was found to be `dead` or [fled](../../Actors%20states/Enemy%20features.md#fled) earlier, [ReorganizeEnemies](../../Actors%20states/Enemy%20party%20members/ReorganizeEnemies.md) is called without skip
Finally, this is where all of this section's logic can be reiterated. It happens if all of the reamining enemy party members have their `diebyitself` set to true. This means that they should die automatically and in order to do so, their `hp` are set to 0 and their `diebyitself` set to false to avoid reentering this case.
By reiterating all the enemies check like this, CheckDead will be forced to detect the death of all remaining enemy party members because their `hp` were just set to 0. This recheck can only happen once making the loop iterating a maximum of 2 times.
## `extraenemies` summons
This section will move the appropriate amount of `extraenemies` to the main `enemydata` array so the ones that died can be replaced when applicable. Here's the process:
- All the enemy party members that died or [fled](../../Actors%20states/Enemy%20features.md#fled) during this CheckDead has their `droproutine` stopped then set to null if it was in progress
- For each `deadenemypos` (but not more than the amount in `extraenemies`):
- `summonnewenemy` is set to true
- [SummonEnemy](../../Actors%20states/Enemy%20party%20members/SummonEnemy.md) is called with type `Offscreen`, the [enemy](../../../Enums%20and%20IDs/Enemies.md) id being the `extraenemies` at the same index than the `deadenemypos` and the position being the `deadenemypos`
- 0.5 seconds are yielded
- All frames are yielded as long as `summonnewenemy` is true and EnemiesAreNotMoving reports false (meaning at least one enemy party member has their battleentity is in a [forcemove](../../../Entities/EntityControl/EntityControl%20Methods.md#forcemove))
- If instance.`map` is the `AbandonedCity` [map](../../../Enums%20and%20IDs/Maps.md) and [flags](../../../Flags%20arrays/flags.md) 400 (temporary slot) is true, all enemy party members have 2 [SetCondition](../../Actors%20states/Conditions%20methods/SetCondition.md) calls on them: one with [AttackUp](../../Actors%20states/BattleCondition/AttackUp.md) for 999999 actor turns and one with [DefenseUp](../../Actors%20states/BattleCondition/DefenseUp.md) for 999999 actor turns
- All the corresponding `extraenemies` that were just summoned are removed from `extraenemies`
- A frame is yielded

View File

@@ -0,0 +1,171 @@
# Chompy
This action coroutine involves `chompy`'s special attack phase when she is present. It it is called during the [player phase](../Main%20turn%20life%20cycle.md#player-phase) after all player party members's actor turns are done. Whether or not this coroutine has ran is tracked by `chompyattacked` and whether or not it's in progress is tracked by the `chompyattack` coroutine (`chompyaction` also tells if the setup is complete).
The actual flow is only switched once the setup is complete meaning this coroutine may stay in a [controlled flow](../Update%20flows/Controlled%20flow.md) for a little while before switching to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
## Setup
This section runs first and performs any waits or setup needed before switching to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md).
- A frame is yielded if there's at least one `extraenemies`
- All frames are yielded while `checkingdead` is in progress, `summonnewenemy` is true or while any enemy party member's battleentity is in a `forcemove`
- [ReorganizeEnemies(true)](../../Actors%20states/Enemy%20party%20members/ReorganizeEnemies.md) is called which removes all dead enemy party members and orders them by battleentity.position.x
- RefreshEnemyPos is called which checks all `enemydata` whose `hp` is above 0, whose [cantfall](../../Actors%20states/Enemy%20features.md#cantfall) is false and whose [position](../../Actors%20states/BattlePosition.md#battleposition) is `Ground` or `Flying`. If the enemy battleentity.`height` is above battleentity.`minheight` + 0.5, the `position` is set to `Flying`, `Ground` otherwise
- `combo` is set to 1
- `chompyaction` is set to true informing that the setup is complete
- `action` is set to true switching to a [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- A frame is yielded
## Vine menu setup
This section builds the vine menu.
- A new GameObject named `ChompyVine` is created and childed to `battlemap` with a position of `chompy`'s position + (0.0, 10.0, 0.0)
- A new GameObject named `Base` is created and childed to `ChompyVine` with a scale of to (1.0, 0.75, 1.0) and angles of (0.0, -40.0, 0.0)
- `coptions` is set to a new list with 2 elements being 0 and 1 (these are the attack and do nothing options)
- The list of the ribbons's [item](../../../Enums%20and%20IDs/Items.md) ids in `items[1]` (key items) is obtained locally via EventControl.ChompyRibbons. Only the `ChomperRibbon`, `PoisonRibbon`, `NumbRibbon`, `SleepRibbon` and `RedRibbon` items counts
- If the lost of ribbons isn't empty, 3 is added to `coptions` (this adds the switch ribbons option)
- If [flags](../../../Flags%20arrays/flags.md) 404 is true (chompy has a ribbon on her) and [flagvar](../../../Flags%20arrays/flagvar.md) 56 (the [item](../../../Enums%20and%20IDs/Items.md) id of the ribbon chompy has on her) isn't `ChomperRibbon` `RedRibbon` or 0 (which means unequipped here), 2 is added to `coptions` (this adds the the ribbon specific attack option)
- `maxoptions` is set to the final amount of `coptions`
- `option` is set to `chompyoption`. This means the default option will be the last one selected during the battle, but if that option index is no longer available by checking if it's equal or higher than `maxoption`, `option` is set to 0 instead (attack)
- For each option indexes available from 0 to `maxoptions` exclusive:
- A `Prefabs/Objects/Vine` is instantiated to a new GameObject childed to the `Base` with a position of `ChompyVine`'s position + (0.0, 0.0, -1.0), a scale of (2.5, 2.5, 2.5) and a SpriteRenderer component
- `ChompyVine`'s angles are decremented by (0.0, 360 / `maxoptions` converted to float, 0.0)
- The sprite of the SpriteRenderer of the vine GameObject is set depending on the corrsponding `coption` matching the option index:
- 0 (Attack): `guisprites[147]`
- 1 (Do Nothing): `guisprites[148]`
- 2 (Ribbon specific action): Depends on the [flagvar](../../../Flags%20arrays/flagvar.md) 56 (the [item](../../../Enums%20and%20IDs/Items.md) id of the ribbon chompy has on her). This also initialises the attack property of the bite specific attack (check the selected option handling for details). The sprite is `guisprites[158]` for the `PoisonRibbon`, `guisprites[159]` for the `NumbRibbon` and `guisprites[160]` for the `SleepRibbon`. Additionally, if instance.`tp` is less than 2, the material of the sprite is set to MainManager.`grayscale`
- 3: (Switch Ribbon) `guisprites[217]`
- The sprite of the vine GameObject's flipX is set to true
- [currentaction](../../Player%20UI/Pick.md) is set to `Chompy`
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
## Vine menu selection loop
This is an infinite loop that runs until an option has been confirmed in the vine menu. Everything in this section runs perpetually until explicitly said otherwise.
- [RefreshEnemyHP](../../Visual%20rendering/RefreshEnemyHP.md) is called
- As long as input 4 (confirm) isn't pressed, the following runs in an inner infinite loop:
- If input 3 (left) or input 2 (right) is pressed, the `Scroll` sound is played followed by the `option` being decremented or incremented accordingly with wrap around to `maxoptions` - 1 followed by [UpdateText](../../Visual%20rendering/UpdateText.md) being called
- `Base` y angle is lerped from the existing one to -`option` * (360.0 / `maxoptions`) - 40.0 with a factor of 1/10 of the game's frametime
- `Base`'s y scale is lerped from the existing one to 1.0 with a factor of 1/10 of the game's frametime (the x and z scale are set to 1.0)
- A frame is yielded
- Getting here means a main vine menu option was chosen. If it's 2 (ribbon specific action) while instance.`tp` is less than 2, the buzzer sound is played followed by a frame yield followed by perfoming another iteration of the selection loop
- If the confimed option isn't 3 (switch ribbons), the slection loop ends (switch ribbon is the only option that needs further handling once chosen)
- The `Confirm` sound is played if it wasn't already
- [currentaction](../../Player%20UI/Pick.md) is set to `BaseAction`
- [UpdateTect](../../Visual%20rendering/UpdateText.md) is called
- instance.`multilist` is set to the ribbons list obtained earlier except the one held in [flagvar](../../../Flags%20arrays/flagvar.md) 56 (the one chompy has on her)
- [SetText](../../../SetText/SetText.md) is called in [dialogue mode](../../../SetText/Dialogue%20mode.md#dialogue-mode) using the text `|`[hide](../../../SetText/Individual%20commands/Hide.md)`||`[pickitem](../../../SetText/Individual%20commands/Pickitem.md)`,35,-11,-11|` (which pops an [ItemList](../../../ItemList/ItemList.md) with the [chompy ribbons list type](../../../ItemList/List%20Types%20Group%20Details/Chompy%20Ribbons%20List%20Type.md)). The call has these properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- linebreak of `messagebreak`
- No tridimensional
- position of Vector3.zero
- No cameraoffset
- size of Vector3.one
- No parent
- No caller
- [RefreshEnemyHP](../../Visual%20rendering/RefreshEnemyHP.md) is called
- As long as the [message](../../../SetText/Notable%20states.md#message) lock is active:
- `Base`'s y angle is set to a lerp from the existing one to -`option` * (360.0 / `maxoptions`) - 40.0 with a fractor of `framestep` * 0.1
- `Base`'s y scale is lerped from the existing one to 1.0 with a factor of `framestep` * 0.1 (the x and z scale are set to 1.0)
- A frame is yielded
- Getting here means the [ItemList](../../../ItemList/ItemList.md) handling and the dialogue has completed. If MainManager.`listcancelled` is true, it means the selection loop isn't done yet and the following is performed:
- `option` is set to the value it had before the SetText call (this is because the ItemList system uses it so it restores the value to continue being used for the vine menu)
- `maxoptions` is set to the amount of `coptions` (this is also because it was used as part of ItemList)
- [currentaction](../../Player%20UI/Pick.md) is set back to `Chompy`
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- Another iteration of the vine menu selection loop is performed
- The value of [flagvar](../../../Flags%20arrays/flagvar.md) 0 is saved locally (this corresponds to the [item](../../../Enums%20and%20IDs/Items.md) id of the selected ribbon)
- The vine menu selection loop ends here as the switch ribbon option was just confirmed
## Selected option handling
Getting here means that an option has been confirmed in the vine menu selection loop and the coroutine is ready to handle it.
- `chompyoption` is set to the selected `option`
- [currentaction](../../Player%20UI/Pick.md) is reset to `BaseAction`
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- The `Confirm` sound is played
- The `ChompyVine` object is destroyed
- `hideenemyhp` is set to true
What follows depends on the `coption[option]` selected.
### 0 (Attack) or 2 (Ribbon specific action)
- If the `coption` is 2 (ribbon specific action), instance.`tp` is decreased by 2
- All player party members has DestroyConditionIcons called on their entity (not battleentity)
- All enemy party members has DestroyConditionIcons called on their entity if it exists (this is normally the same than battleentity)
- The enemy party member to target is obtained by getting the first one whose [position](../../Actors%20states/BattlePosition.md) is `Ground` or `enemydata[0]` if none are found
- MainManager.SetCamera is called with no target, the targetted enemy's battleentity's position as the targetpos, 0.03 as the speed and (0.0, 2.85, -7.5) as the offset
- The x/z position of `chompy` are saved locally (the y component is saved to 0.0)
- `chompy`'s `overrideflip` is set to true
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md) is called on `chompy` to move towards the targetted enemy's battleentity's position + (0.0 - the `size` of the targetted enemy, 0.0, -0.1) with a multiplier of 3.0
- All frames are yielded while `chompy` is in a `forcemove`
- `chompy`'s [animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 100
- The `Chew` sound is played with a pitch of 1.5
- If the targetted enemy's [position](../../Actors%20states/BattlePosition.md) is indeed `Ground` (always happen unless no grounded enemies existed earlier):
- [DoCommand](../../Action%20commands/DoCommand.md) is called with a timer of 60.0, a commandtype of `PressKeyTimer` and a data being a one element array containing a random integer between 4 and 6 converted to float
- A frame is yielded
- All frames are yielded while `doingaction` is true
- If the targetted enemy's [position](../../Actors%20states/BattlePosition.md) is indeed `Ground` (always happen unless no grounded enemies existed earlier) and `commandsuccess` is true:
- `chompy`'s [animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 102
- The `Bite` sound is played with a pitch of 1.25
- [DoDamage](../../Damage%20pipeline/DoDamage.md) is called without attacker to the targetted enemy for a damage of 2 (or 3 if [flags](../../../Flags%20arrays/flags.md) 404 is true and [flagvar](../../../Flags%20arrays/flagvar.md) 56 is `ChomperRibbon` meaning that ribbon is currently on Chompy) without block. The property depends on the ribbon:
- `PoisonRibbon`: `Poison`
- `NumbRibbon`: `Numb`
- `SleepRibbon`: `Sleep`
- Anything else: No properties
- if [flagvar](../../../Flags%20arrays/flagvar.md) 56 (the [item](../../../Enums%20and%20IDs/Items.md) id of the ribbon chompy has on her) is `RedRibbon` and `lastdamage` is above 0:
- instance.`tp` is incremented then clamped from 0 to instance.`maxtp`
- The `Heal2` sound is played
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 2 (TP) with an ammount of 1 starting from `chompy`'s position + (-1.0, 1.0, 0.0) and ending at Vector3.up
- Otherwise (meaning no grounded enemies existed or the action command was failed):
- 0.1 seconds are yielded
- The `AtkFail` sound is played
- `chompy`'s [animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 103
- 0.4 seconds are yielded
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- `chompy`'s `rigid` constraints are set to freeze everything except x/z position
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md) is called on `chompy` to move her to the position saved earlier with a multiplier of 2.0
- All frames are yielded while `chompy` is in a `forcemove`
- [StopForceMove](../../../Entities/EntityControl/EntityControl%20Methods.md#stopforcemove) is called on `chompy`
- `chompy`'s `rigid` gravity is enabled
- `chompy`'s position is set to the one saved earlier
- A frame is yielded
- `chompy`'s `flip` is set to true
- `chompy`'s `overrideflip` is reset to false
- `startdrop` is set to true (this allows enemies that requires dropping to finish their drops)
- A frame is yielded (this lets the drops finish)
- `startdrop` is set back to false (since it's no longer needed)
- `checkingdead` is set to a new [CheckDead](CheckDead.md) coroutine
- All frames are yielded while `checkingdead` is in progress
- If there's still any enemy party member with an `hp` above 0, `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md) (this means the flow isn't changed if all enemies are dead)
### 1 (Do Nothing)
The only thing that happens is `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md)
### 3 (Switch ribbon)
- The `Switch` sound is played
- `chompy`'s `spin` is set to (0.0, -20.0, 0.0)
- 0.33 seconds are yielded
- The selected ribbon's [item](../../../Enums%20and%20IDs/Items.md) id is removed from `items[1]` (key items)
- If [flags](../../../Flags%20arrays/flags.md) 404 is false (Chompy doesn't have a ribbon on her), flags 404 is set to true. Otherwise, [flagvar](../../../Flags%20arrays/flagvar.md) 56 (the [item](../../../Enums%20and%20IDs/Items.md) id of the ribbon chompy has on her) is added to `items[1]` (key items) if it didn't existed in the list already
- [flagvar](../../../Flags%20arrays/flagvar.md) 56 (the [item](../../../Enums%20and%20IDs/Items.md) id of the ribbon chompy has on her) is set to the selected ribbon item id
- ChompyRibbon is called on `chompy` which changes its color depending on [flagvar](../../../Flags%20arrays/flagvar.md) 56 (the [item](../../../Enums%20and%20IDs/Items.md) id of the ribbon chompy has on her):
- `PoisonRibbon`: Lerp between pure red and pure blue with a factor of 0.65 (this means purple with a bit more blue)
- `NumbRibbon`: Lerp between pure yellow and pure black with a factor of 0.2 (mostly yellow)
- `SleepRibbon`: Lerp between pure green and pure black with a factor of 0.3 (mostly green)
- `RedRibbon`: Lerp between pure white and pure bluw with a factor of 0.5 (light blue)
- Any other item id: Lerp between pure red and pure white with a factor of 0.5 (light red)
- 0.1 seconds are yielded
- `chompy`'s `spin` is zeroed out
- `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md)
## End
This section contains all the cleanup steps needed to end the action coroutine.
- A frame is yielded if there's at least one `extraenemies`
- All frames are yielded while `checkingdead` is in progress, `summonnewenemy` is true or while any enemy party member's battleentity is in a `forcemove`
- [RefreshEnemyHP](../../Visual%20rendering/RefreshEnemyHP.md) is called
- `chompyaction` is reset to false
- `chompyattacked` is set to true
- `chompyattack` is set to null indicating the coroutine is done

View File

@@ -0,0 +1,271 @@
# DoAction
This action coroutine allows an actor to perform an action which is an hardcoded procedure in battle such as an attack, skill or special item usage. This coroutine contains the logic of all player and enemy actions making it the largest method in the game by far in terms of code volume. This has performance implications (see the section below for details).
The vast majority of the logic of this coroutine are contained in the individual actions, but this page will focus on documenting the surrounding code as the actions will be documented somewhere else.
TODO: Document all player and enemy actions in part 3 of the battle docs
```cs
private IEnumerator DoAction(EntityControl entity, int actionid)
```
## Parameters
- `entity`: The actor that will be performing the action
- `actionid`: The meaning changes depending on the entity:
- If it's a player party member, this is a number that tells what action entity will be performing (-2 is a `LonglegSummoner` [item](../../../Enums%20and%20IDs/Items.md) -1 is a basic attack, anything of 0 or above is a [Skill](../../../Enums%20and%20IDs/Skills.md) id or [item](../../../Enums%20and%20IDs/Items.md) use)
- If it's an enemy party member, this is its `enemydata` index. Sending an invalid index is considered invalid and will result in an exception being thrown in the vast majority of cases
- If the value is -555, this is reserved to perform a blank dummy call, see the section below about performance for more details
## Performance implications
This coroutine is extremely large in IL code size. This creates a problem because when calling it for the first time, it requires the JIT's full attention to compile it which can stutter the game. This performance penalty goes away once it has been called at least once throughout the entire game's session, but it is still very noticeable (it can be as long as a second or two).
One mitigation the game does is to precipitate the stutter during the battle out loading transition of [StartBattle](../../StartBattle.md). It does this by checking a boolean that belongs to MainManager and is only set to true when this happened for the first time since the last save load. To prevent any destructive logic to happen, StartBattle will send -555 as the actionid which can be seen as a blank dummy call: it will not perform any meaningful logic, but it will still be enough to force the JIT to compile the coroutine as it was explicitly called.
## Procedure
Considering how large this method its lifecycle will be divided into different phases.
NOTE: If this is a player action, the coroutine expects `availabletargets`, `target`, [currentaction](../../Player%20UI/Pick.md), [itemarea](../../Player%20UI/AttackArea.md) and `currentturn` to be correctly set because they are needed to tell the coroutine the details of the action (notably, `currentturn` tells the `playerdata` index of the player party member performing the action). For a [Skill](../../../Enums%20and%20IDs/Skills.md), its cost is expected to be in [flagvar](../../../Flags%20arrays/flagvar.md) 0 (TP if it's 0 or above, HP if it's negative using the absolute value).
### Setup
This is the first phase of the coroutine. It ensures the coroutin can proceed and does some preparations logic.
- `deadmembers` is set to the return of GetDeadParty which are all the player party members indexes whose `hp` is 0 or below
- If `cancelupdate` is true (which means we had entered into a [terminal flow](../Update%20flows/Terminal%20flow.md)), a frame is yielded followed by the coroutine abruptly ending with a yield break. This can be considered a safeguard in case terminal flow was entered before a DoAction call occured
- `overridechallengeblock` is set to false
- Any string invocation of [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is cancelled. This can happen if [AdvanceMainTurn](AdvanceMainTurn.md) invoked it, but a DoAction call processed before the incation occurs which can interfere because DoAction needs tighther control over calling UpdateAnim (and it calls it later as part of the setup anyway). Cancelling the invocation prevents this from happening
- DestroyHelpBox is called which sets `helpboxid` to -1 and destroys `helpbox` if it existed in 0.5 seconds with shrink before setting it to null
- `action` is set to true switching to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
What follows is a bunch of field value resets:
|Field|Value|
|----:|-----|
|`infinitecommand`|false|
|`hasblocked`|false|
|`dontusecharge`|false|
|`nolifesteal`|false|
|`caninputcooldown`|0.0|
|`blockcooldown`|0.0|
|`combo`|1|
|`barfill`|0.0|
|`weakenemyfound`|false|
|`killinput`|false|
|`nonphysical`|false|
|`commandsuccess`|false|
From there, a couple of local variables are initialised that may be used in the actions logic:
- flip: The `flip` value of the entity, used for restoring later in normal post action
- randomposafter: A boolean starting at false that when true by the normal post action, the `position` of the enemy party member will be determined randomly. This only applies to enemy party members and is only used by `Mushroom` and `BeeBot` under normal gameplay. NOTE: it is invalid to set this to true during a player action and if done, it will lead to illogical behaviors
- fled: A boolean starting at false that when true by the normal post action, it will change the majority of the normal post action logic to be very reduced. This is supposed to signal that the action lead to the enemy party member fleeing the battle. This only applies to enemy party members and is only used by `Burglar` and `GoldenSeedling` under normal gameplay. NOTE: it is invalid to set this to true during a player action and if done, it will lead to illogical behaviors
- nocharm: A boolean starting at false that when true by the normal post action, it will prevent any [UseCharm](../UseCharm.md) calls to occur. This means no `HealTP` for the player party if it spent any to perform a skill and no `HealHP` after an enemy action. This is only used by `WaspHealer`, `LeafbugNinja` and `LeafbugArcher` under normal gameplay
- startp: The x/y starting position of the entity (the y component is left at 0.0). This can be overriden to another value in action logic and it is only used to move the actor back to it in normal post action
- startstate: The starting [animstate](../../../Entities/EntityControl/Animations/animstate.md) of the entity. This can be overriden in action logic and is only used as the stopping state when moving the actor back to startp in normal post action
- usedtp: An integer starting at -1 that reports the cost of the skill used by the player party member if applicable. This is only used in normal post action to determine if a [UseCharm](../UseCharm.md) call should occur with `HealTP` corresponding to half of the skill's cost. This has no effect on enemy party members
After, the following is done:
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- [LockRigid(false)](../../../Entities/EntityControl/EntityControl%20Methods.md#lockrigid) is called on the entity to unlock its `rigid`
From there, the next phase depends on the entity itself. It can either be a player action or an enemy action:
- If the entity has a `Player` tag, it's a player action
- Otherwise, this is an enemy action, but there is a special case in which it will not be performed and the coroutine will skip to the post action phase if all of the following are true:
- `firststrike` is true
- The `DoublePain` [medal](../../../Enums%20and%20IDs/Medal.md) is not equipped
- [flags](../../../Flags%20arrays/flags.md) 614 is false (HARDEST is inactive)
- `actionid` is not 0 (this isn't the first enemy party member)
NOTE: This enemy action exception never applies under normal gameplay. This is because `firststrike` is only true in the case where the enemy had the advantage when [StartBattle](../../StartBattle.md) was called and in that logic, DoAction is only called on the first enemy party member. This means that in practice, whenever `firststrike` is true, actionid should ALWAYS be 0. The exception clause can be considered dead logic.
### Player action
This phase applies only if the entity has a `Player` tag.
#### Player action setup
The setup first begins by initialising a local variable called targetentity which is the actor data of the action's target (if it exists). This is primarily used for an [itemarea](../../Player%20UI/AttackArea.md) of `SingleAlly` or `SingleEnemy` targetting action, but it is technically initialised for multi targetting, just not very useful. Only some action uses this variable and it may not get a valid actor if it is not needed, but it must be set correctly if it is. Here's the logic for determining the value:
- If actionid is -555 (blank dummy call), the value is left at the [BattleData](../../Actors%20states/BattleData.md)'s default
- Otherwise, if [currentaction](../../Player%20UI/Pick.md) is `ItemList` (this is an item use action), then it depends on [itemarea](../../Player%20UI/AttackArea.md) (if none match, the variable is left at the [BattleData](../../Actors%20states/BattleData.md)'s default):
- `SingleAlly`: The `target` player party member
- `SingleEnemy`: [GetAvaliableTargets](../../Actors%20states/Targetting/GetAvaliableTargets.md) is called without onlyground and onlyfront with excludeunderground using actionid as the attack id followed by setting the variable to `avaliabletargets[target]`. NOTE: In practice, the GetAvaliableTargets shouldn't change anything under normal gameplay because it was called with similar parameters (attackid was -1, but it doesn't change anything) during [SetItem](../../Player%20UI/SetItem.md)
- Otherwise, if `target` is less than the length of `avaliabletargets` (it's a valid target), the variable is set to `avaliabletargets[target]`
- Otherwise, it's left at [BattleData](../../Actors%20states/BattleData.md)'s default
After, if actionid isn't negative (meaning this isn't a basic attack action or player first strike) and [currentaction](../../Player%20UI/Pick.md) isn't `ItemList` (meaning this must be a [skill](../../../Enums%20and%20IDs/Skills.md)), the cost of the skill is paid by doing the following:
- If the `HPFunnel` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped or [flagvar](../../../Flags%20arrays/flagvar.md) 0 is negative (meaning it's an HP cost), the `hp` of the `currentturn` player party member is decreased by the absolute value of flagvar 0
- Otherwise, instance.`tp` is decreased by [flagvar](../../../Flags%20arrays/flagvar.md) 0 (TP cost)
If a cost was paid, usedtp is set to the value of [flagvar](../../../Flags%20arrays/flagvar.md) 0 (the TP or HP cost).
After, if actionid isn't -555 (meaning it's not a player first strike) and [currentaction](../../Player%20UI/Pick.md) isn't `ItemList` (meaning it's not an item use so it's a basic attack or skill action), `checkingdead` is set to a new [UseCharm](../UseCharm.md) call with the type being `AttackUp`.
After, `targettedenemy` is set to the `enemydata` index of the targetted enemy using the following logic:
- If actionid is -555 (blank dummy call), it's 0
- Otherwise, if `target` is at least `avaliabletargets`'s length - 1 (this is wrong, but safe, see the note below) or [currentaction](../../Player%20UI/Pick.md) is `ItemList` (this is an item use action), it's `target`
- Otherwise, it's the battleentity.`battleid` of the return of GetEnemyFromAvaliable using `avaliabletargets[target]`. Basically, it means if `avaliabletargets[target]`'s battleentity still exists in `enemydata`, it will be its `battleid` (which is the same than the `enemydata` index) and if it doesn't, it will be 0
NOTE: This logic is very broken, but in practice, it's only ever used in 2 actions: the `HeavyStrike` [skill](../../../Enums%20and%20IDs/Skills.md) or `Beetle`'s basic attack. For those actions specifically, this logic happens to always be correct whether it is on accident or not. `targetedenemy` will be correct in these cases, but it should not be relied upon because its value isn't reliable and can easilly point to the wrong enemy party member.
Finally, all frames are yielded while `checkingdead` is in progress (which would be the [UseCharm](../UseCharm.md) call made earlier if it was).
#### Player action procedure
The actionid directly tells what action will be performed by a switch on it. Unlike enemy actions, there is no loop so the action is performed once and then completes.
TODO: document the player actions in part 3 of the battle docs in a separate place
### Enemy action
This phase applies if the entity doesn't have a `Player` tag unless it's not the first `enemydata` whenever `firststrike` is true, but as mentioned in the setup phase, this never happens under normal gameplay.
#### Enemy action setup
This part of the enemy action phase occurs before any action is performed:
- `checkingdead` is set to a new [UseCharm](../UseCharm.md) call with the type being `DefenseUp`
- All frames are yielded while `checkingdead` is in progress
The action can only occur if the enemy party member doesn't have a [Flipped](../../Actors%20states/BattleCondition/Flipped.md) condition for 2 turns or more (the action is allowed if there's 1 turn left on it or the condition isn't present). If it doesn't occur, the coroutine skips to the post action phase.
If the enemy party member has either the [Flipped](../../Actors%20states/BattleCondition/Flipped.md) or [Topple](../../Actors%20states/BattleCondition/Topple.md) conditions for exactly 1 turn left, the following occurs:
- Both the [Flipped](../../Actors%20states/BattleCondition/Flipped.md) and [Topple](../../Actors%20states/BattleCondition/Topple.md) conditions are removed via [RemoveCondition](../../Actors%20states/Conditions.md) on the enemy party member
- [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called on the enemy party member with a height of 10.0
- entity.`overrideanim` is set to false
- entity.`basestate` and entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 0 (`Idle`)
- startstate is set to 0 (`Idle`)
- 0.1 seconds are yielded
After, a couple of local variables are initialised which are enemy actions specific:
- chance: A random integer between 0 and 100 exclusive (100 possible outcome)
- chances: A float array starting at null
- hardmode: A boolean that is true if any of the following is true (false if none are):
- The `DoublePain` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped
- [flags](../../../Flags%20arrays/flags.md) 614 is true (HARDEST is active)
- [flags](../../../Flags%20arrays/flags.md) 166 is true (EX mode active on the B.O.S.S system)
- pos: A vector starting at Vector3.zero
After, if the enemy party member [isdefending](../../Actors%20states/Enemy%20features.md#isdefending):
- The enemy party member's `isdefending` is set to false
- startstate is set to entity.`basestate`
- entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to its `basestate`
Finally, all frames are yielded while entity is not `onground`.
#### Enemy action loop
Enemy actions works differently than player action in the sense they are all executed inside an infinite loop. This gives the ability for an action to perform many iterations before completing.
The action logic is determined by a giant switch on the enemy party member's `animid` which is its [enemy](../../../Enums%20and%20IDs/Enemies.md) id.
TODO: Document the enemy actions in part 3 of the battle docs in a separate place.
### Post action
This phase occurs after any actions. It starts with logic that allways occur no matter the action:
- If `demomode` is true, the `helpbox` is destroyed if it existed
- If entity has the `Enemy` tag, actionid is overriden to its corresponding enemy party member index
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
From there, what follows depends on if the actionid is -555 or not (whether this is a blank dummy call or not).
If it is, the only logic that happens is `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md) followed by skipping to the cleanup phase.
If it's not, the full post action logic occurs with 2 distinct branche:
- fled is false meaning the action didn't signaled that the enemy party member fled the battle
- fled is true meaning the action signaled that the enemy party member fled the battle
In either cases, they both end by setting all enemy party members's `lockposition` to false once they are done.
#### No fled enemy post action
- entity.`overrideanimspeed` is set to false
- entity.`spin` is zeroed out
- `playertargetID` is reset to -1
- `killinput` is set to true
- FlipAngle is called on the entity
- entity.`overrideanim` is reset to false
- entity.`overrideflip` is set to true
- entity.`rigid` gravity is enabled
- 0.15 seconds are yielded
- If the distance with the entity's position and startp is greater than 0.35, PlayMoveSound is called with the entity which plays its corresponding move sound if one exists for its [animid](../../../Enums%20and%20IDs/AnimIDs.md) using the audio source 9
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called on the entity to move towards startp with a multiplier of 2.0 using its `walkstate` as the state and startstate as the stopstate
- All frames are yielded while the entity is in a `forcemove`
- The audio source 9 has its sound stopped if applicable (this is the move sound played earlier if one existed)
- A frame is yielded
- entity's position is set to startp
- entity.`flip` is reset to flip
- entity.`overrideflip` is reset to false
- 0.15 seconds are yielded
- If randomposafter is true, an attempt with be made to change the enemy party member's [position](../../Actors%20states/BattlePosition.md) by generating a 50/50 random position between `Ground` and `Flying`. If the position changed from its previous one, the following is performed (in either cases, entity.`oldid` is reset to -1 after):
- If the new enemy party member's [position](../../Actors%20states/BattlePosition.md) is `Ground`:
- As long as entity.`height` is higher than entity.`minheight`, the `Fall` AnimationClip is played on entity.`anim` followed by entity.`height` being decreased by 0.075 of the game's frametime followed by a frame yield
- entity.`onground` is set to true
- entity.`height` is set to entity.`minheight`
- entity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to its `basestate`
- A frame is yielded
- If the entity.`originalid` isn't the `BeeBot` [animids](../../../Enums%20and%20IDs/AnimIDs.md), entity.`basestate` in enum string format is played on entity.`anim` (this implies entity.`basestate` must be a [predefind animation](../../../Entities/EntityControl/Animations/animstate.md#predefined-animations-names))
- Otherwise (the new [position](../../Actors%20states/BattlePosition.md) is `Flying`):
- `Idlef` is played on entity.`anim`
- All frames are yielded while entity.`height` is less than 1.9 (entity.`height` is increased by 0.075 of the game's frametime each time before the frame yield)
- entity.`bobrange` is reset to entity.`startbf`
- entity.`bobspeed` is reset to entity.`startbs`
- entity.`height` is set to 2.0
- [UpdateAnimSpecific](../../../Entities/EntityControl/Animations/AnimSpecific.md#updateanimspecific) is called on the entity
- If the entity has the `Player` tag (this is a player party member):
- If usedtp is above 0, nocharm is false and [currentaction](../../Player%20UI/Pick.md) isn't `ItemList` (meaning a skill was used that had a paid cost to it while healing charms aren't disallowed):
- [flagvar](../../../Flags%20arrays/flagvar.md) 1 is set to usedtp / 2 clamped from 1 to usedtp (the integer division floors implicitly)
- `checkingdead` is set to a new [UseCharm](../UseCharm.md) call with the type being `HealTP` which heals for the amoutn set to flagvar 1 just before
- All frames are yielded while `checkingdead` is in progress
- `playerdata[currentturn]`'s `tired` is incremented if [currentaction](../../Player%20UI/Pick.md) isn't `ItemList` and actionid is not among the following (these are all the team moves, the reason they are exempted from exhaustion is because their individual action logic already took care of incremented the proper `tired` fields so this would have been a second, unwanted increment):
- 5 (`BeeFly`)
- 26 (`IceBeemerang`)
- 27 (`IceDrill`)
- 31 (`IceSphere`)
- `playerdata[currentturn]`'s `tired` is incremented again if `turns` is 0 (meaning this is the first turn of the battle) while the `StrongStart` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped
- Unless `dontusecharge` is true, `playerdata[currentturn]`'s `charge` is reset to 0
- [EndPlayerTurn](../EndPlayerTurn.md) is called
- [currentaction](../../Player%20UI/Pick.md) is set to `BaseAction`
- `option` is set to `lastoption` (this restores the main vine menu's selection to whichever was the last one selected)
- If [GetFreePlayerAmmount](../../Actors%20states/Player%20party%20members/GetFreePlayerAmmount.md) returns at least 1, [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- Otherwise, if `selfsacrifice` is false (the enemy party member didn't killed themselves during their action):
- If the enemy party member had any `delayedcondition`:
- All `delayedcondition` are processed. See the [delayed condition](../../Actors%20states/Delayed%20condition.md) documentation to learn more
- If any `delayedcondition`'s processing caused a [condition](../../Actors%20states/Conditions.md) to be inflicted, the enemy party member's `cantmove` is set to 0 (EndEnemyTurn will later advance it making it 1 which means one actor turn needs to pass before an action is available)
- If the enemy party member's [position](../../Actors%20states/BattlePosition.md) is `Flying` while its [cantfall](../../Actors%20states/Enemy%20features.md#cantfall) is false, entity.`droproutine` is set to a new [Drop](../../../Entities/EntityControl/EntityControl%20Methods.md#drop) coroutine on the entity
- 0.5 seconds are yielded
- The enemy party member's `delayedcondition` is set to null
- If nocharm is false (healing charms weren't disallowed):
- `checkingdead` is set to a new [UseCharm](../UseCharm.md) call with the type being `HealHP`
- All frames are yielded while `checkingdead` is in progress
- If the enemy party member was performaning a [hitaction](../../Actors%20states/Enemy%20features.md#hitaction), `enemy` is set to false, giving control back to the player party
- [EndEnemyTurn](../EndEnemyTurn.md) is called with the actionid
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- If this isn't a `firststrike`:
- A [CheckDead](CheckDead.md) is done without storing the coroutine
- Otherwise, `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- If this isn't a `firststrike` and any enemy party member has their battleentity.`droproutine` in progress:
- `action` is set to true switching to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- `startdrop` is set to true which allows any existing enemy party members to fall during their `droproutine`
- All frames are yielded while an enemy party member still has its battleentity.`droproutine` in progress (it also constantly set `startdrop` to true to make sure they can drop)
- `startdrop` is reset to false
- `action` is reset to false switching back to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
#### Fled enemy post action
- [EndEnemyTurn](../EndEnemyTurn.md) is called witht the actionid
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- A [CheckDead](CheckDead.md) is performed, but the coroutine isn't stored anywhere.
### Cleanup
This is the last phase of the coroutine:
- `selfsacrifice` is reset to false
- A frame is yielded
- `lastkill` is reset to -1

View File

@@ -0,0 +1,53 @@
# Relay
This is an action coroutine that invokes the relay mechanic which allows a player party member to donate their actor turn to another. It also handles the animations and the `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md) effects when applicable.
The coroutine excepts to have the player party member whose index is `currentturn` to relay to the one whose index is `option`.
## Setup
- `action` is set to true changing to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- [UpdateText](../../Visual%20rendering/UpdateText.md)
- A frame is yielded
- The `Relay` sound is played
## Relay animation
- Both the `currentturn` and `option`'s matching player party member's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) are set to 4 (`ItemGet`) and their battleentity.`spin` to (0.0, -20.0, 0.0)
- 0.3 seconds are yielded
- During the course of 10.0 frames (tracked by a local counter advancing by 1/10 of the game's frametime starting at 0.0 reaching 1.0), both the `currentturn` and `option`'s matching player party member's battleentity.`spin` are lerped from (0.0, -20.0, 0.0) to Vector3.zero linearly over the course of those 10.0 frames
- Both the `currentturn` and `option`'s matching player party member's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) are set to 0 (`Idle`) and their battleentity.`spin` are zeroed out
- `receivedrelay[option]` is set to true (this allows the `tiredpart` to be rendered on the player party member whenever their `tired` goes above 0 during [UpdateAnim](../../Visual%20rendering/UpdateAnim.md))
- A frame is yielded
## The actual relay
- The `currentturn`'s player party member's `haspassed` is set to true (indicating it already relayed disallowing to relay again)
- The `option`'s player party member's `cantmove` is decremented (this adds advances the actor turn, but it needs to be at 0 or above for an action to be possible still)
## `RelayTransfer` [medal](../../../Enums%20and%20IDs/Medal.md) effects
If that medal is equipped on the `currentturn`'s player party member's `trueid`, the effects will be performed (this section is skipped if it's not equipped):
Essentially, how it works is the `currentturn`'s player party member's [condition](../../Actors%20states/Conditions.md) are checked and all of the ones that aren't in the following list will be removed (by reseting the `condition` field to a new array without the ones to remove):
- [Topple](../../Actors%20states/BattleCondition/Topple.md)
- [Flipped](../../Actors%20states/BattleCondition/Flipped.md)
- [Shield](../../Actors%20states/BattleCondition/Shield.md)
- [Eaten](../../Actors%20states/BattleCondition/Eaten.md)
- [EventStop](../../Actors%20states/BattleCondition/EventStop.md)
- [Reflection](../../Actors%20states/BattleCondition/Reflection.md)
The conditions removed will be added to the `option`'s player party member via [SetCondition](../../Actors%20states/Conditions%20methods/SetCondition.md) using the same `BattleCondition` and actor turn counter. This does imply they can amend existing conditions.
If at least one condition is transfered, the `Charge10` sound will play when the first condition is transfered so it plays only once.
It also transferts `charge`: the `currentturn`'s player party member's `charge` is set to the existing one + the `option`'s clamped from 0 to 3 while the `option`'s player party member's `charge` gets set to 0.
The logic ends by calling [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) followed by UpdateConditionIcons being called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true).
## Finalising the relay
- [EndPlayerTurn](../EndPlayerTurn.md) is called which advances the actor turn
- [CancelList](../../Player%20UI/CancelList.md) is called
- A frame is yielded
- `action` is set to false changing to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called

View File

@@ -0,0 +1,37 @@
# SwitchParty
This action coroutine alloews to rotate the party once. It is possible to do it without a fancy visual animation.
```cs
private IEnumerator SwitchParty(bool fast)
```
> NOTE: The process of switching is complex and involves [battle `playerdata` addressing documentation](../../playerdata%20addressing.md#methods-of-addressing-durring-battle). It is recommended to check this documentation to fully understand how a party rotation works.
## Parameters
- `fast`: Whether to include vidual animations and waiting.
## Procedure
- `action` is set to true changing to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- `currentturn` is set to -1 which unselects the current player party member
- SetLastTurns is called which resets `lastturns` to a new aray with the length being the amount of free players - 1 and all elements being -1 (this resets the player selection cycle)
- If fast is false
- All player party members has their battleentity.`spin` set to (0.0, -20.0, 0.0)
- 0.33 seconds are yielded
- MainManager.SwitchParty is called with the battle version which rotates the `partypointer` elements
- 0.1 seconds are yielded
- For each player party members, the second part of the rotation is performed:
- battleentity.`overridejump` is set to true
- battleentity.`spin` is zeroed out
- `pointer` is set to the matching `partypointer`. This gives a way to do the same function than `partypointer`, but using `playerdata` indexes. In practice, this feature is UNUSED because the field is only written to
- `playerdata[partypointer[j]]`.battleentity position is set to the matching `partypos`. This can be thought as the player party member who had this formation position in the player party is moved to be physically at the matching position of that formation position
- If battleentity.`deathcoroutine` is in progress, it is stopped and set to null followed by battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) being set to 18 (`KO`)
- 0.7 seconds are yielded if fast is false
- [CancelList](../../Player%20UI/CancelList.md) is called
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- A frame is yielded
- `action` is set to false changing to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- A frame is yielded (this frame will process in a controlled flow, but the rest is just visual updates so it's safe)
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called

View File

@@ -0,0 +1,38 @@
# SwitchPos
This action coroutine alloews to swap 2 player party member's position with each other.
```cs
private IEnumerator SwitchPos(int called, int targeted)
```
> NOTE: The process of switching is complex and involves [battle `playerdata` addressing documentation](../../playerdata%20addressing.md#methods-of-addressing-durring-battle). It is recommended to check this documentation to fully understand how a party swap works.
## Parameters
- `called`: The `playerdats` index that is requesting the swap
- `targeted`: The `playerdata` index that was targetted for swapping by the `called`'s player party member's action
## Procedure
- The `Switch` sound is played
- `action` is set to true changing to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- `currentturn` is set to -1 which unselects the current player party member
- SetLastTurns is called which resets `lastturns` to a new aray with the length being the amount of free players - 1 and all elements being -1 (this resets the player selection cycle)
- The called and targeted player party members has their battleentity.`spin` set to (0.0, -20.0, 0.0)
- 0.33 seconds are yielded
- The `partypointer` indexes that maps to the called and targeted `playerdata` indexes are found and their value are set to called and targeted respectively (essentially, this converts called and targeted from `playerdata` indexes to `partypointer` indexes)
- Both `partypointer` elements whose indexes matches the ones found are swapped. This essentially completes the first party of the swap
- 0.1 seconds are yielded
- For each player party members, the second part of the swap is performed:
- battleentity.`overridejump` is set to true
- battleentity.`spin` is zeroed out
- `pointer` is set to the matching `partypointer`. This gives a way to do the same function than `partypointer`, but using `playerdata` indexes. In practice, this feature is UNUSED because the field is only written to
- `playerdata[partypointer[j]]`.battleentity position is set to the matching `partypos`. This can be thought as the player party member who had this formation position in the player party is moved to be physically at the matching position of that formation position
- If battleentity.`deathcoroutine` is in progress, it is stopped and set to null followed by battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) being set to 18 (`KO`)
- [CancelList](../../Player%20UI/CancelList.md) is called
- UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- A frame is yielded
- `action` is set to false changing to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- A frame is yielded (this frame will process in a controlled flow, but the rest is just visual updates so it's safe)
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called

View File

@@ -0,0 +1,88 @@
# Tattle
This action coroutine allows a player party member to spy an enemy party member if they pass an action command. The spy will only proceeed if `disablespy` is false, otherwise, the logic is limited to play the buzzer sound and calling [UpdateAnim](../../Visual%20rendering/UpdateAnim.md).
The coroutine expects `playerdata[currentturn]` to be the player party member that attemps the spying and for `avaliabletargets[option]` to be the enemy party member being spied.
## Action command setup
- DestroyHelpBox is called which sets `helpboxid` to -1 and destroys `helpbox` if it existed in 0.5 seconds with shrink before setting it to null
- `action` is set to true changing to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- `caninputcooldown` is set to 0.0
- `blockcooldown` is set to 0.0
- `combo` is set to 0
- `killinput` is set to false
- `nonphysical` is set to false
- `commandsuccess` is set to false
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
From there, if the `HPScope` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped, this will bypass the action command portion and the logic will be limited to playing the `AtkSuccess` sound and everything will continue as if `commandsuccess` was true.
Otherwise, the action command is done by calling [DoCommand](../../Action%20commands/DoCommand.md) with the timer being 60.0, the type being `Crosshais` and the data being {3.0, the battleentity.`battleid` of the target enemy party member converted to float, 3.25, 10.0}. From there, all frames are yielded while `doingaction` is true.
## Spying process
This section only happens if the `HPScope` [medal](../../../Enums%20and%20IDs/Medal.md) was equipped or `commandsuccess` is true meaning the player passed the action command. If these conditions are fufilled, the logic of this section is limited to setting the player party member's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) to 11 (`Hurt`).
- The `currentturn` player party member's battleentity.`spin` is set to (0.0, 20.0, 0.0)
- The `currentturn` player party member's battleentity.`animstate` is set to 4 (`ItemGet`)
- 0.65 seconds are yielded
- The `currentturn` player party member's battleentity.`animstate` is set to 13 (`BattleIdle`)
- The `currentturn` player party member's battleentity.`spin` is zeroed out
- The [SetText text advance](../../../SetText/Related%20Systems/Text%20advance.md)'s `skiptext` is set to false
- [waitinput](../../../SetText/Notable%20states.md#waitinput) is set to false
- instance.`inputcooldown` is set to 15.0
- A frame is yielded
- [SetText](../../../SetText/SetText.md) is called in [dialogue mode](../../../SetText/Dialogue%20mode.md#dialogue-mode) with the text being `|`[fwait](../../../SetText/Individual%20commands/Fwait.md)`,0.075||`[spd](../../../SetText/Individual%20commands/Spd.md),`-1||`[stopskip](../../../SetText/Individual%20commands/Stopskip.md)`|` followed by the correspondong tattle line from the `currenturn` player party member's `trueid` from [enemytattle](../../../TextAsset%20Data/Enemies%20data.md#enemytattle-data) data using the enemy party member's `animid` as the [enemy](../../../Enums%20and%20IDs/Enemies.md) id. The call also has these properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- linebreak of `messagebreak`
- No tridimensional
- position of Vector3.zero
- No cameraoffset
- size of Vector3.one
- parent being `currentturn`'s player party member's battleentity
- No caller
- A frame is yielded
- A nameless pure white 9Box is created with position (20.0, 0.0, 10.0), size of (10.75, 5.0) type 4 (torn piece of paper), sortorder of -20 without grow and a DialogueAnim attached with a targetpos of (3.5, -1.75, 10.0) and a speed of (0.1) (this DialogueAnim makes the 9Box appear from offsreen to the right slightly down)
- A new UI object named `enemyimage` is created childed to the 9Box with local position (-2.85, 0.0, 0.0), size of (3.0, 3.0, 3.0) and a sortOrder of 0 using the sprite defined as the portrait from [enemydata](../../../TextAsset%20Data/Enemies%20data.md#about-the-portrait-srpite-index) using the enemy party member's `animid` as the [enemy](../../../Enums%20and%20IDs/Enemies.md) id
- A string of text is prepared which are all the following appended together:
- `|`[single](../../../SetText/Individual%20commands/Single.md)`|`
- If the [languageid](../../../SetText/languageid.md) is `Japanese` and the enemy party member's `entityname` is 6 or more letters long, `|`[size](../../../SetText/Individual%20commands/size.md)`,X,1|` is appended where `X` is 1.0 - 0.075 * (the enemy party member's `entityname`'s length - 5) all clamped from 0.5 to 0.65 (notthing is appended otherwise)
- `|`[line](../../../SetText/Individual%20commands/Line.md)`||`[halfline](../../../SetText/Individual%20commands/Halfline.md)`||`[size](../../../SetText/Individual%20commands/size.md)`,1,1,lock|`
- `menutext[14]` (HP)
- `: `
- The enemy party member's `maxhp`. If the `DoublePain` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped or [flag](../../../Flags%20arrays/flags.md) 614 is true (HARDEST is active), it's the `maxhp` + `hardhp` instead
- `|`[line](../../../SetText/Individual%20commands/Line.md)`|`
- `menutext[17]` (Defense)
- `: `
- The enemy party member's `def`. If the `DoublePain` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped or [flag](../../../Flags%20arrays/flags.md) 614 is true (HARDEST is active), it's the `def` + `harddef` instead. There is an exception however: if that number is negative, `???` is appended instead of the number
- `|`[line](../../../SetText/Individual%20commands/Line.md)`|`
- If the [languageid](../../../SetText/languageid.md) is `Japanese`, `|`[size](../../../SetText/Individual%20commands/size.md)`,0.8,1,force|` is appended (nothing otherwise)
- `menutext[137]` (Seen)
- `: `
- The seen counter of the matching [bestiary entry](../../../Enums%20and%20IDs/librarystuff/Bestiary%20entry.md) of the enemy party member
- `|`[line](../../../SetText/Individual%20commands/Line.md)`|`
- `menutext[138]` (Defeated)
- `: `
- The defeated counter of the matching [bestiary entry](../../../Enums%20and%20IDs/librarystuff/Bestiary%20entry.md) of the enemy party member
- [SetText](../../../SetText/SetText.md) is called in [non dialogue mode](../../../SetText/Dialogue%20mode.md#non-dialogue-mode) using the string assembled with the following properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- No linebreak
- No tridimensional
- position of (-0.65, 1.3. 0.0)
- No cameraoffset
- size of Vector3.one
- parent being the 9Box
- No caller
- All frames are yielded while the [message](../../../SetText/Notable%20states.md#message) lock is grabbed
- The [bestiary entry](../../../Enums%20and%20IDs/librarystuff/Bestiary%20entry.md) of the [enemy](../../../Enums%20and%20IDs/Enemies.md) is updated via UpdateJounal to unlock it in `librarystuff`
- The 9Box's DialogueAnim's `targetpos` is set to (20.0, 0.0, 10.0) (this sets it to move offscreen to the right)
- The 9Box is destroyed in 1.0 second
## Cleanup
- 0.5 seconds are yielded
- Unless the `HPScope` [medal](../../../Enums%20and%20IDs/Medal.md) was equipped, [EndPlayerTurn](../EndPlayerTurn.md) is called which advances the player party member's actor turn
- [CancelList](../../Player%20UI/CancelList.md) is called
- A frame is yielded
- `action` is set to false changing to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called

View File

@@ -0,0 +1,95 @@
# TryFlee
This action coroutine allows the player to attempt to flee from the battle if an action command is passed. This allows to go directly to the [ReturnToOverworld](../Terminal%20coroutines/ReturnToOverworld.md) in a [terminal flow](../Update.md#terminal-flow) if the action command is passed. If the action command is failed, all player party members gets all their action turns exhausted which leads to [EndPlayerTurn](../EndPlayerTurn.md) earlier than usual.
## Command preparation
- `action` is set to true changing to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- `commandsuccess` is reset to false
- instance.`showmoney` is set to 100000000.0 which effectively makes the berry count HUD element shown permanently for now
- The instance.`camtargetpos` is set to (-4.5, 0.0, 2.5) with an instance.`camspeed` of 0.075
- 10 RigidBodies are initialised to hold lost berries (they each get a SpriteRenderer using the `MoneySmall`'s `itemsprites`) childed to the `battlemap` in kinematic mode, but initially placed offscreen at (0.0, 999.0, 0.0)
- The `FlipNoise` sound is played
- For each player party member that isn't [IsStopped](../../Actors%20states/IsStopped.md), the following adjustements happens on their battleentity (this setups their walk in place animations):
- `anim`.speed is set to 2.0
- `overridejump` is set to true
- [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called
- `flip` is set to false
- `overrideanim` is set to true
- [animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 1 (`Walk`)
- 0.4 seconds are yielded
- A [DoCommand](../../Action%20commands/DoCommand.md) coroutine is started with a commandtype of `SequentialKeys` using 250.0 as the timer and the data being one element whose value is 6 unless the `SpeedUp` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped which makes the value 3 instead
## Performing the action command
This section is in effect as long as `doingaction` is true. It's where the berry loss happens periodically when applicable. A frame is yielded at the end of every cycle when this section is in effect.
In order for a berry to be lost, the following must be true:
- instance.`money` must be above 0
- The `SecurePouch` [medal](../../../Enums%20and%20IDs/Medal.md) is unequipped
- [flags](../../../Flags%20arrays/flags.md) 162 is false (We aren't in a B.O.S.S or Cave of Trials session)
- A certain amount of frames has passed (tracked by a local framecounter using instance.`framestep` as the increment)
The amount of frames that needs to pass to loose a berry depends on `estimatedexp`. It is calculated by taking (30 - `estimatedexp`) / 2, clamping it from 5 to instance.`neededexp` / 2 and finally, multiply the result by 2.0 which also casts it to a float for the counter comparison. What this intuitively mean is that the amount of frames before a berry is lost is always between 5 and 15, but the base amount decreases the more EXP has been accumulated so far. As for the upper clamping bound, it doesn't do anything because the minimum value of instance.`neededexp` is normally 100 making its half 50 which is higher than 15, the upper bound of the base value if `estimatedexp` is 0.
All in all, this can be reduced to just (30 - `estimatedexp`) / 2 clamped from 5 making the overall result from 5 to 15 frames between loosing a berry.
If no berry losses occurs, the local counter is incremented by instance.`framestep`.
If a berry loss occurs, the following is done on one of the 10 RigidBodies initialised earlier (the index starts at 0 and increments each berry loss, resetting to 0 when reaching 10):
- position is set to a randomly selected player party member's battleentity's position
- kinematic mode is turned off
- velocity is set to RandomItemBounce(4.0, 15.0)
The berry loss ends by decrementing instance.`money` and resetting the local frame counter to 0.0.
## Handling the action command result
The rest of the coroutine depends on `commandsuccess` being true or not indicating the command was succeeded or failed. In either outcome, all RigidBodies initialised earlier are destroyed at the very end.
### Success
This section is applicable if `commandsuccess` is true:
- MainManager.`battleresult` is set to false
- For each player party member that isn't [IsStopped](../../Actors%20states/IsStopped.md), [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called on their battleentity
- 0.45 seconds are yielded
- The `Flee` sound is played
- For each player party member that isn't [IsStopped](../../Actors%20states/IsStopped.md), the following happens on their battleentitty:
- The y position is set to 0.0
- The `rigid`'s gravity is disabled
- [MoveTowards](../../../Entities/EntityControl/EntityControl%20Methods.md#movetowards) is called to move to (-20.0, 0.0, 0.0) with a multiplier of 5.0
- All frames are yielded until the `forcemove` of the battleentity of the last player party member that isn't [IsStopped](../../Actors%20states/IsStopped.md) goes to false (meaning the last player party member that was moved is done with its `forcemove`)
- [flagvar](../../../Flags%20arrays/flagvar.md) 42 (number of fleed battles) is incremented
- [ReturnToOverworld](../Terminal%20coroutines/ReturnToOverworld.md) is called with flee
### Fail
This section is applicable if `commandsuccess` is false:
- The `Fail` sound is played
- For each player party member that isn't [IsStopped](../../Actors%20states/IsStopped.md), the following happens on their battleentitty (this undo what was done on the command preparations with some more animations):
- `anim`.speed is reset to 1.0
- `overrideanimspeed` is set to false
- [Jump](../../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called
- [animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`)
- 0.1 seconds are yielded
- For each player party member that isn't [IsStopped](../../Actors%20states/IsStopped.md), the following happens on their battleentitty:
- DeathSmoke is called with the battleentity
- [animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 18 (`KO`)
- The `Drop` sound is played on the entity (not the battleentity)
- If [flags](../../../Flags%20arrays/flags.md) 162 is false (we aren't in a B.O.S.S or Cave of Trials session), all of the 10 RigidBodies will count as a berry loss meaning up to 10 berries are lost (or instance.`money` berries is lost if less than 10 remained). The following happens for each loss on the concerned RigidBody:
- position is set to a randomly selected player party member's battleentity's position
- kinematic mode is turned off
- velocity is set to RandomItemBounce(4.0, 15.0)
- instance.`money` is decremented
- A frame is yielded
- 0.85 seconds are yielded
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- For each player party member that isn't [IsStopped](../../Actors%20states/IsStopped.md), the following happens on their battleentitty:
- `overridejump` is set to false
- `overrideanim` is set to false
- `flip` is set to true
- The player party member's `cantmove` is set to 1 except for the `currentturn` one where it's set to 0 (this is because its turn will be exhausted soon so all member's `cantmove` will end up at 1)
- A frame is yielded
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- instance.`showmoney` is set to -1 which hides the berry count HUD
- [EndPlayerTurn](../EndPlayerTurn.md) is called (which will increment the `currentturn` player party member so all members's `cantmove` ends up at 1)
- `action` is set to false switching back to a [controlled flow](../Update%20flows/Controlled%20flow.md)

View File

@@ -0,0 +1,221 @@
# UseItem
This action coroutine allows the player party member to use an [item](../../../Enums%20and%20IDs/Items.md). It receives its id in a parameter which should corresponds to the one that was selected during [GetChoiceInput](../../Player%20UI/GetChoiceInput.md) after passing the CheckItemUse check.
## Setup
- `action` is set to true switching to an [uncontrolled flow](../Update%20flows/Uncontrolled%20flow.md)
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- The `ItemHold` sounds is played
- `lastitemuser` is set to the `trueid` of the `currentturn` player party member
- A new temporary item object is created with a SpriteRenderer using the corresponding item's sprite from [items data](../../../TextAsset%20Data/Items%20data.md) using the standard spritemat with a renderQueue of 50000 on layer 14 (`Sprite`). The object is positioned at the `currentturn` player party member's battleentity's position + its `cursoroffset` - (0.0, 0.0, 0.1)
- The `currentturn` player party member's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 4 (`ItemGet`)
## `BanditLeader` specific logic
This coroutine has special logic if a `BanditLeader` [enemy](../../../Enums%20and%20IDs/Enemies.md) is present in the enemy party. When that happens, this coroutine will not apply any item effects and it will instead end abruptly with a yield break after some animations and cleanup logic. This logic is what this section is about. It doesn't apply if no `BanditLeader` is present.
If it does apply, the enemy party member index of the first `BanditLeader` is saved locally and used for this section.
- 0.25 seconds are yielded
- The `BanditLeader`'s battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is saved locally for restore later
- [HealConditions](../../Actors%20states/Conditions%20methods/HealConditions.md) is called on the `BanditLeader`
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- The `BanditLeader`'s battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 103
- The `Slash2` sound is played
- 0.5 seconds are yielded
- Gleam is called on the `BanditLeader`'s battleentity using the offset (-0.4, 2.35, -0.1) which plays the `Gleam` particles and sound
- 0.5 seconds are yielded
- The `Slash` sound is played
- The `BanditLeader`'s battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 107
- MainManager.FadeIn is called with a speed of 1.0 (which makes the screen go to black instantly)
- 0.25 seconds are yielded
- ItemDrop is called on the temporary item object which will do the following:
- The object gets rooted to the scene
- A RigidBody component is added with a velocity of RandomItemBounce(5.0, 12.5)
- The object is destroyed in 1.0 second
- The `currentturn`'s battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`)
- MainManager.FadeOut is called with a speed of 1.0 (which makes the screen go back to what it was before the fade in instantly)
- The `ItemStolen` sound is played
- 0.65 seconds are yielded
- The `BanditLeader`'s battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is restrored to the saved value
- The first occurence of the item corresponding to the sent id is removed from instance.`items[0]` (standard items)
- [CancelList](../../Player%20UI/CancelList.md) is called
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- [EndPlayerTurn](../EndPlayerTurn.md) is called
- `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- Yield break which ends this coroutine
## Pre item effects
This section happens if the `BanditLeader` specific logic didn't apply.
- 1.3 seconds are yielded
- The temporary item object is destroyed
- `deadmembers` is set to GetDeadParty which is all player party member indexes whose `hp` is 0 or below in ascending order
- The `currentturn` player party member's battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 13 (`BattleIdle`)
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
## Item effects
This section depends on the [itemarea](../../Player%20UI/AttackArea.md).
### `SingleAlly` or `AllParty`
This first starts by having all frames yielded while PartyIsDying which means that at least one player party member's `hp` is 0 or below while its battleentity.`deathroutine` is still in progress.
From there, the ItemUse elements of the item are processed by first calling [DoItemEffect](../../../TextAsset%20Data/Items%20data.md#doitemeffect) with the element's information and `option` as the characterid.
After, there's additional logic depending on the ItemUsage.
#### `HPRecover` or `HPRecoverFull`
- HealParticle is called on the `option` player party member with a size of Vector3.one and an offset of Vector3.up
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 1 (HP) with the ammount being the return of DoItemEffect starting at the `playerdata[option].battleentity`'s position + `playerdata[option].cursoroffset` and ending at Vector3.up
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `Revive`
The same than `HPRecover` or `HPRecoverFull`, but if the `option` player party member's battleentity is `dead`, [RevivePlayer](../../Actors%20states/Player%20party%20members/RevivePlayer.md) is called with its id for -1 hp and showcounter as false.
#### `TPRecover` or `TPRecoverFull`
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 2 (TP) with the ammount being the return of DoItemEffect starting at the `playerdata[option].battleentity`'s position + `playerdata[option].cursoroffset` and ending at Vector3.up
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `HPRecoverAll`
This effect applies to each player party member that isn't `eatenby` and has an `hp` above 0:
- HealParticle is called on the player party member with a size of Vector3.one and an offset of Vector3.up
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 1 (HP) with the ammount being the return of DoItemEffect starting at the `playerdata[option].battleentity`'s position + `playerdata[option].cursoroffset` and ending at Vector3.up
If at least one player party member was affected and there's more than 1 effect, 0.5 seconds are yielded before processing more.
#### `ReviveAll`
The same than `HPRecoverAll`, but it also affects player party members with an `hp` of 0 or below and if its battleentity is `dead`, [RevivePlayer](../../Actors%20states/Player%20party%20members/RevivePlayer.md) is called with its id for -1 hp and showcounter as false.
#### `HPorDamage`
- An RNG check is performed with 2 possible outcomes at 66% and 34% respectively:
- 66%: [Heal](../../Actors%20states/Heal.md) is called on the `option` player party member with the ammount being the returned value of DoItemEffect
- 34%: [DoDamage](../../Damage%20pipeline/DoDamage.md) is called without an attacker to the `option` player party member with the damageammount being the returned value of DoItemEffect with a `NoExceptions` property and without block
- The `hp` of the `option` player party member is clamped from 1 to its `maxhp`
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `Battle`
An action may be set to trigger in the post item effect section depending on the item id:
- `VitalitySeed`: 14
- `GenerousSeed`: 15
- `ShellOil`: 33
#### `AddPoison`
The `PoisonEffect` particle are played without sound at the `option` player party member's battleentity's position.
#### `AddNumb`
The `ElecFast` particle are played without sound at the `option` player party member's battleentity's position + Vector3.up all scaled by (1.5, 1.5, 1.5).
#### `AddFreeze`
- The `mothicenormal` particle are played without sound at the `option` player party member's battleentity's position + Vector3.up all scaled by (1.5, 1.5, 1.5)
- If the `option` player party member has a [Freeze](../../Actors%20states/BattleCondition/Freeze.md) ondition and its battleentity.`icecube` is null or inactive, [Freeze](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#freeze) is called on the battleentity
#### `AddSleep`
DeathSmoke particles are played at the `option` player party member's battleentity's position
#### `TurnNextTurn`
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with the `option` player party member's battleentity with type 5 (orange up arrow)
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `CureNumb`
- The `option` player party member's `isnumb` is set to false
- The `CurePoison` effects applies
#### `CureFreeze`
- [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#breakice) is called on the `option` player party member's battleentity
- The `CurePoison` effects applies
#### `CureSleep`
- The `option` player party member's `isasleep` is set to false
- The `CurePoison` effects applies
#### `CureParty`
- For each player party members that isn't `eatenby` and has an `hp` above 0:
- `isnumb` is set to false
- [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#breakice) is called on the battleentity
- `isasleep` is set to false
- The `CurePoisonAll` effects applies
#### `CurePoison`, `GradualHP`, `GradualTP`, `CureFire` or `CureAll`
- The `MagicUp` particle are played without sound at the `option` player party member's battleentity's position
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `CurePoisonAll`
- The `MagicUp` particle are played without sound at each of the player party members's battleentity's position who isn't `eatenby` and whose `hp` is above 0
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `ChargeUp`
- The `StatUp` sound is played
- [StatEffect](../../Visual%20rendering/StatEffect.md) is called with the `option` player party member's battleentity with type 4 (green up arrow)
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `GradualHPParty`
The `MagicUp` particle are played without sound at each of the player party members's battleentity's position who isn't `eatenby` and whose `hp` is above 0
#### `HPto1`
- [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) is called with type 0 (Damage) with the ammount being the `option` player party member's `maxhp` - 1 starting at its battleentity's position and ending at (-1, 2.0, 0.0)
- [DoDamageAnim](../../Visual%20rendering/DoDamageAnim.md) is called with the `option` player party member with a damage of its `maxhp` - 1 without block
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `AtkUpStat`
- [StatusEffect](../../Actors%20states/Conditions%20methods/StatusEffect.md) is called with the `option` player party member using the [AttackUp](../../Actors%20states/BattleCondition/AttackUp.md) condition with the amount of turns being the returned value from DoItemEffect with effect being true
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `DefUpStat`
- [StatusEffect](../../Actors%20states/Conditions%20methods/StatusEffect.md) is called with the `option` player party member using the [DefenseUp](../../Actors%20states/BattleCondition/DefenseUp.md) condition with the amount of turns being the returned value from DoItemEffect with effect being true
- If there's more than 1 effect, 0.5 seconds are yielded before processing more
#### `Sturdy`
- [flagvar](../../../Flags%20arrays/flagvar.md) 0 is set to the returned value from DoItemEffect
- The action id 33 is set to trigger in the post item effects section
### `SingleEnemy`, `AllEnemies` or `All`
An action will may be set to trigger in the post item effects section depending on the item id:
- `LonglegSummoner`: The -2 action id will be set to trigger
- If the item id is in the following list, the 9 action id will be set to trigger:
- `HardSeed`
- `SpicyBomb`
- `PoisonBomb`
- `ClearBomb`
- `NumbDart`
- `Ice`
- `FrostBomb`
- `NumbBomb`
- `SleepBomb`
- `Abombhoney`
- `PoisonDart`
- `CherryBomb`
- `BurlyBomb`
- `FlameRock`
## Post item effects
- The first occurence of the item corresponding to the sent id is removed from instance.`items[0]` (standard items)
- [CancelList](../../Player%20UI/CancelList.md) is called
- [UpdateAnim](../../Visual%20rendering/UpdateAnim.md) is called
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- If an action was set to trigger after the item use:
- [currentaction](../../Player%20UI/Pick.md) is set to `ItemList`
- [DoAction](DoAction.md) is called with the `currentturn` party member using the action id set to trigger earlier
- Otherwise:
- 0.5 seconds are yielded
- [EndPlayerTurn](../EndPlayerTurn.md) is called
- `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md)

View File

@@ -0,0 +1,137 @@
# AdvanceTurnEntity
This is a method only called by [AdvanceMainTurn](../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) that takes in an actor whose turn will be advanced and a ref to a bool value that will be set to true if there should be a delay after the turn advancement.
```cs
private void AdvanceTurnEntity(ref MainManager.BattleData t, ref bool delay)
```
## Parameters
- `t`: The actor to advance the turn
- `delay`: a dummy ref bool value. It should always have a false value before calling this method as the method only sets it to true in some cases, but never to false
## Procedure
There are 2 parts to this: [Conditions](../Actors%20states/Conditions.md) advances and state advance.
## [Conditions](../Actors%20states/Conditions.md) advances
This part goes through each `condition` and acts on them. This part refers to what happens to each individual condition unless stated otherwise.
There's 2 sections to this: alive advance and last advance.
### Alive advance
This section occur if the actor is alive and it depends on the `BattleCondtion`.
#### [Reflection](../Actors%20states/BattleCondition/Reflection.md)
The turn count of the condition is set to 0.
#### [Poison](../Actors%20states/BattleCondition/Poison.md)
If there is at least one enemy party member:
- If the actor is a player party member with a `ReversePoison` [medal](../../Enums%20and%20IDs/Medal.md) equipped:
- The actor's `hp` is increased by the actor's `maxhp` * 0.1 rounded to nearest clamped from 1 to 3. NOTE: the nearest rounding has a quirk where if it ends in .5, the even number will be chosen over the odd one no matter if it is actually the lower or higher bound that is correct mathematically
- If the `Heal` sound isn't playing or its more than halfway done player, it is played
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 1 with the damage amount as the amount healed earlier with the start being the battleentity position + (0.0, 1.0, 0.0) and the end being (0.0, 2.0, 0.0)
- Otherwise, [DoDamage](../Damage%20pipeline/DoDamage.md) is called to the actor with no attacker with a `NoExceptions` property without block. The damageammount is the actor's `maxhp` / 10.0 ceiled - 1 and then clamped from 1 to 3 for a player party member and from 1 to 2 for an enemy party member. The call also has these [overrides](../Damage%20pipeline/DamageOverride.md):
- `NoFall`
- `NoIceBreak`
- `FakeAnim`
- `DontAwake`
- `IgnoreNumb`
- If the actor's `hp` became 0, battleentity.`overrideanim` is set to false followed by an OverrideOver call being invoked on the battleentity in 1.0 seconds
- The actor's `hp` is clamped from 1 to its `maxhp`
- delay is set to true
#### [Fire](../Actors%20states/BattleCondition/Fire.md)
If there is at least one enemy party member:
- The `Flame` sound is played
- [DoDamage](../Damage%20pipeline/DoDamage.md) is called to the actor with no attacker with a `NoExceptions` property without block. The damageammount is the player party member's `maxhp` / 7.5 ceiled - 1 and then clamped from 2 to 3. The call also has these [overrides](../Damage%20pipeline/DamageOverride.md):
- `NoFall`
- `NoIceBreak`
- `FakeAnim`
- `DontAwake`
- `IgnoreNumb`
- If the actor's `hp` became 0, battleentity.`overrideanim` is set to false followed by an OverrideOver call being invoked on the battleentity in 1.0 seconds
- The actor's `hp` is clamped from 1 to its `maxhp`
- delay is set to true
#### [Eaten](../Actors%20states/BattleCondition/Eaten.md)
It is assumed the actor is a player party member here:
- delay is set to true
- If `eatenby` exists backed by an enemy party member, the player party member's `hp` is above 0 and there is at least one enemy party member:
- [DoDamage](../Damage%20pipeline/DoDamage.md) is called to the player party member with no attacker with a `NoExceptions` property, a `NoCounter` overrides without block. The damageammount is the player party member's `maxhp` / 10.0 + 1 ceiled and then clamped from 1 to 99
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 0 (damage) with the damage amount as the amount with the start being the `eatenby` enemy party member's `cursoroffset` and the end being (0.0, 2.0, 0.0)
- [Heal](../Actors%20states/Heal.md) is called on the `eatenby` enemy party member for the same damage amount dealt to the player party member
- If the player party member's `hp` is 0 or below while there are at least 1 player party member with an `hp` above 0 while not having an `eatenby`:
- `eatenkill` is set to true (used for [AdvanceMainTurn](Action%20coroutines/AdvanceMainTurn.md) to handle this later)
- [EventDialogue](../Battle%20flow/EventDialogue.md) 19 is started and stored in `checkingdead`
#### [Freeze](../Actors%20states/BattleCondition/Freeze.md)
- The `Freeze` sound is played on the battleentity at 1.5 pitch
- battleentity.`shakeice` is set to true
- delay is set to true
#### [Numb](../Actors%20states/BattleCondition/Numb.md)
- delay is set to true
- The `ElecFast` particles are played at the battleentity position + Vector3.up
- A ShakeSprite coroutine is started on the battleentity with the intensity being (0.1, 0.15, 0.0) for 40.0 frames
- The `Shock` sound is played on the battleentity at 1.25 pitch
#### [Sleep](../Actors%20states/BattleCondition/Sleep.md)
Nothing happens if the actor's `hp` is at least its `maxhp`, but if it doesn't:
- A heal amount is determined with a starting value of the actor's `maxhp` * 0.1 ceiled. If the `HeavySleeper` [medal](../../Enums%20and%20IDs/Medal.md) is equipped on the actor (no checks if it's necesarily a player party member), the amount is tripled. On top of this, if it's not a player party member (checked by the battleentity tag not being `Player`), the amount is clamped from 0 to 4
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 1 (HP) with the amount determined earlier with a start of the actor position + its `cursoroffset` and an end of Vector3.up
- The actor's `hp` is incremented by the amount determined earlier clamped from 0 to the actor's `maxhp`
- The `Heal` sound is played
- delay is set to true
#### [GradualHP](../Actors%20states/BattleCondition/GradualHP.md)
The same than `Sleep`, but the amount to heal and show is always 2.
#### [GradualTP](../Actors%20states/BattleCondition/GradualTP.md)
If instance.`tp` is less than instance.`maxtp`:
- The `Heal2` sound is played
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 2 (TP) for 2 as the ammount with a start of battleentity position + the actor's `cursoroffset` and an end of Vector3.up
- instance.`tp` is increased by 2 clamped from 0 to instance.`maxtp`
- delay is set to true
From there, the condition turn counter is decremented with some exceptional cases when this doesn't happen:
- The condition is [Eaten](../Actors%20states/BattleCondition/Eaten.md)
- The condition is [Poison](../Actors%20states/BattleCondition/Poison.md) while the `EternalPoison` [medal](../../Enums%20and%20IDs/Medal.md) is equipped
- The condition is [Flipped](../Actors%20states/BattleCondition/Flipped.md) while the turn count on the first `Flipped` condition (this is assumed to be the same one) is 1 or lower
## Last advance
The first thing that happens is `frozenlastturn` is set to whether or not the actor still has the [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition even after the alive update above.
This section only does something if the condition's turn counter just reached 0 and what happens depends on the condition:
- [Numb](../Actors%20states/BattleCondition/Numb.md): `isnumb` is set to false followed by `cantmove` is set to 1 (resets to one actor turn before an action is available, but it will be exhausted later on this actor turn advance)
- [Sleep](../Actors%20states/BattleCondition/Sleep.md): `isasleep` is set to false followed by `cantmove` is set to 1 (resets to one actor turn before an action is available, but it will be exhausted later on this actor turn advance)
- [Freeze](../Actors%20states/BattleCondition/Freeze.md) / [EventStop](../Actors%20states/BattleCondition/EventStop.md): If the battleentity.`icecube` exists, [BreakIce](../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md) is called on the battleentity. Also, `cantmove` is set to 1 (resets to one actor turn before an action is available, but it will be exhausted later on this actor turn advance)
- [Shield](../Actors%20states/BattleCondition/Shield.md): battleentity.`shieldenabled` is set to false
- [AttackUp](../Actors%20states/BattleCondition/AttackUp.md): If the actor's `atkdownloseatkup` is true, an [AttackDown](../Actors%20states/BattleCondition/AttackDown.md) condition is slated to be added later followed by `atkdownonloseatkup` being set to false
## State advance
- All the [conditions](../Actors%20states/Conditions.md) whose turn count reached 0 are removed
- If an [AttackUp](../Actors%20states/BattleCondition/AttackUp.md) condition's turn count reached 0 while `atkdownonloseatkup` was true earlier:
- [SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called with [AttackDown](../Actors%20states/BattleCondition/AttackDown.md) for 2 actor turns on the actor
- The `StatDown` sound is played
- [StatEffect](../Visual%20rendering/StatEffect.md) is called on the battleentity with type 2 (red arrow down)
- The actor's `isasleep` is set to whether or not the actor has the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition
- The actor's `isnumb` is set to whether or not the actor has the [Numb](../Actors%20states/BattleCondition/Numb.md) condition
- If `firststrike` is false, the actor's `turnsalive` or `turnssincedeath` is incremented (the one chosen depends on the `hp` being above 0)
- If the actor has the [Freeze](../Actors%20states/BattleCondition/Freeze.md) or [EventStop](../Actors%20states/BattleCondition/EventStop.md) condition or their `isnumb` or `isasleep` is true, their `cantmove` is set to 0 (one action available) if they are a player party member (checked by having the `Player` tag), 1 (one turn before an action is available) if it's an enemy party member
- Otherwise, if the actor's `hp` is above 0 and it's not a `firststrike`:
- `cantmove` is decremented which passes a turn in the counter
- If `moreturnnextturn` is above 0, `cantmove` is decreased by it followed by `moreturnnextturn` being set to 0
- Otherwise, if the actor's `hp` is 0, `cantmove` is set to 0
- The actor's `tired` is set to 0
- The actor's `didnothing` is set to false
- The actor's `haspassed` is set to false

View File

@@ -0,0 +1,19 @@
# EndEnemyTurn
This method is only called by [DoAction](Action%20coroutines/DoAction.md) during the [post action phase](Action%20coroutines/DoAction.md#post-action) if the actionid isn't -555 (it's not a player first strike) and it's an enemy party member's action. It will end an enemy party member's actor turn, just like [EndPlayerTurn](EndPlayerTurn.md), but for enemy party members instead of player party members.
```cs
private void EndEnemyTurn(int id)
```
## Parameters
- `id`: The `enemydata` index whose actor turn should be ending
## Procedure
- If we were not in the enemy party member's [hitaction](../Actors%20states/Enemy%20features.md#hitaction), the `DoublePain` [medal](../../Enums%20and%20IDs/Medal.md) isn't equipped and the enemy party member's `notired` is false, its `tired` field is incremented (this adds an exhaustion). NOTE: This neglects HARDEST and B.O.S.S's EX mode making this check incorrect as it leaves exhaustion enabled on HARDEST without `DoublePain`, same for EX mode
- If we were not in the enemy party member's [hitaction](../Actors%20states/Enemy%20features.md#hitaction), the enemy party member's `cantmove` is incremented (this consumes the actor turn)
- The enemy party member's [hitaction](../Actors%20states/Enemy%20features.md#hitaction) is reset to false
- Unless `dontusecharge` is true, the enemy party member's `charge` is reset to 0
- RefreshAllData is called which sets `alldata` to a new list which consists of all the `playerdata` followed by all the `enemydata` appended together
- Unless we were `inevent`, [ReorganizeEnemies(true)](../Actors%20states/Enemy%20party%20members/ReorganizeEnemies.md) is called which removes all dead enemies and orders all `enemydata` by their battleentity's x position

View File

@@ -0,0 +1,10 @@
# EndPlayerTurn
This methods tells the `currentturn` player party member that its action is over and its turn must be consumed.
- `playerdata[currentturn].cantmove` is incremented which consumes one of its available action
- `currentturn` is set to -1 which deselects the player party member and lets [Update](Update.md) decide what to do next as part of the [Main turn life cycle](Main%20turn%20life%20cycle.md#main-turn-life-cycle).
- UpdateConditionIcons is called which calls UpdateConditionBubbles on the battleentity (all `playerdata` with right to false and all `enemydata` with `hp` above 0 with right to true)
- [currentaction](../Player%20UI/Pick.md) is set to `BaseAction` (the main vine action menu)
- RefreshAllData is called which sets `alldata` to a new list which consists of all the `playerdata` followed by all the `enemydata` appended together
- Each `enemydata` that has a [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition or `isasleep` while [actimmobile](../Actors%20states/Enemy%20features.md#actimmobile) is false has their `cantmove` set to 1
- SetLastTurns is called which resets `lastturns` to a new aray with the length being the amount of free players - 1 and all elements being -1 (this resets the player selection cycle)

View File

@@ -0,0 +1,2 @@
# EventDialogue
TODO, this will be documented in part 3

View File

@@ -0,0 +1,55 @@
# GetBlock
This is a parameterless void returning method that is called from [Update](Update.md) when in an [uncontrolled flow](Update%20flows/Uncontrolled%20flow.md).
This logic is exclusive to an uncontrolled flow, but it only happens when `enemy` is true (we are in the player phase / a [delproj](../Actors%20states/Delayed%20projectile.md) is landing / an enemy party member is performing a [hitaction](../Actors%20states/Enemy%20features.md#hitaction)), `inevent` is false (no EventDialogue is in progress) and the [message](../../SetText/Notable%20states.md#message) lock is released (covers cases like [Tattle](Action%20coroutines/Tattle.md)).
GetBlock mainly does 2 things: process the blocking storing the result in `blockcooldown` and `commandsuccess` and update the player party members's [animstate](../../Entities/EntityControl/Animations/animstate.md) to different stages of the blocking.
## How blocking works
A block can be attempted by pressing any of the following inputs (this is the -3 input which aggregates any of this list):
- 4 (Confirm)
- 5 (Cancel)
- 6 (Switch party)
- 7 (Toggle HUD)
However, the block will only be accepted if both `caninputcooldown` and `blockcooldown` expires. If this happens:
- `blockcooldown` is set to 20.0 frames (effectively starts at ~19.0 because GetBlock decreases it later by MainManager.`framestep`). This is the amount of frames left to have a block count by the damage pipeline should a [DoDamage](../Damage%20pipeline/DoDamage.md) call occurs. If it still has 16 or more frames left by the time DoDamage occurs, it counts as a super block for the next 3.0 frames (tracked by `superblockedthisframe`, set during the damage pipeline when processing the super block in [CalculateBaseDamage](../Damage%20pipeline/CalculateBaseDamage.md) and decreased by [LateUpdate](../Visual%20rendering/LateUpdate.md)).
- `caninputcooldown` is set to 37.0 frames. (effectively starts at ~36.0 because GetBlock decreases it later by MainManager.`framestep`) This is the amount of frames that must pass in order for a block to be allowed. The purpose of this is to prevent the player from spamming blocks because it effectively leaves ~17.0 frames of vulnerability after `blockcooldown` expires where the player will not be allowed to block, but if [DoDamage](../Damage%20pipeline/DoDamage.md) gets called during those frames, the block check will fail.
Another important field is updated no matter if a block is processed or not: `commandsuccess`. This field in a blocking context tells if `blockcooldown` is above 0.0 meaning it hasn't expired so it's a quick bool value that tells if the player is currently blocking. The purpose of this is to pass this value to [DoDamage](../Damage%20pipeline/DoDamage.md) as the block parameter so the damage pipeline can act accordingly of whether or not a block was successful. The damage pipeline needs to check `blockcooldown` to know if it was a super block or a regular one.
On each GetBlock (which is normally called on each Update during an enemy action), `caninputcooldown` and `blockcooldown` are decreased by MainManager.`framestep`. This has the side effect that the cooldown starting values are decreased by ~1.0 from the ones actually written to initially. It's not exactly 1.0 because it depends on the last MainManager.`framestep`. For example, if the last frame took longer than the target framerate, it will be decreased by slightly more than 1.0.
## A summarised explanation of blocking
All of the above can be summarised by the following:
- A block of any kind can be performed by pressing 4 (Confirm), 5 (Cancel), 6 (Switch party) or 7 (Toggle HUD) if it's been less than ~36.0 frames since the last time these inputs were pressed (tracked by `caninputcooldown`, decreased each GetBlock which is called on each Update)
- An accepted block only counts for up to ~19.0 frames leading the [DoDamage](../Damage%20pipeline/DoDamage.md) call (tracked by `blockcooldown`, decreased each GetBlock which is called on each Update). DoDamage receives a block parameter where it is intended that `commandsuccess` is passed to it which tells if `blockcooldown` is still active or not
- If `blockcooldown` reaches 0.0, no blocking can be performed for the next ~17.0 frames due to `caninputcooldown`. Blocking never influences the damage pipeline if it's performed after the DoDamage call
- If an accepted block reaches a [DoDamage](../Damage%20pipeline/DoDamage.md) while there's still 16.0 or more frames left on `blockcooldown`, the block counts as a super block. This effectively leaves only the first ~4.0 frames window of the block to count it as a super block
- If a super block occurs and is verified by the damage pipeline, it is valid for up to 3.0 frames after the damage pipeline completes where any further [DoDamage](../Damage%20pipeline/DoDamage.md) calls will count a super block no matter what `blockcooldown` and `commandsuccess` reports. This is done to allow quick damages in succession to still count the super blocks as it wouldn't be possible for the player to block due to the block spam prevention. This is tracked by `superblockedthisframe` which decreases on every [LateUpdate](../../Entities/EntityControl/Update%20process/Unity%20events/LateUpdate.md) by MainManager.`framestep`
## Details on why this blocking system works
It's important to understand why this system works because it involves the asynchronous nature of the battle system.
Let's take a typical attack action as an example. [DoAction](Action%20coroutines/DoAction.md) is an action coroutine. It means that it runs concurently to the main Update loop. Since GetBlock runs on Update and enemy actions must go through DoAction to call [DoDamage](../Damage%20pipeline/DoDamage.md) as part of their action, it means GetBlock and DoAction runs concurently from each other.
This allows GetBlock to not touch any of the damage pipeline, but still report and track whether the player is blocking and for how long they been blocking. Meanwhile, DoAction runs indepedently from this which allows very tight control on the animations and the moment to call DoDamage which can have an intuitive visual and auditive timing to assist the player in performing the block. It is free to use the results GetBlock gathered at any time because it is guaranteed to be correct since Update always run before DoAction gets any attention if it was set to resume on that frame.
This results in the blocking timing to work no matter how the enemy action is performed. There is no need to define any timing anywhere because it's implicitly handled by the asynchronous nature of the system. The one downside however is the entire timing window leads up to the actual damage frame meaning that intuitively, the player could be a frame after and still miss the block while they were within 4 frames of the damage. There is no coyote frames to account for this (adding any would introduce visual delays to present the damage counter and other effects).
## Animation updates
Other than managing blocking, it also manages animations of the player party members. The following happens happens for every player party members whose battleentity.`overrideanim` is false:
- If the `hp` is 0 while their battleentity isn't `dead` yet, battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`)
- Otherwise, if [IsStopped](../Actors%20states/IsStopped.md) returns false on the player party member:
- battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is set to 24 (`Block`) if all of the following are true:
- `hp` is above 0
- `playertargetID` is the player party member or -1 (the whole player party)
- battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) isn't 11 (`Hurt`)
- `blockcooldown` is above 0.0,
- Otherwise, [UpdateAnim](../Visual%20rendering/UpdateAnim.md) is called with onlyplayer to true
- Otherwise, if the player party member `isasleep`, battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is set to 14 (`Sleep`)
- Otherwise, if the player party member `isnumb` or it has the [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition, battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is set to 11 (`Hurt`)

View File

@@ -0,0 +1,77 @@
# LevelUpMessage
This is a static coroutine that is part of [AddExperience](../Battle%20flow/Terminal%20coroutines/AddExperience.md) when a rank up occurs. Some ranks also have special level up bonuses that are signaled via this method which may end up calling [SetText](../../SetText/SetText.md) in [dialogue mode](../../SetText/Dialogue%20mode.md#dialogue-mode)
> NOTE: This coroutine expects [flagvar](../../Flags%20arrays/flagvar.md) 0 to be set to 0 so the caller can yield on it. It will be set to 1 at the very end to inform the caller of its completion.
## Message setup
The [rank data](../../TextAsset%20Data/Rank%20data.md#rank-data) matching the new instance.`partylevel` is found. If no one exists, this section is skipped and it only applies the last steps.
When one is found, 0.5 seconds are yielded.
The logic that happens here depends on the rank up bonus type:
### 0 (Skill grant)
There will be a message only if there is a player party member that exist with the [animid](../../Enums%20and%20IDs/AnimIDs.md) of whom should receive the skill.
To setup the message:
- [flagstring](../../Flags%20arrays/flagstring.md) 0 is set to `menutext[46 + X]` where `X` is the animid (this is the name of the player party member)
- [flagstring](../../Flags%20arrays/flagstring.md) 1 is set to the skill's name from [skills data](../../TextAsset%20Data/Skills%20data.md)
### 1 (Stat bonus grant to a player party member)
There will be a message only if there is a player party member that exist with the [animid](../../Enums%20and%20IDs/AnimIDs.md) of whom should receive the stat bonus. This only supports `Attack`, `Defense` and `HP` bonuses.
Regardless if a message is sent:
- The corresponding stat bonus is applied to the player party member via AddStatBonus
- [flagstring](../../Flags%20arrays/flagstring.md) 0 is set to `menutext[46 + X]` where `X` is the animid (this is the name of the player party member)
- [flagstring](../../Flags%20arrays/flagstring.md) 1 is set to the amount of the bonus increase followed by ` ` followed by a `menutext` that depends on the bonus type which is its name (16 for `Attack`, 17 for `Defense` and 14 for `HP`)
### 2 (Stat bonus grant to the whole player party)
There will always be a message. This only supports `TP` and `MP` bonuses.
If this is a `TP` bonus:
- [flagstring](../../Flags%20arrays/flagstring.md) 0 is set to the amount of the bonus increase followed by ` ` followed by `menutext[15]` (TP)
- instance.`tp` is increased by the amount of the bonus
- instance.`maxtp` is increased by the amount of the bonus
- AddStatBonus is called to apply the `TP` bonus to the party, but it will either be called once if the amount is 3 for a single 3 `TP` bonus to the party, or it will be called multiple times if it's not 3 where each calls is a 1 `TP` bonus to the party adding up to the same amount
If this is an `MP` bonus:
- [flagstring](../../Flags%20arrays/flagstring.md) 0 is set to the amount of the bonus increase followed by ` ` followed by `menutext[19]` (MP)
- instance.`bp` is increased by the amount of the bonus
- instance.`maxbp` is increased by the amount of the bonus
- AddStatBonus is called to apply the `MP` bonus to the party with the amount of the bonus in a single call
### 3 (standard items capacity upgrade)
There will always be a message.
- [flagstring](../../Flags%20arrays/flagstring.md) 0 is set to the amount of the inventory upgrade
- instance.`maxitems` is increased by the amount of the inventory upgrade
- [flagstring](../../Flags%20arrays/flagstring.md) 0 is set to the new instance.`maxitems`
### Message display
This part only happens if we decided to show a message.
[SetText](../../SetText/SetText.md) is called in [dialogue mode](../../SetText/Dialogue%20mode.md#dialogue-mode) with the text being `|`[boxstyle](../../SetText/Individual%20commands/Boxstyle.md)`,4||`[spd](../../SetText/Individual%20commands/Spd.md)`,0||`[halfline](../../SetText/Individual%20commands/Halfline.md)`||`[center](../../SetText/Individual%20commands/Center.md)`|` followed by `menutext[141 + X]` where `X` is the type of the rank up bonus. The call has the following properties:
- [fonttype](../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- linebreak of instance.`messagebreak`
- No tridimensional
- position of Vector3.zero
- No cameraoffset
- size of Vector3.one
- No parent
- No caller
From there, all frames are yielded while the [message](../../SetText/Notable%20states.md#message) lock is grabbed.
After, an additional frame is yielded
## Last steps
This section applies regardless if a rank data was found:
- [ApplyStatBonus](../ApplyStatBonus.md) is called
- A frame is yielded
- [flagvar](../../Flags%20arrays/flagvar.md) 0 is set to 1 which informs the caller that the coroutine completed

View File

@@ -0,0 +1,100 @@
# Main turn life cycle
This page describes the life cycle of a main turn which is processed as the last step of a [controlled update flow](Update%20flows/Controlled%20flow.md). It means the steps presented in this page are parts of [Update](Update.md).
It is composed of 3 phases, starting from the first and each subsequent one needing the previous to finish:
1. Player phase (`enemy` is false or became false from the last main turn's end of turn phase)
2. Enemy phase (`enemy` became true after the end of the player phase)
3. End of turn phase (`enemy` is still true while no free enemy party members are left)
This cycle repeats continuously until the flow changes to a [Terminal flow](Update%20flows/Terminal%20flow.md).
## Player phase
This is where the player party portion of the turn is handled. It is denoted by `enemy` being false and once the player phase is over, `enemy` is set to true which moves the battle into enemies phase.
The following always happen first:
- [UpdateAnim](../Visual%20rendering/UpdateAnim.md) is called
- `blockcooldown` is set to 0.0
The phase only proceeds if no `enemydata` battleentity is in a [forcemove](../../Entities/EntityControl/EntityControl%20Methods.md#forcemove) (returned by EnemiesAreNotMoving).
From there, what happens in the phase depends on `currentturn` and `avaliableplayers`. The former manages the current player party member selected for the current action while the latter tells if player party members are still free.
`currentturn` being positive, but below the length of `playerdata` means that we already are selecting a player party member for the turn. In that case some logic happens:
- If instance.`hud` exists while not being empty, GUIMovement is called. This method will visually render the `fronticon` on the applicable `playerdata` element (`partypointer[0]`) on its lower right corner and also move the currently selected player's HUD element by setting its y local position to 0.0 - the abosolute value of Sin(Time.time / 2.0) / 7.0 (the other HUD elements have it reset to 0.0) This makes the HUD element move up and down.
- [PlayerTurn](PlayerTurn.md) is called
If `currentturn` is -1 however, it means no one is selected yet which indicates the phase needs to proceed to either select one or perform a post player action step. This starts by updating `availableplayers` to [GetFreePlayerAmmount](../Actors%20states/Player%20party%20members/GetFreePlayerAmmount.md).
From there, the next appropriate part of the player phase is performed which is the first of the next 4 parts. They can be thought of a sequence where the first applicable part occurs. A part may be skipped entirely, but eventually, the last one will occur which will end the player phase.
Here are the player phase parts and their conditions:
1. Player party member selection (`availableplayers` is above 0 meaning at least one player party member is free)
2. `chompy` action (no player party members are free, `chompy` exists, can act and haven't acted in this main turn)
3. `aiparty` action (no player party members are free, `aiparty` exists and haven't acted yet in this main turn)
4. End of the player phase (none of the above applied meaning the player phase is done)
### Player party member selection
This part only happens if `availableplayers` is above 0.
This is where the player party member selection happens:
- The player party member index selected for `currentturn` value is found by searching in `partypointer` order and finding the first that isn't [IsStopped](../Actors%20states/IsStopped.md), its `cantmove` is 0 or below (it has at least one action available) and it is cleared by CheckFreePlayers which means it isn't in `lastturns` when more than 1 player is free (it means it's the next player in the select cycle or it's the last free player)
- [UpdateText](../Visual%20rendering/UpdateText.md) is called
- If `playerdata` length is more than 1, AddLastTurn is called on the player index (by `partypointer`) which adds the player index to the next free slot or pushes it to the last one if all slots are taken, removing the oldest one (it just advances the select cycle)
- [PlayerTurn](PlayerTurn.md) is called
This cycle then ends. From now on, all cycles will see the `currentturn` being already set to a player and just process it
### `chompy` action
This part happens if all of the following are fufilled:
- `chompy` exists
- `chompyattacked` is false (this part hasn't happened yet)
- `chompylock` is false
- `enemydata` is not empty
This is what happens when the above are fufilled (otherwise, this part is skipped):
- If [spitout](../Actors%20states/BattleCondition/Eaten.md#spitout) is in progress, `chompyattacked` is set to true which skips the chompy action
- Otherwise, if `chompyattack` isn't in progress, it is set to a new [Chompy](Action%20coroutines/Chompy.md) action coroutine starting
### `aiparty` action
This part happens if all of the following are fufilled:
- `aiparty` exists
- `aiattacked` is false (this part hasn't happened yet)
- `enemydata` is not empty
The only thing that happens here is an [AIAttack](Action%20coroutines/AIAttack.md) action coroutine is started.
### End of the player phase
If none of the possible parts applied above (or all of the applicable ones are done), the following happens which ultimately ends the player phase:
- `enemy` is set to true
- All of the instance.`hud`'s first child has their local position reset to Vector3.zero
- `currentturn` is set to the length of `playerdata`
## Enemy phase
This is where the enemies party portion of the turn is handled. It is denoted by `enemy` being true while there are at least 1 free enemy obtained via GetFreeEnemies.
A free enemy is one whose `cantmove` is 0 or below (it has at least one action available) and whose `hp` is above 0 (not dead yet). If there are no free enemies, this phase is skipped and we move on to the turn end phase.
If we somehow got here while GetAlivePlayerAmmount returns 0 (all `playerdata`'s `hp` is 0 or below or their `eatenby` isn't null which means they got eaten), this phase will end abruptly by doing the following:
- `mainturn` is set to an [AdvanceMainTurn](Action%20coroutines/AdvanceMainTurn.md) call if it wasn't in progress already
- `cancelupdate` is set to true which changes the flow to a [terminal flow](Update%20flows/Terminal%20flow.md)
If at least one player is alive, then the first enemy with a `cantmove` of 0 or below is found. In order for the enemy to get their action, they need to not be considered IsStoppedLite which uses the same standard than [IsStopped](../Actors%20states/IsStopped.md) with [actimmobile](../Actors%20states/Enemy%20features.md#actimmobile) check, but with one difference: if the enemy has the `Flipped` [condition](../Actors%20states/Conditions.md), it isn't considered stopped.
If the game finds it's stopped, their `cantmove` is set to 1 and the next enemy is checked instead. Effectively, this simply readjusts their actor turn counter because it isn't exhausted like it normally would have been in [EndEnemyTurn](EndEnemyTurn.md).
If the enemy isn't stopped, [DoAction](Action%20coroutines/DoAction.md) is called on the battleentity with actionid of the `enemydata` index. This changes to an [uncontrolled flow](Update%20flows/Uncontrolled%20flow.md). At most, this can happen only once and the next enemy in line will need to wait the current one's action is done.
This process is repeated for each enemy party member until all of them have a `cantmove` above 0 meaning no actions are available on any enemy party members and the game is ready to proceed to the turn end phase.
## Turn end phase
After both parties performed their phases, an [AdvanceMainTurn](Action%20coroutines/AdvanceMainTurn.md) action coroutine is started and set to `mainturn` if it wasn't in progress already. This immediately move the flow back to [uncontrolled flow](Update%20flows/Uncontrolled%20flow.md) while the coroutine handles the turn advancement.

View File

@@ -0,0 +1,23 @@
# PlayerTurn
This method processes any [controlled flow](Update%20flows/Controlled%20flow.md) during the [player phase](Main%20turn%20life%20cycle.md#player-phase) when applicable to the currently selected player.
- `actedthisturn` is set to true
- If [currentaction](../Player%20UI/Pick.md) is `BaseAction` (the main vine action menu):
- [SetMaxOptions](../Player%20UI/SetMaxOptions.md) is called
- [ItemList](../../ItemList/ItemList.md)'s `inlist` is set to false
- For each `playerdata`:
- If the actor isn't [IsStopped](../Actors%20states/IsStopped.md#isstopped), its battleentity.`overrideanim` is set to false
- If battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is 24 (`Block`), [UpdateAnim](../Visual%20rendering/UpdateAnim.md) is called and the `playerdata` loop exited. NOTE: it means not all player party member might have their `overrideanim` set to false when not stopped, but in practice, this doesn't impact anything negatively under normal gameplay
- If `choicevine` doesn't exist, it is created via CreateVine:
- `choicevine` is created as a new GameObject named `Vine`
- `vineicons` is created as new array of length `maxoptions`
- `vinebase` is created as a new GameObject named `Base` childed to `choicevine`
- Each `vineicons` elements is initialised as the SpriteRenderer of a new instance of `Prefabs/Objects/Vine` childed to the `vinebase` (each element causes the `choicevine` angles to be decreased by (0.0, 360 / `maxoptions` floored, 0.0)):
- position of `choicevine` position + (0.0, 0.0, -1.6)
- angles of (-180, 275.0, 0.0)
- scale of (2.5, 2.5, 2.5)
- sprite of `guisprites[35 + i]` where i is the option index
- with flipX
- The `choicevine` gets childed to the `battlemap`
- The `choicevine` position is set to `playerdata[currentturn].battleentity` position + (0.0, 10.0, 0.0)
- If `turncooldown` expired, [GetChoiceInput](../Player%20UI/GetChoiceInput.md) is called which handles the player UI

View File

@@ -0,0 +1,40 @@
# Retry
This method serves as a transition from a [GameOver](Terminal%20coroutines/GameOver.md) to a complete retry of the battle using [StartBattle](../StartBattle.md).
```cs
private void Retry(bool skipdata)
```
## Parameters
- `skipdata`: If true, ReloadInitialData won't be called. This is done if the caller already called it which is needed to adjust the starting stats to what they were on the first [StartBattle](../StartBattle.md) recorded from `sdata`
## Prcedure
- All [delprojs](../Actors%20states/Delayed%20projectile.md)'s `obj` are destroyed followed by the `delprojs` array set to null
- The `battlemap` is destroyed
- [SetDefaultCamera](../Visual%20rendering/SetDefaultCamera.md) with reset is called
- `chompyattacked` is set to false
- `aiattcked` is set to false
- `tskybox` is set to RenderSettings.skybox
- RenderSettings.skybox is set to null
- instance.`enemyencounter` is set to `sdata.encounter`
- If skipdata is false, ReloadInitialData is called which does the following (mostly loads from the [StartUpData](../StartUpData.md)):
- [ApplyBadges](../ApplyBadges.md) is called
- [ApplyStatBonus](../ApplyStatBonus.md) is called
- instance.`maxtp` is set to `sdata.maxtp`
- instance.`tp` is set to `sdata.tp` clamped from 0 to instance.`maxtp`
- For each player party member:
- `atk` is set to the matching `sdata.atk`
- `def` is set to the matching `sdata.def`
- `hp` is set to the matching `sdata.hp` clamped from 0 to the player party member's `maxhp`
- `lockitems` is set to the matching `sdata.partyitemuse`
- instance.`items[0]` (standard items) is set to `sdata.items`
- instance.`items[1]` (key items) is set to `sdata.keyitem`
- A [StartBattle](../StartBattle.md) call starts with the following:
- enemyids: `sdata.enemies`
- stageid: `sdata.stage`
- adv: `sdata.adv`
- music: `sdata.music`
- calledfrom: `sdata.called`
- canescape: `canflee` (from this BattleControl)

View File

@@ -0,0 +1,226 @@
# AddExperience
AddExperience is a terminal coroutine that is invoked whenever most battles are won with EXP gain. This coroutine will be the step between the battle finishing and [ExitBattle](../Terminal%20wrappers/ExitBattle.md) which is a wrapper around [ReturnToOverworld](ReturnToOverworld.md).
The coroutine yield breaks immediately if `alreadyending` is true (meaning AddExperience or [GameOver](GameOver.md) was already invoked) or `gameover` is in progress.
> NOTE: The vast majority of the logic in this coroutine concerns very verbose animations and UI rendering. For the sake of brevity, they will be paraphrased and details will be kept at a high level. All other logic will still be mentioned in granular details.
## Setup
- `alreadyending` is set to true which prevents double invocations
- `action` and `cancelupdate` are set to true changing to a [terminal flow](../Update%20flows/Terminal%20flow.md)
- `enemy` is set to false, but this doesn't do anything because we just changed to a terminal flow
- If the `HealingBuzz` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped:
- All player party members with an `hp` above 0 has [Heal](../../Actors%20states/Heal.md) called on them for an ammount of 2 with nosound
- The `Heal` sound is played (the reason the Heal calls didn't had sound is to avoid playing healing sounds multiple times)
- 0.5 seconds are yielded if any player party members were healed as a result of the `HealingBuzz` logic above
- If the `VictoryBuzz` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped:
- HealTP is called which plays a `Heal2` sound followed by a heal of instance.`tp` by 4 followed by a [ShowDamageCounter](../../Visual%20rendering/ShowDamageCounter.md) with type 2, the amount being 4, the start position being `playerdata[`[GetRandomAvaliablePlayer()](../../Actors%20states/Targetting/GetRandomAvaliablePlayer.md)`].battleentity` position + (2.0, 2.0, 2.0) and the end position being (5.0, 5.0, 5.0)
- 0.5 seconds are yielded
- If `expreward` is above 5:
- `checkingdead` is set to a new [UseCharm](../UseCharm.md) coroutine starting with `ExpUp` as the type
- All frames are yielded while `checkingdead` is in progress
- The `switchicon` and `fronticon` are destroyed
- If [flags](../../../Flags%20arrays/flags.md) 613 is true (RUIGEE is active), `expreward` is set to 0
- Otherwise, if `expreward` was already 0 while `enemyfled` is false and instance.`partylevel` is less than 27 (the normal max rank), `expreward` is set to 1
- [RefreshEXP](../../Visual%20rendering/RefreshEXP.md) is called
- AddExperience determines if a `BattleWon` sound should be played. it will be if `musicvolume` is above 0.0 and `music[0]`.name is `Battle0` or `Battle6` (meaning that the music we were just playing was one of the 2 regular battle themes). If that is the case:
- FadeMusic is called with a fadespeed of 0.05
- The `BattleWon` sound is played and the AudioSource is kept track locally
- If the `BattleWon` AudioSource indeed exists, its volume is set to `musicvolume` (this is needed because it's a sound so it wouldn't get the music volume by default)
- [flagvar](../../../Flags%20arrays/flagvar.md) 0 is set to `expreward` (this will be used for rendering later)
- instance.`hudcooldown` is set to -1.0
- All frames are yielded while there are still any enemy party members
- 0.45 seconds are yielded
- All player party members has their matching instance.`hud`'s child has its local position set to Vector3.zero
- For every player party members whose `hp` is above 0:
- If they have the [Freeze](../../Actors%20states/BattleCondition/Freeze.md) condition, [BreakIce](../../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#breakice) is called on their battleentity
- battleentity.`spin` is set to (0.0, -17.0, 0.0)
- battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) is set to 4 (`ItemGet`)
- instance.`camtargetpos` is set to (-4.5, 0.0, 2.5)
## EXP gain visuals setup
The process to render the expereince gain screen is very verbose and complex so the procedure is paraphrased a lot here:
- A `textholder` GameObject gets created with a `DelAftBtl` tag (destroyed on [ReturnToOverworld](ReturnToOverworld.md)) childed to the GUICamera with a z local position of 5.0
- [SetText](../../../SetText/SetText.md) is called in [non dialogue mode](../../../SetText/Dialogue%20mode.md#non-dialogue-mode) using the following string: `|`[sort](../../../SetText/Individual%20commands/Sort.md)`,10000||`[color](../../../SetText/Individual%20commands/Color.md)`,4||`[center](../../../SetText/Individual%20commands/Center.md)`||`[dropshadow](../../../SetText/Individual%20commands/Dropshadow.md)`,0.05,-0.05||`[backbox](../../../SetText/Individual%20commands/Backbox.md)`,6|` followed by `menutext[117]` (a message informing the player they gained EXP where the number is `|`[var](../../../SetText/Individual%20commands/Var.md)`,0|`). The call has the following properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of 2 (UNUSED, but gets overriden to `D3Streetism`)
- No linebreak
- No tridimensional
- position of (0.0, 3.0, 5.0)
- No cameraoffset
- size of Vector3.one
- parent being the `textholder`
- No caller
- A new UI object called `ExpBar` with a `DelAftBtl` tag (destroyed on [ReturnToOverworld](ReturnToOverworld.md)), a DialogueAnim and a pure yellow color using `guisprites[4]` (the HUD background sprite) is created as the background of the EXP text
- `lvicon` is set to a new UI object named `Icon` using `guisprites[27]` (the EXP icon sprite) childed to the `ExpBar`
- A DynamicFont is setup childed to the `ExpBar` with a layer of 5 (`UI`) with a pure white color with the starting text being the following appended together:
- instance.`partyexp` padded to the left with 3 `0`
- `/`
- instance.`neededexp`
- All player party members with an `hp` above 0 has their battleentity.`spin` zeroed out
- `leveled` is set to false
- 0.15 seconds are yielded
## EXP orbs counting and wait
This sub section concerns the counting of the EXP gained and the management of its fast version if requested by the player.
- instance.[skiptext](../../../SetText/Related%20Systems/Text%20advance.md#text-skip) is set to false (this isn't used for its SetText use since it will be managed manually)
- A new GetSkip coroutine is started and stored localled which will yield all frames until input 4 (Confirm) is pressed which wil cause instance.`skiptext` to be set to true
- The EXP orbs are counted starting with `bigexporbs` then moving to `smallexporbs` that exists (there is a frame yield between the 2 types's counting). A big one will have 1 EXP counted 10 times while a small one will only have it counted once. This is how the counting happens each time:
- The orb gets destroyed
- AddExp(1) is called which does the following:
- Incrementes instance.`partyexp` by 1
- An `Exp2` sound is played on `sounds[4]`, `sounds[5]`,`sounds[6]` or `sounds[7]` (the first one that isn't playing with `sounds[7]` being the falback) with a pitch being 1.5 + a random number between -0.1 and 0.1 inclusive
- If instance.`partyexp` reached instance.`neededexp` (meaning this is a rank up), instance.`partyexp` is decreased by `neededexp` and the rank up is signaled by returning true
- Otherwise, no rank up occured so false is returned
- If the AddExp call resulted in a rank up, Leveled is called which sets `leveled` to true, but if it wasn't true before, a SpinAround component added to `lvicon` with its `itself` set to (0.0, 20.0, 0.0) followed by a `Lazer` sound being played at 1.2 pitch
- The DynamicFont of the EXP's text is refreshed using the new instance.`partyexp`
- If instance.`skiptext` is still false, a yield is done. The time of the yield is 0.075 seconds unless `expreward` was at least 10 where it will be 0.045 seconds instead
- At this point, the GetSkip coroutine call earlier is stopped since it no longer has any use
- If instance.`skiptext` was set to true by the end of the counting, the DynamicFont of the EXP's text is refreshed using the new instance.`partyexp` followed by 0.2 seconds being yielded
- A frame is yielded
- instance.`skiptext` is set back to false
- For a maximum of 50.0 frames (tracked with a local counter starting at 0.0 and incremented by 1/50 of the game's frametime until it reaches 1.0), all frames are yielded until any input is pressed which interupts this wait early
- If the `BattleWon` sound was played earlier, all frames are yielded while it's still playing and hasn't reached 2.35 seconds
- A second is yielded if no `BattleWon` sound was played
## Text UI teardown
- A DialogueAnim is added on the `ExpBar` object to move it to the left offscreen
- 0.5 seconds are yielded
- The `textholder` object is destroyed
- A frame is yielded
## Rank up logic
This logic only happens if `leveled` is true and instance.`partylevel` is less than 27 (the normal max rank).
The logic in here is very complex and mostly contains verbose animations so it will be paraphrased a lot.
### Setup
- instance.`partylevel` is incremented
- 0.25 seconds are yielded
- instance.`neededexp` is increased to a certain amount to indicate the new amount required to rank up. The first increase that applies in the following ones is the one that will occur (they are mutually exclusive):
- +5 If [flags](../../../Flags%20arrays/flags.md) 656 is true (MOREFARM is active)
- +3 if instance.`partylevel` is at least 24
- +2 if instance.`partylevel` is at least 15
- +1 if none of the above applied
- ChangeMusic is called with the `LevelUp` music
- `Prefabs/Particles/Floweretti` particles are instantiated childed to the `battlemap` and played
- All `Sprites/GUI/BattleMessage/rankX` are loaded where `X` is the [languageid](../../../SetText/languageid.md) (it falls back to English if no Sprites exists for it)
- All objects with tag `Enemy` are destroyed
- [SetDefaultCamera](../../Visual%20rendering/SetDefaultCamera.md) is called
- MainManager.Heal is called
- instance.`hudcooldown` is set to -1
- instance.`option` is set to 0 and instance.`maxoptions` to 3
### Rank up animation
- All player party members has their battleentity.`animstate` set to 4 (`ItemGet`) and their `spin` to (0.0, 20.0, 0.0)
- All player party members are move to be centered on the screen using MiddlePos via lerping their battleentity.position for a maximum of 34 frames (tracked via a local framecounter advancing by 0.03 of the game's frametime from 0.0 to 1.0)
- All player party members gets their battleentity.`spin` zeroed out and their battleentity has a [SpecialAnimation](../../../Entities/EntityControl/EntityControl%20Methods.md#specialanimation) started with the `levelup` animation
- The letters of the Rank up messages appears in the following fashion:
- A `LetterHolder` object is created and childed to GUICamera
- New UI objects called `letterX` where X is the index of the letter sprite loaded earlier are created all childed to the `LetterHolder` with a FontEffects using just the [rainbow](../../../SetText/Individual%20commands/Rainbow.md) effect
- The letters appear from offscreen at 99.0 in Y and 5.0 in Z using a lerp off their local position. This is done over a maximum of 200.0 frames and it is porportional to the amount of letters to show
- 0.65 seconds are yielded
- All letters have their local scale lerped from Vector3.one to (0.0, 1.25, 1.0) and their angle increased by Vector3.up * 5x the game's frametime continuoudly over the course of maximum 34 frames (tracked via a local framecounter advancing by 0.03 of the game's frametime from 0.0 to 1.0)
- The `LetterHolder` is destroyed
### Rank up bonus UI setup
- 3 `Prefabs/Objects/Vine` are created using layer 15 (`3DUI`) childed to the `battlemap` with each their own UI icon. The vines are positioned centered to the screen using MiddlePos and they have a DialogueAnim with a tsize being Vector3.one * 2.0. Each has a `guisprites[42]` (a hexagon) on the background of a new `Overicon` object with a SpriteRenderer childed to their vine. The sprites used for the icons are:
- 0: HP icon
- 1: TP icon
- 2: MP icon
- An MP count HUD element is created:
- New UI object called `medalhud` childed to the `textholder` with a pure yellow color using the HUD background sprite
- New UI object called `medalicon` chiled to the `medalhud` using the MP icon sprite
- A DynamicFont is setup on the `medalhud` as parent with `dropshadow` and with the text being the following appended together:
- instance.`bp` padded to the left by 2 `0`
- `/`
- instance.`maxbp` padded to the left by 2 `0`
- A DialogueAnim is added on the `medalhud` so it appears from the top of the screen
- 0.8 seconds are yielded
- A 9Box is created with a DialogueAnim to make it grow
- A [SetText](../../../SetText/SetText.md) call happens in [non dialogue mode](../../../SetText/Dialogue%20mode.md#non-dialogue-mode) with the text being `|`[single](../../../SetText/Individual%20commands/Single.md)`|` followed by `menutext[122]` (a prompt message to pick a stat boost) and the following properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- No linebreak
- No tridimensional
- position of (-7.5, 0.15, 0.0)
- No cameraoffset
- size of Vector3.one
- parent being the 9Box
- No caller
- A new UI object is created named `t` childed to the GUICamera using the `cursorsprite[0]` with a SpriteBounce
- 5 frames are yielded (counted by MainManager.`framestep`)
### Rank up bonus UI naviguation and confirmation
- All frames are yielded while Input 4 (Confirm) isn't pressed
- A `Confirm` sound is played
- A frame is yielded
- The cursor gets childed to the `battlemap` then moved offscreen and DestroyText is called with it
- instance.`hudcooldown` is set to -1
- A [SetText](../../../SetText/SetText.md) call happens in [non dialogue mode](../../../SetText/Dialogue%20mode.md#non-dialogue-mode) with the text being `|`[single](../../../SetText/Individual%20commands/Single.md)`|` followed by `menutext[119]` (the HP rank up bonus description) and the following properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- No linebreak
- No tridimensional
- position of (-7.5, 0.15, 0.0)
- No cameraoffset
- size of Vector3.one
- parent being the 9Box
- No caller
- 5 frames are yielded (counted by MainManager.`framestep`)
- From here, an infinite loop is entered with a frame yield each iteration that won't exit until one of the 3 rank up bonuses have been chosen. Each iterations features the selected instance.`option`'s vine's sprites being rotated and scaled via a lerp continuously propotional to the games frametime. It also feature another SetText call just like the above when instance.`option` changes, but the text is `menutext[119 + X]` where `X` is instance.`option`:
- If `caninputcooldown` isn't expired, it is decreased by the MainManager.`framestep` and no input can be taken until it expires
- Otherwise, the logic depends on the input:
- 2 / 3 (Left / Right): changes instance.`option` accordingly with wrap around to 2 followed by a scroll sound followed by `caninputcooldown` being set to 3.0
- 4 (confirm): The UI loop is exited (the option chosen is indicated by instance.`option`)
- The `LevelUp` sound is played
- For a maximum of 40 frames (tracked with a local counter starting at 0.0 and incremented by 1/40 of the game's frametime until it reaches 1.0):
- All other vines than the instance.`option` one have their local Y position lerped to 20.0 and their Z to 0.0 which moves them offscreen
- The instance.`option` vine gets their angles reset
- The `CrowdClap` sound is played on `sounds[9]` with 0.5 volume
### Rank Up bonus application
The logic to apply the bonus depends on instance.`option`:
- 0 (HP): All player party members gets their `basehp` and `maxhp` gets incremented and a 1 `HP` bonus to the party is added to instance.`statbonus` via AddStatBonus
- 1 (TP): A 1 `TP` bonus to the party is added to instance.`statbonus` via AddStatBonus
- 2 (MP): instance.`maxbp` and instance.`bp` gets increased by 3 and a 3 `MP` bonus to the party is added to instance.`statbonus` via AddStatBonus. It also causes the `medalhud`'s DynamicFont text to be refreshed with the new instance.`bp` and instance.`maxbp`
After, the following happens:
- [ApplyStatBonus](../../ApplyStatBonus.md) is called
- Each player party member has a unique animation played there that sets their battleentity.[animstate](../../../Entities/EntityControl/Animations/animstate.md) to a value that depends on the `trueid`:
- `Bee`: 111, also comes with a SlowSpinStop of (0.0, -20.0, 0.0) for 30.0 frametime on the battleentity
- `Beetle`: 114, also comes with a battleentity.`flip` toggle
- `Moth`: 115
- A frame is yielded
- [ApplyBadges](../../ApplyBadges.md) is called
### LevelUpMessage and teardown
- instance.`hudcooldown` is set to -1
- `medalhud`'s DialogueAnim's `targetpos` is set to (3.7, 10.0, 5.0) which moves it along with the rest of the HUD
- `medalhud` is destroyed in 0.5 seconds
- 0.5 seconds is yielded
- The 9Box is destroyed
- [flagvar](../../../Flags%20arrays/flagvar.md) 0 is set to 0 (this will be used to track whenever a coroutine gets done)
- A [LevelUpMessage](../LevelUpMessage.md) coroutine is started (this will set flagvar 0 to 1 when it's complete)
- All frames are yielded while flagvar 0 is 0 (meaning the LevelUpMessage isn't done yet)
- [ApplyBadges](../../ApplyBadges.md) is called
- A frame is yielded
- MainManager.Heal is called with noparticle and with nosound
- instance.`hudcooldown` is set to -1
## Special heal
If the rank up logic didn't happen, but instance.`partylevel` is at least 99 (which normally can never happen), Heal is called.
## Last steps
- A frame is yielded
- `sounds[9]` is stopped with a 0.002 delay
- [ExitBattle](../Terminal%20wrappers/ExitBattle.md) is called

View File

@@ -0,0 +1,12 @@
# DeadParty
This is a wrapper terminal coroutine that will call [GameOver](GameOver.md) or [ReturnToOverworld](ReturnToOverworld.md) depending on MainManager.`battlelossevent`. It is called when the game finds out the party is fully dead.
- `cancelupdate` is set to true changing to a [terminal flow](../Update%20flows/Terminal%20flow.md)
- `currentturn` is set to `partypointer[0]` (the front member)
- A second is yielded
- If MainManager.`battlelossevent` is false, `gameover` is set to a new [GameOver](GameOver.md) call without skipsetup if it wasn't running already
- Otherwise, this means the game requested the battle to not game over if lost:
- MainManager.`battleresult` is set to false (the battle was still lost)
- A [ReturnToOverworld](ReturnToOverworld.md) coroutine starts
- `forceattack` is reset to -1 (there are no valid player party members target anyway)
- `mainturn` is set to null

View File

@@ -0,0 +1,148 @@
# GameOver
This is a terminal coroutine that will present the player with the game over screen and a prompt to reload, return to main menu or if allowed, retry or retry with the ability to manipulate the standard items and medals using a mini PauseMenu.
```cs
private IEnumerator GameOver(bool skipsetup)
```
## Parameters
- `skipsetup`: If true, it will skip some setup logic at the start and only show the prompt immediately. This is meant only to be used recursively in an edge case where reloading the save file failed which lets the player remedy the problem before letting GameOver try again, but with less setups. This should NEVER be called with the value true for the first time because it will prevent to change to a [terminal flow](../Update%20flows/Terminal%20flow.md)
## Procedure
- `alreadyending` is set to true. This prevents [AddExperience](AddExperience.md) or [EventDialogue](../EventDialogue.md) 19 (The `Pitcher` [enemy](../../../Enums%20and%20IDs/Enemies.md) spit out event) from switching to a [terminal flow](../Update%20flows/Terminal%20flow.md)
- [ItemList](../../../ItemList/ItemList.md)'s `listredirect` is set to -1 (this workarounds a potential [inlist issue](../../../ItemList/inlist%20issue.md) that can happen as a result of the [SetText](../../../SetText/SetText.md) call later)
- The [SetText](../../../SetText/SetText.md) string is prepared and it starts with `|`[boxstyle](../../../SetText/Individual%20commands/Boxstyle.md)`,-1|` which renders without a dialogue box. This string will get appended when needed later
### Setup
This entire section is skipped if skipsetup is true.
- All `smallexporbs` and `bigexporbs` are destroyed
- `action` and `cancelupdate` are set to true changing to a [terminal flow](../Update%20flows/Terminal%20flow.md)
- [RefreshEnemyHP](../../Visual%20rendering/RefreshEnemyHP.md) is called
- SetFlags is called which sets all [flags](../../../Flags%20arrays/flags.md) and [flagvar](../../../Flags%20arrays/flagvar.md) to the ones from the [StartupData](../../StartUpData.md) of the `sdata`
- instance.`hudcooldown` is set to -1 which hides the HP HUD elements
- FadeMusic is called with a speed of 0.035
- A RoundTransition is played via PlayTransition to pure black with a speed of 0.05 and a data of -10 (which is the sortingOrder)
- A frame is yielded
- instance.`transitionobj[0]` z local position is set to 15.0 and its SpriteRenderer's sortingOrder is set to -100
- 2.0 seconds are yielded
- The `cursor` is destroyed if it existed
- If the `GameOver` sound isn't playing, it is played (as `Gameover`, but it works still) and the audiosource's volume is set to MainManager.`musicvolume` which is needed because it is considered a sound instead of a music
- The [SetText](../../../SetText/SetText.md) string gets the following ammended to it: `|`[boxstyle](../../../SetText/Individual%20commands/Boxstyle.md)`,-1||`[center](../../../SetText/Individual%20commands/Center.md)`||`[line](../../../SetText/Individual%20commands/Line.md)`||`[line](../../../SetText/Individual%20commands/Line.md)`||`[line](../../../SetText/Individual%20commands/Line.md)`||`[line](../../../SetText/Individual%20commands/Line.md)`||`[line](../../../SetText/Individual%20commands/Line.md)`||`[halfline](../../../SetText/Individual%20commands/Halfline.md)`||`[spd](../../../SetText/Individual%20commands/Spd.md)`,0||`[color](../../../SetText/Individual%20commands/Color.md)`,4||`[sort](../../../SetText/Individual%20commands/Sort.md)`,10||`[fadeletter](../../../SetText/Individual%20commands/Fadeletter.md)`|` followed by `menutext[146]` (the game over text shown at the top) followed by `|`[fwait](../../../SetText/Individual%20commands/Fwait.md)`,4.5|`. This is basically the game over text positioned a bit down using empty lines and fading in for 4.5 seconds
### [SetText](../../../SetText/SetText.md) call
The following and any further section happens regardless of skipsetup.
- `actiontext` and `hexpcounter` are destroyed if they exist
- The SetText string gets its final append and it depends on the value of `canflee` (meaning the battle was escapable). To note, `menutext[78]` only contains `|`[end](../../../SetText/Individual%20commands/End.md)`|` because these prompt options are blanks: they don't cause SetText to continue since they will be handled after the call:
- If it's true, `|`[prompt](../../../SetText/Individual%20commands/Prompt.md)`,menu,3,2,78,78,135,36,none|` is appended
- If it's false, `|`[prompt](../../../SetText/Individual%20commands/Prompt.md)`,menu,4.5,4,78,78,78,78,134,136,135,36,none|` is appended
- The SetText call happens in [dialogue mode](../../../SetText/Dialogue%20mode.md#dialogue-mode) using the final string generated and the following properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of `BubblegumSans`
- linebreak of `messagebreak`
- No tidimensional
- position of MainManager.`bubblepos` (normally (0.0, 4.15.0, 10.0))
- No cameraoffset
- size of Vector2.one
- No parent
- No caller
#### Broken failsafe logic
This is where a very broken failsafe logic occurs. See the note block below for details on why this logic should never happen.
From there, GameOver will yield all frames for a maximum of 330.0 frames until instance.`promptbox` exists which is when the prompt appears. This is tracked with a local frame countdown decremented by MainManager.`framestep` followed by a frame yield on each iteration. If the countdown reaches 0.0 before `promptbox` exists:
- `gameover` is set to a new GameOver call with skipsetup
- A yield break happens which abruply stops this coroutine
> NOTE: This failsafe was supposed to be a workaround to a previous [inlist issue](../../../ItemList/inlist%20issue.md), but this did not worked because crucically, it breaks the [dialogue mode](../../../SetText/Dialogue%20mode.md#dialogue-mode) rule since the [message](../../../SetText/Notable%20states.md#message) lock will still be grabbed if this failsafe triggers. This means the second GameOver call will allow SetText to process a dialogue mode call WHILE ONE IS ONGOING! This is extremely dangerous because it will lead to 2 SetText calls fighting for each other or even allow player control during a dialogue mode call because one of the prompt option reloads a save. This logic should NEVER trigger under any circumstances otherwise, it will break SetText and general game flow! The original inlist issue has been sucessfully workarounded by setting MainManager.`listredirect` to -1 earlier so it provides no benefit.
#### Proper [message](../../../SetText/Notable%20states.md#message) lock wait
After avoiding the broken failsafe (which happens due to instance.`promptbox` existing after 4.5 seconds instead of 5.5 seconds) instance.`promptbox` local z position is set to 10.0.
This is followed by all frames being yielded until the [message](../../../SetText/Notable%20states.md#message) lock gets released. This is a proper and safe wait for the dialogue mode call to finish unlike the broken failsafe above.
### Prompt option handling
The `GameOver` (as `Gameover` but it works anyway) sound is stopped with a speed of 0.002.
From there, the specific prompt options are handled by checking `canflee` and instance.`option`.
If you can flee, there's 2 prompt options:
- 0: Reload save
- 1: Return to main menu (this will reset the whole game and go back to the main menu)
If you can't flee, there's 4 prompt options (2 are common with the can flee case):
- 0: Retry
- 1: Change loadout and retry (opens a pause menu allowing to manipulate standard items and medals before retrying)
- 2: Reload save
- 3: Return to main menu (this will reset the whole game and go back to the main menu)
The following details what each option's handling does. No matter which one is handled, a frame is yielded at the very end after the option handler is done.
#### Retry
This only calls [Retry](../Retry.md) without skipdata.
#### Change loadout and retry
- ReloadInitialData is called which does the following (mostly loads from the [StartUpData](../../StartUpData.md)):
- [ApplyBadges](../../ApplyBadges.md) is called
- [ApplyStatBonus](../../ApplyStatBonus.md) is called
- instance.`maxtp` is set to `sdata.maxtp`
- instance.`tp` is set to `sdata.tp` clamped from 0 to instance.`maxtp`
- For each player party member:
- `atk` is set to the matching `sdata.atk`
- `def` is set to the matching `sdata.def`
- `hp` is set to the matching `sdata.hp` clamped from 0 to the player party member's `maxhp`
- `lockitems` is set to the matching `sdata.partyitemuse`
- instance.`items[0]` (standard items) is set to `sdata.items`
- instance.`items[1]` (key items) is set to `sdata.keyitem`
- instance.`inbattle` is set to false (this is only temporary, but needed to have the correct UI naviguation logic to use the PauseMenu)
- MainManager.`pausemenu` is set to a new GameObject named `PauseMenu` with a PauseMenu component added to it
- A frame is yielded
- [ApplyBadges](../../ApplyBadges.md) is called
- All frames are yielded while `pausemenu` exists
- [Retry](../Retry.md) with skipdata is called
#### Reload save
There is a special failsafe that occurs if the existing [save file](../../../External%20data%20format/Save%20File.md) no longer exists for some reasons. Here is what happens in that case:
- A frame is yielded
- A new [SetText](../../../SetText/SetText.md) call happens in [dialogue mode](../../../SetText/Dialogue%20mode.md#dialogue-mode) with the text being `|`[boxstyle](../../../SetText/Individual%20commands/Boxstyle.md)`,4||`[center](../../../SetText/Individual%20commands/Center.md)`||`[halfline](../../../SetText/Individual%20commands/Halfline.md)`||`[spd](../../../SetText/Individual%20commands/Spd.md)`,0|` followed by `menutext[145]` which is an error message informing the player of the problem. The call also has these properties:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of `BubblegumSans`
- linebreak of `messagebreak`
- No tidimensional
- position of Vector3.zero
- No cameraoffset
- size of Vector2.one
- No parent
- No caller
- All frames are yielded while the [message](../../../SetText/Notable%20states.md#message) lock is grabbed. This allows the player to possibly remedy the problem by moving the save file at the correct location or to load the backup one. Since no [end](../../../SetText/Individual%20commands/End.md) commands was processed here, there will be a `waitinput` at the end allowing this failsafe to be remediable
- `gameover` is set to a new GameOver call with skipsetup. This is safe unlike the failsafe because in this case, there are no SetText call running anymore so this will simply present the same prompt and the player is able to try the reload option again. Since this GameOver call finishes shortly after, it essentially transferts complete control to the new one and it allows this cycle to repeat over and over
If the save does exist, the following is done instead:
- 0.5 seconds are yielded
- MainManager.ReloadSave is called which does the following:
- The `CrowdChatter` sound is stopped
- FadeMusic is called with a speed of 0.1
- All coroutines belonging to MainManager.`battle` are stopped and `battlemap` is destroyed
- All coroutines belonging to MainManager.`events` (the EventControl) are stopped
- All player party member's `entity` are destroyed
- RenderSettings.skybox is set to null
- MainManager.`map` is destroyed
- [Event](../../../Enums%20and%20IDs/Events.md) 22 is started via `events` without a caller (this is the save loading event)
- instance.`inbattle` is set to false
- We enter a `minipause`
- `pause` is set to false
- This BattleControl is destroyed
#### Return to main menu
- The `CrowdChatter` sound is stopped
- 0.5 seconds are yielded
- SceneManager.LoadScene(0) is called which resets the entire game

View File

@@ -0,0 +1,138 @@
# ReturnToOverworld
This terminal coroutine is the last one invoked to transition out of battle. It is always invoked in a finished battle except for a save reload serving as the last step before the battle is completely ended.
```cs
public IEnumerator ReturnToOverworld(bool flee)
```
## Parameters
- `flee`: Whether or not the battle ended as a result of fleeing
## Procedure
The following sections are performed in order.
### Fade out
- We enter a `minipause`
- MainManager.`battlenoexp` is set to whether or not `expreward` is exactly 0
- The `switchicon`, `cancelb` and `hexpcounter` are destroyed
- A fade out to pure black is done via PlayTransition with a speed of 0.075
- A frame is yielded
- All frames are yielded while `transitionobj[0]`'s SpriteRenderer's alpha hasn't reached 95% opacity or MainManager.`musiccoroutine` is still in progress
- 0.25 seconds are yielded
- `transitionobj[0]`'s SpriteRenderer's alpha is set to fully opaque
- A frame is yielded
### Battle teardown
- The `battlemap` is destroyed
- instance.`globalcooldown` is set to 30.0 frames
- A frame is yielded
- MainManager.`map` is enabled
- A frame is yielded
- For each player party members:
- If the player isn't a `submarine`, their `entity` is enabled
- All matching `hud` elements have their first child local position set to Vector3.zero
- If the player is a `submarine`, the player is enabled
- If we weren't in a instance.`inevent`:
- MainManager.ResetCamera is called with instant
- instance.`camoffset` and instance.`camangleoffset` are reset to their previous counterpart being `oldcamoffset` and `oldcamrotation` respectively
- RestoreLimit is called on the `map` with restoretemp
- A frame is yielded
- The `fronticon` and `expholder` are destroyed
- 0.1 seconds are yielded
- instance.`camspeed` is reset to its previous counterpart being `oldcamspeed`
- A frame is yielded
### Overworld setup
- MainManager.`battlefled` is set to the sent flee value
- MainManager.player.entity.`onground` is set to false
The rest has multiple possibilities on how to setup the overworld, but they are mutually exclusive, only the first one mentioned applies. It is possible none applies.
#### Flee is true
This means the battle ended due to the player fleeing:
- MainManager.player.entity.`icooldown` is set to 120.0 frames of invicibility
- If the `caller` exists, some adjustements needs to happen on it (it implies the `caller` is an [Enemy](../../../Entities/NPCControl/Enemy.md#enemy) NPCControl):
- STOP is called on the `caller` which does the following if the `caller.entity` isn't `dead`:
- Stop `behaviorroutine` if it was in progress and set it to null
- Set `forcebehavior` to null and call [StopForceBehavior](../../../Entities/NPCControl/Notable%20methods/StopForceBehavior.md)
- Call [StopForceMove](../../../Entities/EntityControl/EntityControl%20Methods.md#stopforcemove) on the entity
- Set the entity.`overrideflip` and entity.`overrideonlyflip` to false
- Set `attacking` to false
- `caller.entity.overrideanim` is set to false
- `caller.entity.overrideflip` is set to false
- `caller.entity.onground` is set to false
- If the `caller`'s [regionalflag](../../../Flags%20arrays/Regionalflags.md) isn't negative, the slot value is set to false
- If the `caller`'s [activationflag](../../../Flags%20arrays/flags.md) isn't negative, the slot value is set to false
- All collisions between the `caller.entity.ccol` and the player.entity.`ccol` are ignored
#### Flee is false and the `caller` exists
This means the battle ended without fleeing and it was caused by an [Enemy](../../../Entities/NPCControl/Enemy.md) NPCControl encounter:
- MainManager.player.entity.`icooldown` is set to 120.0 frames of invicibility
- `caller.entity.onground` is set to false
- `callet.entity.rigid` velocity is zeroed out
- The `caller` transform position is set to its `lastpos` (this was set by NPCControl.[StartBattle](../../../Entities/NPCControl/Notable%20methods/StartBattle.md) so the positions is restored to the one before the battle started)
- `caller.attacking` is set to false
- If `expreward` is 0, `enemyfled` is true and instance.`lastdefeated` doesn't contain a `GoldenSeedling` [enemy](../../../Enums%20and%20IDs/Enemies.md):
- MainManager.`battleenemyfled` is set to true
- `caller` is disabled
- Otherwise, if the `caller.entity.deathcoroutine` isn't in progress:
- `caller.entity.deathcoroutine` is set to a new [Death](../../../Entities/EntityControl/Notable%20methods/Death.md) call with activatekill on the `caller`.entity
- If the `Death0` wasn't playing or it was past the halfway point, it is played at 0.6 volume
- `caller.entity.spitmoney` is set to `moneyreward`, but it can get multipliers depending on some conditions (these multipliers aren't mutually exclusive, they can stack):
- `DoublePainReal` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped: 2x
- [flags](../../../Flags%20arrays/flags.md) 613 is true (RUIGEE is active): 2x
- `BerryFinder` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped: 1.25x
- `EXPBoost` [medal](../../../Enums%20and%20IDs/Medal.md) is equipped while [flags](../../../Flags%20arrays/flags.md) 613 is true (RUIGEE is active): 1.25x
#### Flee is false, `enemyfled` is true and `expreward` is 0
The only thing that happens here is MainManager.`battleenemyfled` is set to true
### Other teardown
- A frame is yielded
- instance.`inbattle` is set to false
- [ItemList](../../../ItemList/ItemList.md)'s `listredirect` is set to -1 (this workarounds potential [inlist issues](../../../ItemList/inlist%20issue.md))
- player.entity.`hitwall` is set to false
- CancelAction is called on the player
- [RefreshEntities](../../Actors%20states/RefreshEntities.md) is called with forceanim and refreshmap
- instance.`showmoney` and instance.`hudcooldown` are set to 0.0 (this hides all HUD elements)
- All GameObjects with tag `DelAftBtl` or `Projectile` are destroyed
- The `dimmer` is destroyed
- A frame is yielded
### Fade in
The logic here depends on instance.`inevent`.
#### We weren't in an [event](../../../Enums%20and%20IDs/Events.md)
- If `music[0]` exists:
- If `overworldmusic` exists and its name isn't the `music[0]`'s name, `music[0]`.volume is set to 0.0
- If `music[0]`.name is `LevelUp` and `map.nobattlemusic` is true, ChangeMusic is called which will change the music to either silence or to `map.music[map.musicid]` if it exists
- A frame is yielded
- If MainManager.`keepmusicafterbattle` is true, MainManager.`musicresume` is set to `overmusic`
- ChangeMusic is called with the `overworldmusic`. NOTE: It can mean ChangeMusic is called twice, but the second one will stop the first via a StopCoroutine
- MainCamera's parent angles are set to instance.`camangleoffset`
- A frame is yielded
- A fade in from pure black is performed via PlayTransition with a speed of 0.05 which undoes the fade earlier
- We exit the `minipause`
#### We were in an [event](../../../Enums%20and%20IDs/Events.md)
- If `keepmusic` is false, ChangeMusic is called to silence with a fadespeed of 0.075
- ResetEntitySpeed is called which sets all `map.entitities` and all player party members's entity `anim`.speed to 1.0
This implies that events are responsible for doing the fade in themselves as well as the other logic mentioned above in the non event case.
### Final cleanup
- `actiontext` is destroyed
- ForceHitWall is invoked on the player.entity in 0.2 seconds which will set its `hitwall` to false
- Every player party members with an `hp` of 0 has their `hp` set to 1
- CheckAchievement is invoked on the instance in 0.5 seconds
- This BattleControl is destroyed, the battle is now completely over and it cease to exist

View File

@@ -0,0 +1,18 @@
# EndBattleWon
This method is a wrapper around [AddExperience](../Terminal%20coroutines/AddExperience.md) that is mainly used for [EventDialogues](../EventDialogue.md) to end the battle in a win.
```cs
private void EndBattleWon(bool addexp, int[] skipids)
```
## Parameters
- `addexp`: Whether the `exp` of every remanining enemy party members should be added to `expreward`
- `skipids`: If `addexp` is true, the list of enemy party members index to not have their `exp` added to `expreward`. This is ignored if `addexp` is false
## Procedure
- If addexp is true, all enemy party members's `exp` except the ones whose index is in `skipids` are added to `expreward` followed by a [RefreshEXP](../../Visual%20rendering/RefreshEXP.md) call
- `enemydata` is reset to a new empty array
- `cancelupdate` is set to true changing to a [terminal flow](../Update%20flows/Terminal%20flow.md) (but it will already be changed to it anyway right after)
- An [AddExperience](../Terminal%20coroutines/AddExperience.md) call starts which also makes sure to be in a [terminal flow](../Update%20flows/Terminal%20flow.md)

View File

@@ -0,0 +1,7 @@
# ExitBattle
This method is a wrapper around the [ReturnToOverWorld](../Terminal%20coroutines/ReturnToOverworld.md) terminal coroutine. It is primarily used as part of [EventDialogues](../EventDialogue.md) and is also the last step of [AddExperience](../Terminal%20coroutines/AddExperience.md).
- [ReturnToOverWorld](../Terminal%20coroutines/ReturnToOverworld.md) is called
- `cancelupdate` is set to true changing to a [Terminal flow](../Update%20flows/Terminal%20flow.md)
- `enemy` is set to false which normally makes the flow go to the [player phase](../Main%20turn%20life%20cycle.md#player-phase), but we just changed to a terminal flow so nothing will happen
- `action` is set to true, but not only ReturnToOverworld already did that, this doesn't do anything because we are in a terminal flow

View File

@@ -0,0 +1,106 @@
# Controlled flow
This is one of the flow of [Update](../Update.md) which is the default flow that hapens when the other aren't happening where Update has complete control over the battle and acts as a dispatcher.
It features complete control of the system by the Update event and features the full logic of the battle system. Eventually, this flow will delegate control to an action coroutine which will change to an [uncontrolled flow](Uncontrolled%20flow.md) while the coroutine handles whatever needs to be done.
As part of this flow, everything from the uncontrolled flow except [GetBlock](../GetBlock.md) is included with more logic.
## Pre turn update
The following sections covers everything that happens before an actual main turn is processed. This means everything here gets processed regardless of where in the turn we are in.
### RefreshEXP
If the `oldexp` value doesn't match the current `expreward`, [RefreshEXP](../../Visual%20rendering/RefreshEXP.md) is called. This method manages the visual rendering of the currently cumulated EXP and the different orbs that composes it. `expreward` is the actual EXP cumulated so far while `oldexp` is the last value observed since the last RefreshEXP. It will also create `expholder` if it wasn't created already.
### HP UI refresh
[RefreshEnemyHP](../../Visual%20rendering/RefreshEnemyHP.md) is called every 3 frames.
### UpdateSwitchIcon
UpdateSwitchIcon is called. It only applies if the `switchicon` exists.
The `switchicon` is enabled when all of the following conditions are true (on top of being in this battle flow, it is disabled otherwise):
- There are more than 1 `availableplayers`
- `enemy` is false (we are during the player phase of the turn)
- `inevent` is false (we aren't in an EventDialogue)
- The [message](../../../SetText/Notable%20states.md) lock is released (covers cases like tattling)
- `currentaction` is `BaseAction` (the main vine action menu)
If it gets disabled, it is placed offscreen by setting the local position to (0.0, 99.0, 0.0).
If it gets enabled instead, the local y and z position are set to 4.25 and 5.0 respectively, For the x, it's -7.0 + 3.625 * the length of `playerdata`, but if `longcancel` is true, 0.3 is added to this.
### CheckEvent
This method will check for any special conditions happening and if one occurs, it will result in some logic, frequently involving an EventDialogue starting.
Nothing happens here if `enemydata` is empty.
Here is a list of the conditions and what happens with them (only the first one takes effect):
- `calleventnext` is not negative: [EventDialogue](../EventDialogue.md) is called with the value of `calleventnext` followed by the value being set to -1. This is only used for the [eventonfall](../../Actors%20states/Enemy%20features.md#eventonfall) feature of enemies
- [flags](../../../Flags%20arrays/flags.md) 15 is false (combat tutorial hasn't been given yet): multiplie events can occur with an additional condition:
- [flagvar](../../../Flags%20arrays/flagvar.md) 11 is 0: [EventDialogue](../EventDialogue.md) 0 is started
- [flagvar](../../../Flags%20arrays/flagvar.md) 11 is 2: [EventDialogue](../EventDialogue.md) 2 is started
- [flagvar](../../../Flags%20arrays/flagvar.md) 11 is 3 and `turns` is 3: ExitBattle is called which start a [ReturnToOverworld](../Terminal%20coroutines/ReturnToOverworld.md) without flee, set `cancelupdate` and `action` to true and `enemy` to false which also changes the flow to a [terminal](Terminal%20flow.md) one
- The first `enemydata` has an `animid` (an [enemy](../../../Enums%20and%20IDs/Enemies.md) id) of `Spuder` and [flag](../../../Flags%20arrays/flags.md) 27 is false (haven't gotten past the cutscene of meeting Leif yet), some logic occurs:
- The `Spuder` enemy gets their `hp` set to 999 and `def` to 99
- If the `Spuder` enemy didn't had a weakness of `AntiPierce`, it is added to [weakness](../../Actors%20states/Enemy%20features.md#weakness)
- If `turns` is 2 and [flagvar](../../../Flags%20arrays/flagvar.md) 11 is 2, [EventDialogue](../EventDialogue.md) 4 is started
- Otherwise, if `turns` is 3 and [flagvar](../../../Flags%20arrays/flagvar.md) 11 is 1, [ExitBattle](../Terminal%20wrappers/ExitBattle.md) is called which will change to a [terminal flow](Terminal%20flow.md)
- Otherwise, if `turns` % 2 is 0 while being above 0 and [flagvar](../../../Flags%20arrays/flagvar.md) 11 is 2, [EventDialogue](../EventDialogue.md) 5 is started
- [flag](../../../Flags%20arrays/flags.md) 16 is true (Leif can fight in battle) and [flag](../../../Flags%20arrays/flags.md) 27 is false (haven't received the Relay tutorial yet), [EventDialogue](../EventDialogue.md) 3 is started
- [EventDialogue](../EventDialogue.md) 7 is started followed by [flagvar](../../../Flags%20arrays/flagvar.md) 11 being set to 200 when all of the following are true:
- [flag](../../../Flags%20arrays/flags.md) 37 is false (using the B.O.S.S system in EX mode)
- [flagvar](../../../Flags%20arrays/flagvar.md) 11 is below 200, [flag](../../../Flags%20arrays/flags.md) 27 is true (got past the cutscene of meeting Leif for the first time)
- The first `enemydata` has an `animid` (an [enemy](../../../Enums%20and%20IDs/Enemies.md) id) of `Spuder` with an `hp` below half of its `maxhp` floored, but above 0
- [GetFreePlayerAmmount](../../Actors%20states/Player%20party%20members/GetFreePlayerAmmount.md) returns 0
- [EventDialogue](../EventDialogue.md) 8 is started followed by [flagvar](../../../Flags%20arrays/flagvar.md) 11 being set to 150 when all of the following are true:
- [flag](../../../Flags%20arrays/flags.md) 37 is false (using the B.O.S.S system in EX mode)
- [flagvar](../../../Flags%20arrays/flagvar.md) 11 is below 150, [flag](../../../Flags%20arrays/flags.md) 27 is true (got past the cutscene of meeting Leif for the first time)
- The first `enemydata` has an `animid` (an [enemy](../../../Enums%20and%20IDs/Enemies.md) id) of `Spuder`
- `turns` is 0
### EXP counter updates
The first time this section run, `hexpcounter` wouldn't exist yet so it will get created by doing the following:
- `hexpcounter` is set to a new UI object named `expcounter` with tag `DelAftBtl` (destroyed on [ReturnToOverworld](../Terminal%20coroutines/ReturnToOverworld.md)) childed to the `GUICamera` with position (7.4, -6.5, 10.0) with size (0.5, 0.6, 1.0) using `guisprites[4]` (a HUD backgrond strip) and sortingOrder of 10
- The color of the SpriteRenderer of `hexpcounter` is set to instance.`charcolor[0]` (hardcoded to be pure yellow)
- A new UI object is created called `icon` childed to `hexpcounter` with position (-2.5, 0.0, 0.0) with size (1.25, 1.0, 1.0) using `guisprites[27]` (the EXP icon) and sortingOrder being 1 over the `hexpcounter`'s (11)
- [SetText](../../../SetText/SetText.md) is called in [non dialogue mode](../../../SetText/Dialogue%20mode.md#non-dialogue-mode):
- text: `|`[font](../../../SetText/Individual%20commands/Font.md)`,2||`[sort](../../../SetText/Individual%20commands/Sort.md)`,20||`[color](../../../SetText/Individual%20commands/Color.md)`,4|` + instance.`partyexp` padded with 2 `0` + `/|`[size](../../../SetText/Individual%20commands/size.md)`,0.8|` + instance.`neededexp`
- [fonttype](../../../SetText/Notable%20states.md#fonttype): 0 (`BubblegumSans`)
- No linebreak
- No tridimensional
- position: (-1.2, -0.3, 0.0)
- No cameraoffset
- size: Vector3.one
- parent: `hexpcounter`
- no caller
- The second child of `hexpcounter` (the SetText holder object from the call above) scale is set to (1.75, 1.75, 1.0)
From there, this section is done, but the logic will change on further updates since `hexpcounter` now exists.
Basically, the game will manage the `idletimer` field which will control the positioning of the `hexpcounter` and the `expholder`. The `idletimer` is reset to 0 constantly until the [currentaction](../../Player%20UI/Pick.md) becomes `BaseAction` (the main vine menu). When that happens, it will get incremented once on this cycle until it reaches 250.
What will happen from there is the `hexpcounter` local posiiton will be set to a lerp from the existing one to (7.4, -6.5, 10.0) if the `idletimer` hasn't reached 200 or to (7.4, -4.4, 10.0) if it reached it. All with a factor of a 1/10 of the game's frametime in either case. This essentially will hide the counter offscreen at the bottom until at least 200 frames passed when the player was naviguating the main vine action menu where it will smoothly reveal itself.
If the `expholder` still exists, its x local position gets set to 0.0 if `idletimer` hasn't reached 200 yet or to -3.25 if it did. This moves the orbs to the left when the `hexpcounter` is shown so they don't overlap.
### Enemies [hitaction](../../Actors%20states/Enemy%20features.md#hitaction)
`hitaction` is a field on [BattleData](../../Actors%20states/BattleData.md) that tells if an enemy wants to perform an action immediately on the next controlled 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 to temporarilly seize control of the turn flow to perform their action. This section handles these.
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](../../Actors%20states/IsStopped.md) returns true (without [actimmobile](../../Actors%20states/Enemy%20features.md#actimmobile) check), their `hitaction` gets set to false and nothing happens as it gets skipped
- Otherwise, `enemy` is set to true and a [DoAction](../Action%20coroutines/DoAction.md) call occur with the battleentity with actionid being the `enemydata` index. This will also end the update cycle
For more information on how this works, check the [hitaction](../../Actors%20states/Enemy%20features.md#hitaction) documentation.
This cycle repeats for all applicable enemies untill all `hitaction` are set to false at which point, the main turn procedure can continue.
## GUI cooldown
This only decreases `guicooldown` by the game's frametime if it hasn't expired yet. However, this cooldown isn't actually used anywhere making this dead logic.
## Main turn procedure
This is where the main turn logic happens.
This procedure is documented in the [main turn life cyle](../Main%20turn%20life%20cycle.md) document.

View File

@@ -0,0 +1,10 @@
# Terminal flow
This is one of the flow of [Update](../Update.md) which only happens if the battle is about to end or retried.
This flow happens if `cancelupdate` is true or instance.`pausemenu` exists.
The former is only set to true when some kind of terminal coroutine occurs (such as a game over) where we know the battle will end in some ways (but it may be retried). The latter only happens after selecting the change loadout and retry option after a game over which brings up a cut down pause menu.
In this flow, absolutely no update logic occurs. The flow is completely controlled by whichever coroutine set `cancelupdate` or the PauseMenu. This flow is only entered in terminal cases where we know for sure the battle will end or retried.
It is also possible to enter this flow by setting instance.`inbattle` to false which happens when we know the battle will end without retry, but this alone won't technically be the same without setting `cancelupdate` to true. Doing this will still allow [RefreshEXP](../../Visual%20rendering/RefreshEXP.md) calls that normally happens in the other 2 flows only. However, because they only happen if `oldexp` doesn't match `expreward`, it ends up not mattering because no EXP can be gained in any terminal cases (since the battle is already scheduled to end in some ways). It should be noted that the only terminal case where this happens while `cancelupdate` remains false is a sucessfull flee attempt.

View File

@@ -0,0 +1,28 @@
# Uncontrolled flow
This is one of the flow of [Update](../Update.md) which happens when Update delegates most controls to an action coroutine.
This flow happens if `action` or `inevent` is true which means that an action coroutine or an EventDialogue took control of the battle flow. This means that Update relegated its control and it features a very reduced logic compared to a [controlled flow](Controlled%20flow.md). It is meant to be entered temporarily where control will eventually be given back to a controlled flow with the exception of [terminal](Terminal%20flow.md) cases which ends or retries the battle.
The main feature of this flow is less UI being shown as they are mostly disabled.
Here are all the logic included in this flow.
## RefreshEXP
If the `oldexp` value doesn't match the current `expreward`, [RefreshEXP](../../Visual%20rendering/RefreshEXP.md) is called. This method manages the visual rendering of the currently cumulated EXP and the different orbs that composes it. `expreward` is the actual EXP cumulated so far while `oldexp` is the last value observed since the last RefreshEXP. It will also create `expholder` if it wasn't created already.
## HP UI refresh
[RefreshEnemyHP](../../Visual%20rendering/RefreshEnemyHP.md) is called every 3 frames. It should be noted that in this flow, this will always results in the `hpbar` of the enemies to be disabled. This means this refresh is less useful here, but it's more useful in a controlled flow.
## UpdateSwitchIcon
UpdateSwitchIcon is called. It should be noted that in this flow, this will always results in the `switchicon` to be disabled. This means this refresh is less useful here, but it's more useful in a controlled flow.
## Blocking updates
This section happens only when all the following are fufilled:
- `enemy` is true (we are in the player phase)
- `inevent` is false (no [EventDialogue](../EventDialogue.md) is in progress)
- The [message](../../../SetText/Notable%20states.md#message) lock is released (covers cases like [Tattle](../Action%20coroutines/Tattle.md))
[GetBlock](../GetBlock.md) is called here which updates `blockcooldown` and `commandsuccess` according to the current blocking state. Consult the GetBlock documentation to learn more about how the blocking system works.
This is the only logic that is exclusive to an uncontrolled flow.

View File

@@ -0,0 +1,12 @@
# Update
This Unity event is the main dispatcher of the battle flow. It only handles the synchronous high level flow that runs as long as control wasn't delegated to an action coroutine.
There are 3 possible flows to a BattleControl update: terminal, uncontrolled and controlled. The flows are documented in their own page.
The first flow whose conditions are fufilled will apply from the following table:
|Flow|Conditions|Description|
|---:|----------|-----------|
|[Terminal](Update%20flows/Terminal%20flow.md)|`cancelupdate` is true or instance.`pausemenu` exists|A flow where Update relegates almost complete control to a terminal coroutine which will end or retry this battle|
|[Uncontrolled](Update%20flows/Uncontrolled%20flow.md)|`action` or `inevent` is true|A flow where Update delegates most (but not all) control to an action coroutine which performs a specific battle action|
|[Controlled](Update%20flows/Controlled%20flow.md)|The battle isn't in a terminal or uncontrolled flow|A flow where Update has complete control of the battle and will act as a dispatcher according to the main turn procedure|

View File

@@ -0,0 +1,102 @@
# UseCharm
This is a coroutine that is invoked at specific moments of [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md) and [AddExperience](../Battle%20flow/Terminal%20coroutines/AddExperience.md). It will, when applicable, process a charm if the player had some left with the amount remaining being tracked by [flagvar](../../Flags%20arrays/flagvar.md) 22.
The coroutine is expected to be stored in `checkingdead` as it will be set to null at the very end so the caller can yield on it. As for who gets targetted by the charm, it's either the party or the `currentturn` player party member depending on the `Charm`, an enum that identifies a charm type.
```cs
private IEnumerator UseCharm(Charm type)
```
## Parameters
- `type`: The type of the charm to attempt to apply
## Procedure
In order for this coroutine to process the charm, all of the following must true when it is invoked (otherwise, nothing happens except `checkingdead` being set to null):
- [flagvar](../../Flags%20arrays/flagvar.md) 22 is above 0 (the player has at least 1 charm left)
- `charmcooldown` is 0
- A 6% random test must pass (generate a random integer number between 0 and 100 exclusive, that number converted to float must be \<= 5.5 which is a pass from 0 to 5 inclusive which makes it 6%)
- At least 1 player party member's `hp` is above 0 and isn't `eatenby`
- EnemyActingOutOfOrder returns false meaning no enemy party member's [hitaction](../BattleControl.md#hitactions) is true
- Either the type is `ExpUp` (meaning it was invoked from [AddExperience](../Battle%20flow/Terminal%20coroutines/AddExperience.md)) or it's any other type while `cancelupdate` is false (we aren't in a [terminal flow](Update%20flows/Terminal%20flow.md))
- If the type is `AttackUp`, `playerdata[currentturn]` must not have the [AttackUp](../Actors%20states/BattleCondition/AttackUp.md) condition already
The following sections describes what happens when the charm is cleared to be processed.
### Charm animation
This section will be paraphrased as it contains verbose animation logic:
- The `Magic` sound is played
- A new nameless GameObject is created (locally refered to as dancer) that will have a SpriteRenderer initially using the `charmdance[0]` sprite (which is sprite 98 of `Sprites/Entities/moth0`) on layer 15 (`3DUI`) fully opaque with a SpinAround and a position of (0.0, 0.0, -0.5)
- All the intensity of Light GameObjects are saved locally
- Over the course of 40.0 frames (tracked with a local frame counter):
- The dancer's alpha will be lerped from 0.0 to 0.6 with the factor being the time progression over the 40.0 frames
- The SpinAround on the dancer has its `itself`'s Y component set to a lerp from 0.0 to 15.0 with a factor of the time progression over the 40.0 frames (the X and Z components are always set to 0.0)
- All Light GameObject's intensity will be lerped from their initial value saved locally to half of it with a factor of the time progression over the 40.0 frames
- 0.5 seconds are yielded
- The dancer's sprite is set to `charmdance[1]` (which is sprite 99 of `Sprites/Entities/moth0`)
- The SpinAround of the dancer is destroyed
- The angles of the dancer are set to (0.0, 180.0, 0.0)
### Charm process
The logic here depends on the type:
#### `AttackUp`
- [StatEffect](../Visual%20rendering/StatEffect.md) is called on `playerdata[currentturn]` with type 0 (red up arrow)
- [SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called on `playerdata[currentturn]` giving the [AttackUp](../Actors%20states/BattleCondition/AttackUp.md) condition for 1 actor turn
- The `StatUp` sound is played
#### `DefenseUp`
- All player party members whose `hp` is above 0 and aren't `eatenby` have the following happen to them:
- [StatEffect](../Visual%20rendering/StatEffect.md) is called on the player party member with type 1 (blue up arrow)
- [SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called on the player party member giving the [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) condition for 1 actor turn
- The `StatUp` sound is played
#### `ExpUp`
- `expreward` is multiplied by 1.15 floored then clamped from 0 to instance.`neededexp`
- [RefreshEXP](../Visual%20rendering/RefreshEXP.md) is called
#### `HealHP`
- All player party members whose `hp` is above 0 and aren't `eatenby` have the following happen to them:
- The amount of HP to heal is determined which is the player party member's `maxhp` * 0.2 floored clamped from 1 to the `maxhp`
- The player party member's `hp` is increased by the amount to heal then clamped from 0 to its `maxhp`
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 1 with the amount of HP healed as the ammount starting at the player party member's battleentity position + Vector3.up to (2.0, 2.0, 2.0)
- The `StatUp` sound is played
#### `HealTP`
This type expects [flagvar](../../Flags%20arrays/flagvar.md) 1 to be set to the amount of TP to heal. This is the responsibility of the caller.
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 2 with [flagvar](../../Flags%20arrays/flagvar.md) 1 as the ammount starting at the player party member's battleentity position + Vector3.up to (2.0, 2.0, 2.0)
- instance.`tp` is increaded by [flagvar](../../Flags%20arrays/flagvar.md) 1 then clamped from 0 to instance.`maxtp`
- The `Heal2` sound is played
### End animation
The following is paraphrased as it contains verbose animation logic:
- Over the course of 40.0 frames (tracked with a local frame counter):
- The dancer's alpha will be lerped from 0.6 to 0.0 with the factor being the time progression over the 40.0 frames
- All Light GameObject's intensity will be lerped from half of their their initial value saved locally to their original value before this UseCharm call with a factor of the time progression over the 40.0 frames
- All Light GameObject's intensity are restored to their original value before this UseCharm call
- The dancer is destroyed
### Last steps
- [flagvar](../../Flags%20arrays/flagvar.md) 22 is decremented (this consumes the charm)
- `charmcooldown` is set to a random number from 3 to 7 inclusive (this means a minimum amount of main turn needs to advance before the next charm is able to be processed even if it can be and the amount is between 3 and 7)
- If [flagvar](../../Flags%20arrays/flagvar.md) 22 reached 0 (meaning the last charm was just consumed):
- A [SetText](../../SetText/SetText.md) call occurs in [dialogue move](../../SetText/Dialogue%20mode.md#dialogue-mode) using the text `|`[boxstyle](../../SetText/Individual%20commands/Boxstyle.md)`,4||`[center](../../SetText/Individual%20commands/Center.md)`||`[halfline](../../SetText/Individual%20commands/Halfline.md)`||`[spd](../../SetText/Individual%20commands/Spd.md)`,0|` followed by `menutext[184]` (a message informing the player they no longer have any charms). The call also has these properties:
- [fonttype](../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- linebreak of `messagebreak`
- No tridimensional
- position of Vector3.zero
- No cameraoffset
- size of Vector3.one
- No parent
- No caller
- All frames are yielded while the [message](../../SetText/Notable%20states.md#message) lock is grabbed
- `checkingdead` is set to null which informs the caller the coroutine is complete

View File

@@ -0,0 +1,290 @@
# Battle state
These fields describes the state of the battle. Some fields belongs to MainManager, but are mostly BattleControl related.
## BattleControl fields
This is all the BattleControl fields.
### Battle setup information
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|battlemap|GameObject|Yes|The parent of all the battles objects notably the battle map prefab. This is a game object named `Battle` created on [StartBattle](StartBattle.md)|
|caller|[NPCControl](../Entities/NPCControl/NPCControl.md)|No|The [Enemy](../Entities/NPCControl/Enemy.md) NPCControl whose encounters caused this battle. This is set to the calledfrom value sent to [StartBattle](StartBattle.md). If it's null, no encounter caused this battle and it was started manually|
|sadv|int|No|The starting advantage value. Set to the sent adv value of [StartBattle](StartBattle.md), but adv is set to this field if it's a [retry](Battle%20flow/Retry.md). The only recognised value is 3 which means the enemy party has the advantage, other values do nothing|
|sdata|StartUpData|No|The [StartUpData](StartUpData.md) stored during [StartBattle](StartBattle.md) when `saveddata` is false. Restored on StartBattle for a [retry](Battle%20flow/Retry.md)|
|saveddata|bool|No|Whether the `sdata` have been saved and are ready for restoration. Set to true at the very end of [StartBattle](StartBattle.md)|
|canflee|bool|Yes|Whether fleeing is allowed as well as [retry](Battle%20flow/Retry.md) when a [GameOver](Battle%20flow/Terminal%20coroutines/GameOver.md) occurs. Set to the canescape value sent to [StartBattle](StartBattle.md)|
### Battle flow
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|action|bool|Yes|If true, it means an action coroutine or a method controls the battle flow making it an [uncontrolled flow](Battle%20flow/Update%20flows/Uncontrolled%20flow.md). Set to false on [StartBattle](StartBattle.md)|
|inevent|bool|Yes|Tells if an [EventDialogue](Battle%20flow/EventDialogue.md) is in progress or not. If one is, we enter an [uncontrolled flow](Battle%20flow/Update%20flows/Uncontrolled%20flow.md)|
|calleventnext|int|No|If not negative, the [EventDialogue](Battle%20flow/EventDialogue.md) whose id is this value will be done on the next [uncontrolled flow](Battle%20flow/Update%20flows/Uncontrolled%20flow.md). This is only used in conjuction with an enemy party member's [eventonfall](Actors%20states/Enemy%20features.md#eventonfall) when it triggers|
|cancelupdate|bool|Yes|Whether updates are disabled which only happen when some kind of terminal event occurs that changes the flow to a [terminal flow](Battle%20flow/Update%20flows/Terminal%20flow.md). Set to false on [StartBattle](StartBattle.md)|
|alreadyending|bool|Yes|Tells when the battle is about to end via [GameOver](Battle%20flow/Terminal%20coroutines/GameOver.md) or [AddExperience](Battle%20flow/Terminal%20coroutines/AddExperience.md). Set to false on [StartBattle](StartBattle.md). This protects against potential double terminal flow changes|
|enemy|bool|Yes|Whether we're in the [enemy phase](Battle%20flow/Main%20turn%20life%20cycle.md#enemy-phase) or not (false means we're in the [player phase](Battle%20flow/Main%20turn%20life%20cycle.md#player-phase)) of the turn of a [controlled flow](Battle%20flow/Update%20flows/Controlled%20flow.md) or processing a [hitaction](Actors%20states/Enemy%20features.md#hitaction) or processing a [delproj](Actors%20states/Delayed%20projectile.md). Set to false on [StartBattle](StartBattle.md)|
|mainturn|Coroutine|No|The [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) coroutine if one is in progress (null if it's not)|
|delprojs|DelayedProjectileData\[\]|Yes|The [delayed projectiles](Actors%20states/Delayed%20projectile.md) currently active|
|turns|int|No|The amount of completed main turns advanced by [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md). Set to 0 on [StartBattle](StartBattle.md)|
|demomode|bool|No|If true, indicates the battle operates in tutorial mode|
|gameover|Coroutine|No|The current [GameOver](Battle%20flow/Terminal%20coroutines/GameOver.md) coroutine is one is in progress (null if it's not). Set to null on [StartBattle](StartBattle.md)|
|halfload|bool|Yes|Whether or not [StartBattle](StartBattle.md) roughly got done half of the starting process. This is set to true right after calling SetLastTurns and it's used by the game to yield until this goes to true|
|avaliableplayers|int|No|The amount of players that are considered free by [GetFreePlayerAmmount](Actors%20states/Player%20party%20members/GetFreePlayerAmmount.md). Set to the current amount on [StartBattle](StartBattle.md) and updated in specific situations|
|currentturn|int|Yes|Determine the `playerdata` index currently selected for an action. -1 means no one is selected yet, being below `playerdata` length means that player index is selected and being at length or above means all players have taken their actions and the player phase is over. Set to -1 on [StartBattle](StartBattle.md)|
|lastturns|int\[\]|No|The state of the player index selection cycle which starts with an array with a length of the amount of free players - 1. Advancing it means either assigning the first free slot (-1) to the player being selected or shift the elements such that it falls on the latest while the oldest is removed|
|receivedrelay|bool\[\]|No|An array indicating which player index got relayed to via [Relay](Battle%20flow/Action%20coroutines/Relay.md) which allows the `tiredpart` to be rendered whenever `tired` gets above 0 during [UpdateAnim](Visual%20rendering/UpdateAnim.md)|
|actedthisturn|bool|No|Tells if [PlayerTurn](Battle%20flow/PlayerTurn.md) was called at least once during the turn implying at least one player could act. Set back to false on [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)|
|noaction|int|No|The amount of main turns in a row where `actedthisturn` was false. If it reaches 5 without game over, the [inactive failsafe](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md#inaction-failsafe) triggers in [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)|
|attackedally|int|No|The `playerdata` index that was attacked while the `FavoriteOne` [medal](../Enums%20and%20IDs/Medal.md) was equipped on them which will cause it to take effect during [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md). If this medal isn't applicable, the value is -1|
|firststrike|bool|No|Whether or not the enemy is currently acting as part of the enemy party getting the starting advantage during [StartBattle](StartBattle.md)|
|summonnewenemy|bool|No|If true, it means that the game is in the process of summoning an enemy from the `extraenemies` to `enemydata` via [SummonEnemy](Actors%20states/Enemy%20party%20members/SummonEnemy.md), called duing [CheckDead](Battle%20flow/Action%20coroutines/CheckDead.md). This prevents SummonEnemy to set `checkingdead` to null once completed to not interfere with the ongoing CheckDead and it also allows CheckDead to wait the summon is over|
|selfsacrifice|bool|No|If true, it indicates that the enemy party member killed themselves during their [DoAction](Battle%20flow/Action%20coroutines/DoAction.md)|
|eatenkill|bool|Yes|If true, it indicates that a player party member was killed by a `Pitcher` [enemy](../Enums%20and%20IDs/Enemies.md) by draining their HP which allows [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) to handle this special case|
|lastdamage|int|No|The last final amount of damage done at the end of [DoDamage](Damage%20pipeline/DoDamage.md)|
|damagethisturn|int|No|The amount of damage the player party inflicted in the current main turn. If it gets higher than [flagvar](../Flags%20arrays/flagvar.md) 41 (highest damage in one turn), the flagvar value is set to it before resetting the value of damagethisturn in [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)|
|charmcooldown|int|No|The amount of main turns that needs to pass for [UseCharm](Battle%20flow/UseCharm.md) to process the next charm even if one is available and could have been processed otherwise. Set to a random integer between 3 and 7 inclusive after a charm has been processed and decremented on [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)|
### Actors information
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|partypointer|int\[\]|Yes|The mapping from battle order formation to `playerdata` index. Aligned with the correct order on [StartBattle](StartBattle.md) and changed on [SwitchParty](Battle%20flow/Action%20coroutines/SwitchParty.md) or [SwitchPos](Battle%20flow/Action%20coroutines/SwitchPos.md). Check the [battle party addressing documentation](playerdata%20addressing.md#methods-of-addressing-durring-battle) for more details|
|partyentities|[EntityControl](../Entities/EntityControl/EntityControl.md)\[\]|No|Set to all the `playerdata` battleentity on [StartBattle](StartBattle.md)|
|alldata|[BattleData](Actors%20states/BattleData.md)\[\]|Yes|All the `playerdata` followed by all the `enemydata` appended together. Set by RefreshAllData which is only called during [StartBattle](StartBattle.md)|
|enemydata|[BattleData](Actors%20states/BattleData.md)\[\]|Yes|The first enemy party members data with a length up to 4 (the extra ones are stored in `extraenemies`). Set to a new list with the same length as the sent enemyids on [StartBattle](StartBattle.md) (after it was truncated to the first 4) and then filled with the actual enemy data|
|extraenemies|List<int>|No|This contains the list of [enemy](../Enums%20and%20IDs/Enemies.md) ids that overflows the maximum amount of enemies allowed in `enemydata` which is 4. It is initialised as such on [StartBattle](StartBattle.md)|
|reservedata|List<BattleData>|No|The list of enemies who are no longer part of `enemydata` because they had died and were moved there by [CheckDead](Battle%20flow/Action%20coroutines/CheckDead.md) since their [deathtype](Actors%20states/Enemy%20features.md#deathtype) indicated they should be moved there. Doing so prevents a full destruction which allows the enemy to be revived later or to visually have a death animation without disappearing. Reset to a new list on [StartBattle](StartBattle.md)|
|enemyfled|bool|No|Whether at least one enemy party member fled the battle or not|
|lastaddedid|int|No|The last enemy party member index added via [AddNewEnemy](Actors%20states/Enemy%20party%20members/AddNewEnemy.md)|
|tempslot|BattleData|No|The last enemy to be added in `enemydata` according to [NewEnemy](Actors%20states/Enemy%20party%20members/NewEnemy.md) if the sent animation value isn't `None`|
|deadenemypos|List<Vector3>|No|The list of the positions of previously dead enemies as found by [CheckDead](Battle%20flow/Action%20coroutines/CheckDead.md). It is only used by CheckDead in case `extraenemies` needs to be summoned in the place of the dead ones at the same positions they were before|
|deadmembers|int\[\]|No|The array of player party members indexes whose `hp` is 0 or below as returned by GetDeadParty. Used during [RevivePlayer](Actors%20states/Player%20party%20members/RevivePlayer.md) to decide whether to resucitate the player party member|
### Attack and flow modifiers
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|dontusecharge|bool|No|If true, the `charge` of the enemy party member will not be reset to 0 on [EndEnemyTurn](Battle%20flow/EndEnemyTurn.md)|
|nonphyscal|bool|No|If true, indicate to the damage pipeline that the damages aren't physical which affects the effects of the `FrostBite`, `SpikeBod` and `PoisonTouch` [medal](../Enums%20and%20IDs/Medal.md#)|
|nolifesteal|bool|Yes|If true, disables the effects of the `LifeSteal` [medal](../Enums%20and%20IDs/Medal.md) during the damage pipeline|
|lockmmatter|bool|Yes|If true, prevents the `MiracleMatter` [medal](../Enums%20and%20IDs/Medal.md) to take effect. Set to false on StartBattle|
### Actions commands and blocking
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|actionroutine|Coroutine|No|Tracks the progress of a [DoCommand](Action%20commands/DoCommand.md) coroutine|
|doingaction|bool|Yes|If true, an action command is in progress|
|successfulchain|int|No|The amount of sucessful inputs perfomred in a `LongRandomBar` action commands during [DoCommand](Action%20commands/DoCommand.md)|
|presskey|int|No|A general purpose input id for use in [DoCommand](Action%20commands/DoCommand.md)|
|barfill|float|No|A number between 0.0 and 1.0 that tells the ratio of an action command's bar's filled portion which is managed by [DoCommand](Action%20commands/DoCommand.md)|
|infinitecommand|bool|No|If true, action commands processed by [DoCommand](Action%20commands/DoCommand.md) will use their infinite variant TODO: define what this is in part 3|
|killinput|bool|No|Used for the `PressKey` action command that when set to true, [DoCommand](Action%20commands/DoCommand.md) will stop listening for inputs|
|commandsuccess|bool|Yes|Tells if the last action command succeeded or tell if the player is currently blocking (tracked by [GetBlock](Battle%20flow/GetBlock.md))|
|buttons|ButtonSprite\[\]|No|A general purpose array of ButtonSprites for use in [DoCommand](Action%20commands/DoCommand.md)|
|commandsprites|SpriteRenderer\[\]|No|A general purpose SpriteRenderer array for use in [DoCommand](Action%20commands/DoCommand.md) or other action commands related needs|
|helpboxid|int|No|The id of the current action command whose description should be rendered in `helpbox` by [CreateHelpBox](Visual%20rendering/CreateHelpBox.md#createhelpbox)|
|helpbox|DialogueAnim|No|The 9box containing the action command description whose id is `helpboxid` rendered by [CreateHelpBox](Visual%20rendering/CreateHelpBox.md#createhelpbox)|
|superblockedthisframe|float|No|A short lived cooldown in frames that allows a super block to still count until it expires, check [GetBlock](Battle%20flow/GetBlock.md) to learn more. Used in the damage pipeline and maintained by [LateUpdate](Visual%20rendering/LateUpdate.md)|
|blockcooldown|float|No|The amount of frames left that a block can be processed, check [GetBlock](Battle%20flow/GetBlock.md) for more details|
|hasblocked|bool|No|If true, the damage pipeline detected the player blocked the attack with a valid block (even if FRAMEONE rules would have prevented it). This is only used in HardSeedVenus, a coroutine specific to the `VenusBoss` [enemy](../Enums%20and%20IDs/Enemies.md)|
|overridechallengeblock|bool|Yes|Normally, standard blocks are disallowed when [flags](../Flags%20arrays/flags.md#flags) 615 and 15 are true (FRAMEONE is active while past the first tutorial fight), but if this field is true, it allows to override that behavior to allow them regardless of these conditions being fufilled or not|
### Targetting
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|avaliabletargets|BattleData\[\]|No|An ephemeral array of actors to track possible targets for an action which is frequently set by calling [GetAvailableTargets](Actors%20states/Targetting/GetAvaliableTargets.md)|
|forceattack|int|No|The player party member's [animid](../Enums%20and%20IDs/AnimIDs.md) index that will be forced to be returned during [GetRandomAvaliablePlayer](Actors%20states/Targetting/GetRandomAvaliablePlayer.md). This is only set in the course of the `Taunt` [skill](../Enums%20and%20IDs/Skills.md) during its [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) logic|
|playertargetID|int|No|The player party member index whom is currently targetted by the enemy. If it's -1, the enemy isn't targetting anyone|
|playertargetentity|EntityControl|No|An actor to use for targetting purposes (NOTE: despite the name, it can be an enemy party member as enemies can sometimes target other enemy party members outside of the damage pipeline)|
|targetedenemy|int|No|Indicates the enemy party member index that `Beetle` will target when using his basic attack or the `HeavyStrike` skill during [DoAction](Battle%20flow/Action%20coroutines/DoAction.md)|
|target|int|No|The index of the selected target when selecting a player or enemy|
### Chompy informations
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|chompy|[EntityControl](../Entities/EntityControl/EntityControl.md)|No|If [flags](../Flags%20arrays/flags.md) 402 is true (Chompy is with Team Snakemouth), this is initialised to a new entity created via [CreateNewEntity](../Entities/EntityControl/EntityControl%20Creation.md#createnewentity) with name `chompy` with the `ChompyChan` [animid](../Enums%20and%20IDs/AnimIDs.md) on [StartBattle](StartBattle.md)|
|chompyattack|Coroutine|Yes|The coroutine of [Chompy](Battle%20flow/Action%20coroutines/Chompy.md) if it's in progress (null if it's not)|
|chompyaction|bool|No|Tells if [Chompy](Battle%20flow/Action%20coroutines/Chompy.md) is in progress or not|
|chompyattacked|bool|No|Tells if [Chompy](Battle%20flow/Action%20coroutines/Chompy.md) has completed during the [player phase](Battle%20flow/Main%20turn%20life%20cycle.md#player-phase) when applicable|
|coptions|List<int>|No|The list of action options available during [Chompy](Battle%20flow/Action%20coroutines/Chompy.md): 0 is basic attack, 1 is do nothing, 2 is the ribbon specific attack and 3 is change ribbon|
|chompyoption|int|No|The last chosen `coption` the last time [Chompy](Battle%20flow/Action%20coroutines/Chompy.md) was called|
|chompylock|bool|No|If true, it prevents [Chompy](Battle%20flow/Action%20coroutines/Chompy.md) to be a part of the [player phase](Battle%20flow/Main%20turn%20life%20cycle.md#player-phase) even if it would normally be allowed. This is only used during [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) specifically for the `Centipede` [enemy](../Enums%20and%20IDs/Enemies.md)|
### AI party informations
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|aiparty|[EntityControl](../Entities/EntityControl/EntityControl.md)|No|The entity that was created as part of [AddAI](StartBattle%20phases/Post%20haltbattleload.md#ai-setup) if one was created|
|aiattacked|bool|No|Tells if [AIAttack](Battle%20flow/Action%20coroutines/AIAttack.md) has completed during the player phase when applicable|
### EXP and berries
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|estimatedexp|int|No|The sum of all the calculated `enemydata`'s `exp`|
|expreward|int|No|The amount of EXP cumulated in the course of the battle that will be granted if the battle is won. Set to 0 on [StartBattle](StartBattle.md)|
|oldexp|int|No|The last value of `expreward` observed since the last [RefreshEXP](Visual%20rendering/RefreshEXP.md). If it differs with the current one, RefreshEXP will be called on the next applicable [Update](Battle%20flow/Update.md)|
|leveled|bool|No|Indicates that [AddExperience](Battle%20flow/Terminal%20coroutines/AddExperience.md) detected a rank up situation|
|moneyreward|int|No|The amount of berries that will be dropped after the battle. Set to 0 on [StartBattle](StartBattle.md)|
### UI naviguation
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|currentaction|[Pick](Player%20UI/Pick.md)|Yes|The current menu being naviguated by the player. Set to `BaseAction` on [StartBattle](StartBattle.md)|
|currentchoice|[Actions](Player%20UI/Actions.md)|Yes|The current action being selected on the `BaseAction` menu. Set to `Attack` on [StartBattle](StartBattle.md)|
|itemarea|[AttackArea](Player%20UI/AttackArea.md)|No|Tells what actors are selectable to perform the current action|
|maxoptions|int|No|The amount of available `option` on the main vine menu|
|lastoption|int|No|The last selected `option` on the main vine menu|
|selecteditem|int|No|The selected `listvar` option from an [ItemList](../ItemList/ItemList.md), set by [SetItem](Player%20UI/SetItem.md)|
|vineoption|int|No|Equivalent to `maxoption`, but for the main vine menu value|
|option|int|Yes|The current vine menu option. 0 is attack, 1 is skills, 2 is items, 3 is strategies and 4 is turn relay. Set to 0 on [StartBattle](StartBattle.md). This can also be the index of an enemy or player target being selected. NOTE: the vine order is reversed in game as left goes up and right goes down in the option index with wrap around|
|excludeself|bool|Yes|If true, it will cause the `currentturn` player to not be selectable in a `currentaction` of `SelectPlayer` in [GetChoiceInput](Player%20UI/GetChoiceInput.md)|
|tempskill|int|Yes|The [skill](../Enums%20and%20IDs/Skills.md) id that was confirmed from skills selection in [SetItem](Player%20UI/ItemList%20confirmation%20handling/Skills%20list%20type.md)|
|lastskill|int|No|The last [skill](../Enums%20and%20IDs/Skills.md) id used, set to `selecteditem` before its usage when confirmed in [GetChoiceInput](Player%20UI/GetChoiceInput.md)|
|lastaction|int|No|The last [action](Player%20UI/Actions.md) chosen by a player party member. Set to `option` on [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) which keeps the last selected vine menu options since the last one chosen on the new turn|
|idletimer|int|No|The amount of frames since the player idled which is used in the [EXP counter update](Battle%20flow/Update%20flows/Controlled%20flow.md#exp-counter-updates)|
|turncooldown|float|No|The amount of [FixedUpdate](Visual%20rendering/FixedUpdate.md) cycles left before [GetChoiceInput](Player%20UI/GetChoiceInput.md) calls are allowed during [PlayerTurn](Battle%20flow/PlayerTurn.md). Set to 5.0 in [SetItem](Player%20UI/SetItem.md) and [CancelList](Player%20UI/CancelList.md)|
|caninputcooldown|float|No|A general purpose input cooldown in amount of frames left before expiring. Notably, it has an important role in [GetBlock](Battle%20flow/GetBlock.md)|
### UI rendering
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|vinebase|Transform|No|A GameObject named `Base` childed to `choicevine`|
|choicevine|Transform|No|A GameObject named `Vine` that is the root of the vines UI objects, childed to the `battlemap` and initialised on CreateVine as part of [PlayerTurn](Battle%20flow/PlayerTurn.md)|
|vineicons|SpriteRenderer\[\]|No|The vine icons of the vine menu, childs of `vinebase`|
|cursor|Transform|No|The selection leaf cursor. Initialised on CreateCursor which is only called on [StartBattle](StartBattle.md)|
|switchicon|Transform|No|The parent of the UI objects that composes the switch icon which is a GameObject named `switchicon` childed to the `GUICamera`. Initialised on [StartBattle](StartBattle.md)|
|fronticon|SpriteRenderer|No|The SpriteRenderer of the UI object named `attackicon` childed to the `GUICamera` that corresponds to the icon the front party member has. Initialised on [StartBattle](StartBattle.md)|
|hexpcounter|Transform|No|The EXP counter shown when idling for 200+ frames when `currentaction` is `BaseAction`. Created on the first [controlled update flow](Battle%20flow/Update%20flows/Controlled%20flow.md)|
|expholder|Transform|No|A GameObject named `expholder` childed to the `GUICamera` with tag `DelAftBtl` (destroyed on [ReturnToOverworld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)) that holds the EXP orbs cumulated in the battle for visual rendering|
|lvicon|Transform|No|The EXP icon sprite used in the UI during [AddExperience](Battle%20flow/Terminal%20coroutines/AddExperience.md)|
|hideenemyhp|bool|Yes|If true, the `hpbar` of every enemy party members's battleentity gets disabled on [RefreshEnemyHP](Visual%20rendering/RefreshEnemyHP.md)|
|actiontext|SpriteRenderer|No|The UI element for the game to indicate the current action being selected which is the SpriteRenderer of a new GameObject named `ActionText` childed to the `GUICamera`. Initialised on [StartBattle](StartBattle.md)|
|smallexporbs|Transform\[\]|No|The array of smaller orbs (one per 1 EXP below 10 remaining) which are instances of `Prefabs/Objects/ExpOrbGUI` rendered as child of the `expholder`|
|bigexporbs|Transform\[\]|No|The array of larger orbs (one per 10 EXP) which are instances of `Prefabs/Objects/ExpOrbGUI` rendered as child of the `expholder`|
|longcancel|bool|No|Whether the Cancel input is considered wider for rendering or not. Set to the return of InputIO.LongButton(5) on [StartBattle](StartBattle.md). This is involved during the rendering of the `switchicon`|
|cancelb|ButtonSprite|No|A ButtonSprite of the cancel input for use in [UpdateText](Visual%20rendering/UpdateText.md)|
### Visual effects
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|wordroutine|Coroutine|No|Tracks the progress of a [ShowSuccessWord](Visual%20rendering/ShowSuccessWord.md) coroutine|
|commandword|SpriteRenderer|No|The word SpriteRenderer used in [ShowSuccessWord](Visual%20rendering/ShowSuccessWord.md)|
|combo|int|No|The amount of consecutive successful action commands performed which influences visual and audio effects informing of the input successes|
|damcounters|List<Transform>|No|All of the currently rendered damage counters maintained by [CounterAnimation](Visual%20rendering/ShowDamageCounter.md#counteranimation), a sub coroutine of [ShowDamageCounter](Visual%20rendering/ShowDamageCounter.md). Set to a new list on StartBattle|
|defaultcounteroffset|Vector3|No|Always set to (0.0, 1.25, 0.0) for use in [DoDamage](Damage%20pipeline/DoDamage.md) when calculating the start of the [ShowDamageCounter](Visual%20rendering/ShowDamageCounter.md) call|
|counterspriteindex|int\[\]|No|Indicates the `guisprites` indexes of the different counter used in [ShowDamageCounter](Visual%20rendering/ShowDamageCounter.md). This is always {8, 40, 101}|
|partymiddle|Vector3|No|Always set to (-4.5, 0.0, 0.0) for use in [DoAction](Battle%20flow/Action%20coroutines/DoAction.md)|
|tiredpart|Transform\[\]|No|Set to a new array of the transform of instances of `Prefabs/Particles/Tired` on [StartBattle](StartBattle.md) belonging to each `playerdata` battleentity (each is childed to their battleentity) The length is thus the same than `playerdata`|
|tskybox|Material|No|The RenderSettings.skybox saved on [StartBattle](StartBattle.md). This is used for restoring later in case of a [retry](Battle%20flow/Retry.md)|
|fogdist|float|No|The value of RenderSettings.fogEndDistance saved on [StartBattle](StartBattle.md) if the current one needs to change. Restored from this field during [ReturnToOverworld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md) if it had a value above 0.0|
|dimmer|SpriteRenderer|No|A giant black colored sprite that covers everything behind the transition during load. Initialised on StartBattle after the fade in transition and disabled with a clear color just before the fade out one|
|charmdance|Sprite\[\]|No|The sprites Charmy uses during [UseCharm](Battle%20flow/UseCharm.md). Always set to sprite 98 and 99 of `Sprites/Entities/moth0` on [StartBattle](StartBattle.md)|
### Music
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|overworldmusic|AudioClip|No|On [StartBattle](StartBattle.md), this is set to MainManager.`music[0]`.clip if the map.`music[0]` exists and map.`musicid` is not negative. This is used for restoring the music on [ReturnToOverworld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)|
|overmusic|float|No|If `overworldmusic` was saved, the time of that music is saved on this field if MainManager.`keepmusicafterbattle` is true. This is also used for restore on [ReturnToOverworld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)|
|keepmusic|bool|Yes|Towards the end of [ReturnToOverworld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md) when instance.`inevent` is true, it is possible to skip the default behavior of fading the current music to silence by having this field set to true before ReturnToOverworld ends which will leave the current music playing instead|
### Camera
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|campos|Vector3|No|The `camtargetpos` that will be set when [SetDefaultCamera](Visual%20rendering/SetDefaultCamera.md) is called, normally Vector3.zero|
|camoffset|Vector3|No|The `camoffset` that will be set when [SetDefaultCamera](Visual%20rendering/SetDefaultCamera.md) is called, normally MainManager.`battlecampos`|
|oldcamoffset|Vector3|No|Set to instance.`camoffset` on [StartBattle](StartBattle.md) when it's not a retry. This is used for restore later on [ReturnToOverWorld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)|
|oldcamrotation|Vector3|No|Set to instance.`camangleoffset` on [StartBattle](StartBattle.md) when it's not a retry. This is used for restore later on [ReturnToOverWorld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)|
|oldcamspeed|float|No|Saved to instance.`camspeed` on [StartBattle](StartBattle.md) when it's not a retry. This is used for restore later on [ReturnToOverWorld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)|
### Misc coroutines tracking
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|checkingdead|Coroutine|Yes|Store diverse coroutines to track their progression (NOTE: despite the name, it's not just for [CheckDead](Battle%20flow/Action%20coroutines/CheckDead.md))|
|enemybounce|Coroutine\[\]|No|A general purpose coroutines array for use in [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) that is made to track EnemyBounce and SummonArtifact|
|tryenemyheal|Coroutine|No|Tracks the progress of a TryHealEnemyItem and EnemyFlee coroutines|
|spitout|Coroutine|No|The [SpitOut](Actors%20states/BattleCondition/Eaten.md#spitout) coroutine if one is in progress which is a coroutine used by the `Pitcher` [enemy](../Enums%20and%20IDs/Enemies.md). It is null if it's not in progress|
|gottaspit|bool|Yes|When calling [SpitOut](Actors%20states/BattleCondition/Eaten.md#spitout) (a coroutine specific to the `Pitcher` [enemy](../Enums%20and%20IDs/Enemies.md)), this needs to be set to false whenever `Pitcher` should spit out the player party member trapped within them|
|startdrop|bool|Yes|When a [Drop](../Entities/EntityControl/Notable%20methods/Drop.md#drop) calls occurs, the coroutine will eventually wait for this field to become true so it can proceed with the drops|
### Spying
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|disablespy|bool|Yes|If true, spying is disabled and cannot be performed on any enemy|
|scopeequipped|bool|No|Whether or not the `HPScope` [medal](../Enums%20and%20IDs/Medal.md) is equipped. Set as such on [StartBattle](StartBattle.md)|
### General purpose
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|tempdata|int|Yes|A general purpose integer for use in [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) meant to be set externally. This is only used for the `Spuder` [enemy](../Enums%20and%20IDs/Enemies.md)|
|extraentities|[EntityControl](../Entities/EntityControl/EntityControl.md)\[\]|Yes|A general purpose array of entities. This is only used when a `VenusBoss` [enemy](../Enums%20and%20IDs/Enemies.md) is involved|
### Unused fields
These fields are never referenced or never used in any meaningful ways.
|Name|Type|Public?|Description|
|----:|----|---------|-----------|
|weakenemyfound|bool|No|UNUSED, this is only set to false at the start of [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) and to true on TryHealEnemyItem when a heal occured, but the field is never read making it unused|
|actionid|int|No|UNUSED, this is only read during the damage pipeline, but never written to making it unused|
|oldmusicchannel|int|No|UNUSED|
|counter|int|No|UNUSED|
|selection|int|No|UNUSED|
|specialdefeat|bool|Yes|UNUSED|
|firstaction|bool|Yes|UNUSED|
|currententity|EntityControl|No|UNUSED|
|oldcamtarget|Transform|No|UNUSED, Set to instance.`camtarget` on [StartBattle](StartBattle.md) when it's not a [retry](Battle%20flow/Retry.md)|
|guicooldown|float|No|UNUSED (there is logic in Update implicating it was supposed to be a cooldown that exhausts only during an Update controlled battle, but it is never practically used anywhere else making it practically unused)|
## MainManager fields
These fields belongs to MainManager, but they are mostly related to BattleControl's state and either have influences on the battle or they are reporting the result of the battle.
### Player party
|Name|Type|Static?|Description|
|----:|----|---------|-----------|
|playerdata|[BattleData](Actors%20states/BattleData.md)\[\]|No|The battle data of the players. The game keeps track of them constantly even outside of battle, but [StartBattle](StartBattle.md) resets their fields to a default state|
|tp|int|No|The amount of TP the player party has (usually clamped from 0 to `maxtp`)|
|tpt|int|No|The displayed amount of TP the player party has in the HUD|
|maxtp|int|No|The maximum amount of TP the player can have (this is `basetp` + the medals effects from [ApplyBadges](ApplyBadges.md))|
|basetp|int|No|The base maximum amount of TP the player can have (this is normally 10 + all the bonuses applied from [ApplyStatBonus](ApplyStatBonus.md))|
|bp|int|No|The amount of MP the player party has, clamped to `maxbp`|
|maxbp|int|No|The maximum amount of MP the player party has|
|partylevel|int|No|The player party's rank, starts at 1 and maxes out at 27 under normal gameplay|
|partyexp|int|No|The amount of EXP the player party has (this amount is only the one applicable for the current rank's progression)|
|neededexp|int|No|The amount of EXP needed for the player party to rank up (in other words, `partyexp` needs to reach this value to rank up). This starts at 100|
### Battle modifiers
|Name|Type|Static?|Description|
|----:|----|---------|-----------|
|haltbattleload|bool|Yes|If this is set to true right after [StartBattle](StartBattle.md) starts by the caller, StartBattle will wait that it goes to false right after the fade in transition played|
|battlelossevent|bool|Yes|Tells if [ReturnToOverworld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md) should be called without flee if [DeadParty](Battle%20flow/Terminal%20coroutines/DeadParty.md) happens|
### Battle state and results
|Name|Type|Static?|Description|
|----:|----|---------|-----------|
|battle|[BattleControl](BattleControl.md)|Yes|The current battle (null if no battle is in progress). Set on [StartBattle](StartBattle.md) when it's null (meaning it wasn't a [retry](Battle%20flow/Retry.md))|
|inbattle|bool|No|Whether we are in battle or not. Set to true on [StartBattle](StartBattle.md) after the fade out transition and set to false in a [terminal](Battle%20flow/Update%20flows/Terminal%20flow.md) case where we know the battle will end without [retry](Battle%20flow/Retry.md)|
|partyorder|int\[\]|No|The list of player party members by their [animid](../Enums%20and%20IDs/AnimIDs.md) ordered by their formation in the overworld. Used to align the `partypointer` on [StartBattle](StartBattle.md)|
|battlenoexp|bool|Yes|Whether the last battle yielded no EXP. Set to false on [StartBattle](StartBattle.md)|
|battlefled|bool|Yes|Tells if the battle ended by fleeing|
|battleenemyfled|bool|Yes|Whether the battle ended while `enemyfled` was true without `expreward`. Set to false on [StartBattle](StartBattle.md). This won't be set to true for an [Enemy](../Entities/NPCControl/Enemy.md) NPCControl encounter if any `GoldenSeedling` [enemy](../Enums%20and%20IDs/Enemies.md) were defeated|
|lastdefeated|List<int>|No|The list of [enemy](../Enums%20and%20IDs/Enemies.md) ids that were defeated in the last battle (amended when applicable by [CheckDead](Battle%20flow/Action%20coroutines/CheckDead.md))|
|lastitemuser|int|Yes|The last player party member's `trueid` who used an item via [UseItem](Battle%20flow/Action%20coroutines/UseItem.md)|
|lastdefeated|List<int>|No|The list of [enemy](../Enums%20and%20IDs/Enemies.md) ids that [CheckDead](Battle%20flow/Action%20coroutines/CheckDead.md) detected were killed due to their `hp` reaching 0 or below. Set to a new list on [StartBattle](StartBattle.md) and reset to a new list after processing drops during the [Death](../Entities/EntityControl/Notable%20methods/Death.md) of the [Enemy](../Entities/NPCControl/Enemy.md) NPCControl if the battle was caused by a regular encounter|
|battleresult|bool|Yes|Whether the battle ended by winning (fleeing don't count) Set to true on [StartBattle](StartBattle.md) and set to false during [TryFlee](Battle%20flow/Action%20coroutines/TryFlee.md) (when succeeding) and during [DeadParty](Battle%20flow/Terminal%20coroutines/DeadParty.md)|
|firstbattleaction|bool|No|This is only set to true on the first [StartBattle](StartBattle.md) call since the last save load and it is used to apply an optimisation that involves a dummy [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) call. This is only needed on the first StartBattle call so when true, this optimisation doesn't happen again|

View File

@@ -0,0 +1,110 @@
# BattleControl
BattleControl is a component whose logic contain the entire battle system of the game. This makes it the most monolithic component of the game, but it is also relatively isolated because most of its members are private. The current battle is stored in instance.`battle` with the ability to query if we are in one by checking if it's not null or instance.`inbattle` being true. Some logic belongs in MainManager, but the vast majority belongs to BattleControl which means this will mostly be documenting BattleControl.
For details on BattleControl's fields, consult the [battle state](Battle%20state.md) documentation.
## Terminology
This system is the most complex in the game and as such, it is very easy to confuse terms for the purpose of documenting it. Due to this, there will be some standard terms with a consistent definition to reduce ambiguities as much as possible.
Here are all the terms that will be used throughout the battle system documentation:
- `player party member`: A `playerdata` element which is a [BattleData](Actors%20states/BattleData.md) corresponding to one of the player party members. It can be thought as someone part of the player's side of the battle. These elements are also used in the overworld, but the battle system documentation will focus on their roles during a battle
- `enemy party member`: An `enemydata` element which is a [BattleData](Actors%20states/BattleData.md) corresponding to one of the enemy party members. It can be thought as one of the enemies fought during the battle and is part of the enemy's side. These elements are only used during a battle
- `player party`: Refers to the the aggregate of all `playerdata` elements. This can be thought of as everyone from the player's side
- `enemy party`: Refers to the aggregate of all `enemydata` elements. This can be thought of as all the enemies fought in the battle
- `party`: Refers to either side of the battle (player or enemy)
- `actor`: Refers to any party members no matter which side they are on
- `action`: Refers to what an actor can do during the battle. In more concrete turn, anything that normally consumes an actor turn (usually through `cantmove`) counts as an action
- [player phase](Battle%20flow/Main%20turn%20life%20cycle.md#player-phase): Refers to the processing of all the player party's actions and all logic associated with it. More details in its documentation
- [enemy phase](Battle%20flow/Main%20turn%20life%20cycle.md#enemy-phase): Refers to the processing of all the enemy party's actions and all logic associated with it. More details in its documentation
- [turn end phase](Battle%20flow/Main%20turn%20life%20cycle.md#turn-end-phase): Refers to the special phase that happens after the player and enemy phases where the main turn is advanced and finished
- `phase`: Refers to any of the 3 phases
- [main turn](Battle%20flow/Main%20turn%20life%20cycle.md): Refers to the processing of all 3 phases as a unit which starts on the player phase and ends after the turn end phase. More details about a main turn's lifecycle in its documentation
- `actor turn`: Refers to an individual's actor's concept of turn which includes their actions and ends with its turn advancement including their `cantmove` change. The actor turn is consumed by [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) for player party members (with additional processing in [EndPlayerTurn](Battle%20flow/EndPlayerTurn.md)) or [EndEnemyTurn](Battle%20flow/EndEnemyTurn.md) for enemy party members and it is advanced to the next one by [AdvanceTurnEntity](Battle%20flow/AdvanceTurnEntity.md)
## Execution flow
There is only one way to start a battle: starting a [StartBattle](StartBattle.md) coroutine. This will perform a wide variety of setup and fields initialisation to start the battle from a fresh state. This will not be recalled unless a [Retry](Battle%20flow/Retry.md) occur which is the opt-in ability to recreate the battle from the existing one, but preserving the [StartUpData](StartUpData.md). The caller is able to further configure the battle as needed either by setting battle.`haltbattleload` to true to make the coroutine stop early or by yielding on battle.`halfload` to wait the coroutine stops later on on the caller side and configure it that way.
After the battle is fully started (which may include enemy actions if they got the advantage), [Update](Battle%20flow/Update.md) takes over. From there, its flow can be in one of 3 states from now on:
- [Controlled flow](Battle%20flow/Update%20flows/Controlled%20flow.md) (the one the battle starts at after StartBattle is done)
- [Uncontrolled flow](Battle%20flow/Update%20flows/Uncontrolled%20flow.md) (delegates the control of the battle to another method or coroutine)
- [Terminal flow](Battle%20flow/Update%20flows/Terminal%20flow.md) (relegates control almost completely when the battle is about to end such that it can end or be retried properly)
The key point to understand how a battle flows is the first 2 flows are constantly toggled with each other. Update is the main dispatcher that runs by default, but it's only making sure the usual flow is respected. Most of the heavy lifting is done by a coroutine or a method taking control.
### Action coroutines
Whenever something complex needs to happen such as an attack, battle.`action` (or battle.`inevent`) is set to true which switches to an uncontrolled flow as the coroutine or method takes most control away from Update. Update has very reduced logic during this, notably handling [blocking](Battle%20flow/GetBlock.md) during the enemy phase. Eventually, the procedure gets done so battle.`action` (or `inevent`) gets set back to false switching to a controlled flow. A coroutine which sets battle.`action` to true is refered to as an action coroutine.
Here are all the action coroutines defined in the battle system:
- [Tattle](Battle%20flow/Action%20coroutines/Tattle.md)
- [SwitchParty](Battle%20flow/Action%20coroutines/SwitchParty.md)
- [SwitchPos](Battle%20flow/Action%20coroutines/SwitchPos.md)
- [Relay](Battle%20flow/Action%20coroutines/Relay.md)
- [UseItem](Battle%20flow/Action%20coroutines/UseItem.md)
- [DoAction](Battle%20flow/Action%20coroutines/DoAction.md)
- [CheckDead](Battle%20flow/Action%20coroutines/CheckDead.md)
- [Chompy](Battle%20flow/Action%20coroutines/Chompy.md)
- [AIAttack](Battle%20flow/Action%20coroutines/AIAttack.md)
- [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)
- [TryFlee](Battle%20flow/Action%20coroutines/TryFlee.md)
[DoNothing](Player%20UI/ItemList%20confirmation%20handling/Battle%20strategy%20list%20type.md#2-do-nothing) is notably NOT an action coroutine because it is handled directly in place during player UI handling.
The interesting point these have in common is with the exception of doing nothing from a player party member, these represents all actions that can possibly be taken by an actor. Notably, [DoAction](Battle%20flow/Action%20coroutines/DoAction.md) covers every single attacks in the entire game from every actor. This is why BattleControl can be caracterised as a coroutine driven system: while it does have an Update, it only acts as a dispatcher for the coroutines mentioned above.
### Battle events
Separatly from this, but still features an uncontrolled flow is [EventDialogue](Battle%20flow/EventDialogue.md) which is a coroutine that processes some kind of events or cutscenes. The only difference with an action coroutine is instead of setting battle.`action` to true, it sets battle.`inevent` to true instead, but it has similar effects. These are triggered on specific conditions and behave very similarily to [events](../Enums%20and%20IDs/Events.md), but are specialised to handle the ongoing battle.
### Terminal coroutines
A terminal flow is reserved for cases where the battle will end for sure in some ways and it features battle.`cancelupdate` or instance.`inbattle` being set to false. It features almost no control from Update and instead, the terminal coroutine controls the battle completely. This is done both for retries, losses and wins.
Here are all the terminal coroutines:
- [GameOver](Battle%20flow/Terminal%20coroutines/GameOver.md)
- [ReturnToOverworld](Battle%20flow/Terminal%20coroutines/ReturnToOverworld.md)
- [DeadParty](Battle%20flow/Terminal%20coroutines/DeadParty.md) (this one is a wrapper to GameOver and ReturnToOverworld)
- [AddExperience](Battle%20flow/Terminal%20coroutines/AddExperience.md)
They act similarly to action coroutines, but with even more control which is needed to properly end the battle or retry it.
Additionally, there are also wrapper methods available that will call some of the above and also change to a terminal flow:
- [EndBattleWon](Battle%20flow/Terminal%20wrappers/EndBattleWon.md) (wraps AddExperience)
- [ExitBattle](Battle%20flow/Terminal%20wrappers/ExitBattle.md) (wraps ReturnToOverWorld, part of AddExperience)
## Main turn flow
As this is a turn based battle system, it has a concept of turns. A main turn is composed of 3 phases executed in order:
- [Player phase](Battle%20flow/Main%20turn%20life%20cycle.md#player-phase)
- [Enemy phase](Battle%20flow/Main%20turn%20life%20cycle.md#enemies-phase)
- [Turn end phase](Battle%20flow/Main%20turn%20life%20cycle.md#turn-end-phase)
The player phase is the most involved mainly handling UI naviguations on top of player actions. It is only active when battle,`enemy` is false.
The enemy phase mostly involves each enemies doing their action when `enemy` is true and [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) being the whole procedure that advances the main turn and allows a fresh one to start again.
Each actor also have their own concept of turns called actor turn. An actor turn is composed of their action and other advancement logic such as the `cantmove` advance. `cantmove` is a multi purpose actor turn counter that serves as the way for the game to track that an actor can act, needs to wait before being able to, or has multiple actions available. The actor turn advancement notably includes logic associated with the [conditions](Actors%20states/Conditions.md) currently inflicted on the actor among other details.
When all the actor turns available are consumed, the actor needs to wait their actor turn gets advanced which is done by [AdvanceTurnEntity](Battle%20flow/AdvanceTurnEntity.md) and it is only called as part of [AdvanceMainTurn](Battle%20flow/Action%20coroutines/AdvanceMainTurn.md) during the turn end phase.
### hitactions
There is a notable exception to this flow: an enemy is able to do what's known as a [hitaction](Actors%20states/Enemy%20features.md#hitaction). A hitaction occurs when the field of the same name on the enemy party member is true which causes the next Update cycle to process a temporary DoAction call on the enemy while placing `enemy` to true. Check the documentation for more information on this feature.
## Damage pipeline
During the course of the battle, damages might be processed for various reasons such as attacks or using an item. These damages are processed by the damage pipeline which has a single entry point: [DoDamage](Damage%20pipeline/DoDamage.md). This method takes in a target, an optional attacker belonging to the opposte party of the target (it is possible to have damages comes from no actor, but friendly fire attacks aren't possible) and a base amount to inflict. This amount may change for various reasons as part of the damage calculation logic which is held in [CalculateBaseDamage](Damage%20pipeline/CalculateBaseDamage.md).
The damage might have more effects processed after its calculation for example, by applying some [medals](../Enums%20and%20IDs/Medal.md) that act on it. It is greatly influenced by the property parameter and the enemy party members's [weakness](Actors%20states/Enemy%20features.md#weakness) field, a list of [AttackProperty](Damage%20pipeline/AttackProperty.md) that applies to this enemy party member.
It should be noted however that the caller of DoDamage is free to perform any logic that goes beyond the scope of the damage pipeline which happens very frequently in actions's logic.
## Actor state
The player party's stats are in instance.`playerdata` (which the whole game uses elsewhere in various places) while the enemy party's are specifically inside BattleControl and is called `enemydata`. The `playerdata` array has complex addressing methods, more info can be found at the [`playerdata` addressing documentation](playerdata%20addressing.md)
They are both the same type: a struct called [BattleData](Actors%20states/BattleData.md) which means some fields have different meanings depending if it's a player party member or an enemy party member and some fields are only relevant for one of the 2.
More details on the fields can be consulted in the [BattleData](Actors%20states/BattleData.md) documentation.
## Other Unity events
Besides Update, this component has a [LateUpdate](Visual%20rendering/LateUpdate.md) and a [FixedUpdate](Visual%20rendering/FixedUpdate.md), but they only update UI informations visually and are therefore much more minor in terms of importance.

View File

@@ -0,0 +1,39 @@
# AttackProperty
An AttackProperty is a parameter of [DoDamage](DoDamage.md) and they are also the elements allowed in the [weakness](../Actors%20states/Enemy%20features.md#weakness) field of [BattleData](../Actors%20states/BattleData.md) (meant for enemy party members only). They influence the damage pipeline in various ways either at the specific call level when passed as a parameter to DoDamage or at the target level for an enemy party member's `weakness`. They mainly influence [CalculateBaseDamage](CalculateBaseDamage.md)'s logic.
They are not to be confused with [DamageOverride](DamageOverride.md) which can only be sent to DoDamage as an array of them and have very different logic changes.
Here are the different AttackProperty, how they are meant to be passed to the damage pipeline and a summary of their effects.
|Value|Name|DoDamage parameter?|`weakness`?|Description|
|-----:|----|-------------------|-----------|-----------|
|0|Pierce|Yes|No|Ignores all calculations related to defense in CalculateBaseDamage. Only valid for enemy party member targets that do not have `AntiPierce` in their `weakness`|
|1|Flip|Yes|Yes|When used as a DoDamage parameter, 1 point of defense in CalculateBaseDamage will be ignored when the target doesn't have the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition (this is done incorrectly, see the CalculateBaseDamage documentation to learn more). It will also attempt to inflict the `Flipped` condition if the target has this property in its `weakness` and some other conditions are fufilled. It will also bypass [defenseonhit](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) and prevent `isdefending` from being set to true (it can even break the guard)|
|2|Freeze|Yes|No|Attempts to inflict the [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition during CalculateBaseDamage|
|3|Poison|Yes|No|Attempts to inflict the [Poison](../Actors%20states/BattleCondition/Poison.md) condition during CalculateBaseDamage|
|4|Numb|Yes|No|Attempts to inflict the [Numb](../Actors%20states/BattleCondition/Numb.md) condition during CalculateBaseDamage|
|5|Sleep|Yes|No|Attempts to inflict the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition during CalculateBaseDamage|
|6|AntiPierce|No|Yes|Prevents the `Pierce` property to have any effect during CalculateBaseDamage (only the `Spuder` [enemy](../../Enums%20and%20IDs/Enemies.md) can get it via [CheckEvent](../Battle%20flow/Update.md) when applicable)|
|7|ToppleFirst|No|Yes|The enemy party member will receive the [Topple](../Actors%20states/BattleCondition/Topple.md) condition when it is damaged first before falling or getting the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition during CalculateBaseDamage. It acts as defensive mechanism to enemy party members where they would have fell or flipped immediately if they didn't feature this `weakness`|
|8|Magic|Yes|Yes|When used an enemy party member's `weakness`, it will allow a magic weakness to be processed in CalculateBaseDamage when property is also `Magic` or when the attacker is a player party member while `lastskill` is `Icefall`, `FrigidCoffin` or `IceRain` [skill](../../Enums%20and%20IDs/Skills.md) alongside some other conditions|
|9|ToppleAirOnly|No|Yes|The same as `ToppleFirst`, but only applicable when the enemy party member's [position](../Actors%20states/BattlePosition.md) is `Flying`|
|10|Atleast1|Yes|No|Clamps the damage amount from 1 towards the end of CalculateBaseDamage unless the target has `LimitX10` in its `weakness` where 10 is subtracted from the amount instead|
|11|Atleast1pierce|Yes|No|Combines the effects of `Pierce` and `Atleast1`|
|12|LimitX10|No|Yes|Gives ? defense logic to the enemy party member which CalculateBaseDamage processes towards the end where the amount is first subtracted by 10 if property is `Atleast1` or `Atleast1pierce` and then set to 0 if it was <= 1 or divided by 10 ceiled if it was above 1|
|13|NoExceptions|Yes|No|Ignores many, but not all logic in CalculateBaseDamage. If the target is invulnerable according to DoDamage, the damage dealt will be the ammount sent|
|14|None|Yes|No|No property applies, the same as sending null. DoDamage will override this to null when passing it to CalculateBaseDamage|
|15|HornExtraDamage|No|Yes|Process a +1 damage bonus when dealing damages to the enemy party member if property is `Flip` with weaknesshit|
|16|MinusMagic|No|No|UNUSED|
|17|DieInOneHit|No|Yes|The enemy party member's `hp` is set to 0 on DoDamage, killing him in one hit|
|18|SurviveWith10|No|Yes|The final target's `hp` is clamped from 10 except if `lastskill` is 9 (`PeebleToss`) [skill](../../Enums%20and%20IDs/Skills.md)|
|19|FlyOnFlip|No|Yes|The enemy party member's [position](../Actors%20states/BattlePosition.md) is changed to `Flying` if the property of the attack is `Flip` and the enemy party member's `position` was `Ground`|
|20|Fire|Yes|No|Attempts to inflict the [Fire](../Actors%20states/BattleCondition/Fire.md) condition during CalculateBaseDamage|
|21|MultiHitDefense|No|No|UNUSED|
|22|DefDownOnBlock|Yes|No|Inflicts the [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) condition on the target when they are still alive and don't have the [Shield](../Actors%20states/BattleCondition/Shield.md) condition|
|23|DefDownOnFlyHard|No|Yes|Grant a +1 damage bonus if the target's [position](../Actors%20states/BattlePosition.md) is `Flying` and [HardMode](HardMode.md) returns true (This is specific to a `VenusBoss` [enemy](../../Enums%20and%20IDs/Enemies.md#enemies))|
|24|Ink|Yes|No|Attempts to inflict the [Inked](../Actors%20states/BattleCondition/Inked.md) condition during CalculateBaseDamage|
|25|AtkDownOnBlock|Yes|No|Inflicts the [AttackDown](../Actors%20states/BattleCondition/AttackDown.md) condition on the target when they are still alive and don't have the [Shield](../Actors%20states/BattleCondition/Shield.md) condition|
|26|Sticky|Yes|No|Attempts to inflict the [Sticky](../Actors%20states/BattleCondition/Sticky.md) condition during CalculateBaseDamage|
|27|InkOnBlock|Yes|No|The same then `Ink`, but the infliction can still occur even if the player sucessfully blocked|
|28|AlwaysSurvive|No|Yes|The final target's `hp` is clamped from 1|
|29|Numb1Turn|Yes|No|The same as `Numb`, but the infliction is always for 1 turn regardless if it's a `chompyaction` or not|

View File

@@ -0,0 +1,268 @@
# CalculateBaseDamage
This is a method that contains all the damage calculation logic and returns the final amount calculated from the base one given the battle's state. Every damages that goes through the damage pipeline ends up calling this to get the final amount of damage to deal with the exception of the target being invulnerable which are any of the following conditions on the target:
- Its `plating` is true
- It has the [Shield](../Actors%20states/BattleCondition/Shield.md) condition
- It is a player party member with the [Numb](../Actors%20states/BattleCondition/Numb.md) condition and the `ShockTrooper` [medal](../../Enums%20and%20IDs/Medal.md) equipped
There is no other damage calculation logic in the pipeline with the only exception being the clamping done on [DoDamage](DoDamage.md) after getting the final number. Every other logic involves other matters after the damage has been calculated by this method. Alternatively, actions's logic can perform anything outside of this pipeline.
```cs
private int CalculateBaseDamage(MainManager.BattleData? attacker, ref MainManager.BattleData target, int basevalue, bool block, AttackProperty? property, ref bool weaknesshit, ref bool superguarded, DamageOverride[] overrides)
```
## Parameters
All parameters comes directly from [DoDamage](DoDamage.md) (the damageammount becomes the basevalue) with some exceptions:
- `block`: This may be overriden to false by DoDamage If any of the following are true:
- The target has the [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition
- The target has the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition
- The target has the [Numb](../Actors%20states/BattleCondition/Numb.md) condition
- The target is a player party member with the `Berserker` [medal](../../Enums%20and%20IDs/Medal.md) equipped
- This is a non super block while [flags](../../Flags%20arrays/flags.md) 15 and 615 are true (chapter 1 started after the combat tutorial while FRAMEONE is active) and `overridechallengeblock` is false
- ref `weaknesshit`: This is meant to initially contain false, the method will set this to true if a `Magic` or `Flip` weakness was processed
- ref `superguarded`: This is meant to initially contain false, the method will set this to true if the player sucessfully super blocked
- `property`: The [property](AttackProperty.md) of the attack sent by DoDamage (overriden to null is if it was `None` by DoDamage). If this is `Pierce` or `Flip` while the `target` is a player party member, it is overriden to null at the start of this method which invalidates it
## Damage flow
While the attacker is optional (null means no attacker), the target is mandatory. Additionally, the target cannot be part of the same party as the attacker. This means an enemy party member cannot attack another enemy party member and a player party member cannot attack another player party member. This results in the following damage flows available:
- No attacker to player party member
- No attacker to enemy party member
- Player party member to enemy party member
- Enemy party member to player party member
Each have different implications on the calculations. It is assumed that the target is a player party member if it has the `Player` tag. Otherwise, it is assumed to be an enemy party member. If the attacker exists, it is assumed to be the opposite party of the target.
basevalue is the damage amount that will ultimately be returned. This method may modify it for various reasons until it reaches the end where it becomes final.
## Piercing
There is a concept of piercing which ignores all effects related to enemy party members's defense. Despite the concept of defense having multiple calculation errors, piercing correctly and exhaustively ignores all components of defense.
In order for piercing to apply, the following must all be true:
- The target is an enemy party member (this is specifically disabled for player party members)
- The target doesn't have `AntiPierce` in its [weakness](../Actors%20states/Enemy%20features.md#weakness) (only the `Spuder` [enemy](../../Enums%20and%20IDs/Enemies.md) can get it via [CheckEvent](../Battle%20flow/Update.md) when applicable)
- property is `Atleast1pierce` or `Pierce` (the former is the same as the latter, but the final clamp will be from 1 instead of 0 for any cases not counting a `FrostBite` [medal](../../Enums%20and%20IDs/Medal.md) counter)
If the above isn't fufilled, piercing doesn't apply.
## Calculation pipeline table
The calculation pipeline is very complex and most of it will be illustrated by a table.
Each rows of the table contains an effect to basevalue or other additional effects when applicable. Each row contains 3 columns:
- Attack direction: The damage flow denoted in party to party notation. Here's the party defintions:
- Any: For the attacker, it may or may not exist from either party. For the target, it can belong to either party
- Attacker: The attacker must exist, but can be in either party
- Player: The attacker or target must be a player party member
- Enemy: The attacker or target must be an enemy player member
- Condition: The conditions required for this effect to process. If a list is presented, all conditions must be true unless stated otherwise
- Damage effect: The effects on basevalue if Condition is true. This may contain other effects than changing basevalue. Anything underlined means it's an effect other than increasing or decreasing meaning it's more significant and its position in the calculation is important
These effects are shown in the exact order they appear.
|Attack direction|Condition|Damage effect|
|----------------|---------|-------------|
|Enemy to player|Attacker is a `TANGYBUG` [enemy](../../Enums%20and%20IDs/Enemies.md)|+ 2|
|Attacker to Any|Always processed|- attacker.`tired`|
|Player to enemy|<ul><li>Not in `demomode`</li><li>attacker is `partypointer[0]` (at the front of formation)</li></ul>|+ 1|
|Player to enemy|<ul><li>Not in `demomode`</li><li>attacker has the [Poison](../Actors%20states/BattleCondition/Poison.md) condition</li></ul>|+ amount of attacker's `PoisonAttacker` [medals](../../Enums%20and%20IDs/Medal.md)|
|Player to enemy|<ul><li>Not in `demomode`</li><li>attacker.`hp` <= 4</li></ul>|+ amount of attacker's `AttackUp` [medals](../../Enums%20and%20IDs/Medal.md)|
|Enemy to player|<ul><li>Not in `demomode`</li><li>[flags](../../Flags%20arrays/flags.md) 614 and 88 are true (HARDEST is active after chapter 2 ended)</li></ul>|+ 1|
|Enemy to player|Not in `demomode`|+ attacker.`hardatk` (the scaled attack from [GetEnemyData](../../TextAsset%20Data/Enemies%20data.md#getenemydata))|
|Enemy to player|<ul><li>Not in `demomode`</li><li>`DoublePainReal` [medal](../../Enums%20and%20IDs/Medal.md) is equipped</li></ul>|<u>Clamped from 2 to 99</u>|
|Attacker to any|Always processed|+ attacker.`charge`|
|Any to player|block is true OR `superblockedthisframe` hasn't expired yet|Decreased by:<ul><li>1 if it's a non super block</li></li><li>2 + amount of attacker's `SuperBlock` [medals](../../Enums%20and%20IDs/Medal.md) if it's a super block<sup>1</sup></li></ul>|
|Enemy to player|<ul><li>Target has [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition</li><li>No `NoIceBreak` override AND (first that applies of the 3 below)</li></ul>|Ice thaw<sup>2</sup> (after the sub effect is processed, doesn't change basevalue)|
|-|<ul><li>target has a `FrostBite` [medal](../../Enums%20and%20IDs/Medal.md)</li><li>`nonphysical` is false</li><li>attacker.[position](../Actors%20states/BattlePosition.md) isn't `Underground`</li></ul>|A [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition is added as a [delayed condition](../Actors%20states/Delayed%20condition.md) to the attacker AND a counter of the full damage to the attacker is scheduled (see the final results explanation below for details)</sup>|
|-|<ul><li>target has a `FrostBite` [medal](../../Enums%20and%20IDs/Medal.md)</li><li>The counter effect above didn't apply</li></ul>|<u>Divided by 2 floored</u>|
|-|target has no `FrostBite` [medal](../../Enums%20and%20IDs/Medal.md)|+ 1|
|Any to Any|<ul><li>target has the [Numb](../Actors%20states/BattleCondition/Numb.md) condition</li><li>target doesn't have the the [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) condition. NOTE: this is incorrect<sup>5</sup></li><li>property isn't `Flip`. NOTE: This is incorrect<sup>7</sup></li><li>there is no `IgnoreNumb` in the overrides</li><li>piercing doesn't apply</li></ul>|- 1|
|Any to enemy|<ul><li>target.`noexpatstat` is true (cannot happen because this field is UNUSED)</li><li>[flags](../../Flags%20arrays/flags.md) 162 is false (we aren't using the B.O.S.S system and we aren't in a Cave Of Trials session)</li></ul>|- 1 (this effect never happens under normal gameplay)|
|Any to Any|property is one of the following:<ul><li>`Poison`</li><li>`Numb`</li><li>`Numb1Turn`</li><li>`Sleep`</li><li>`Freeze`</li><li>`Fire`</li><li>`InkOnBlock`</li><li>`Ink`</li><li>`Sticky`</li></ul>|Status infliction logic occurs (see the section below for details), no changes to basevalue|
|Any to Any|property is `Flip`|Flip handling logic (see the section below for details), basevalue may change in various ways|
|Any to Any|property is anything except:<ul><li>`NoExceptions` OR</li><li>`Flip` while target doesn't have the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition. NOTE: If the enemy has [defenseonhit](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) above 0, this is incorrect<sup>7</sup></li></ul>|DefaultDamageCalc (see the section below for details) is called with the corresponding values for the parameters where pierce is true if piercing applies (false otherwise or if property is null), with def being target.`def`. basevalue may decrease due to various defense modifiers|
|Any to Any|<ul><li>target has `Magic` in its [weakness](../Actors%20states/Enemy%20features.md#weakness) AND</li><li>property is `Magic` OR</li> <ul><li>attacker is a player party member while `lastskill` is `Icefall`, `FrigidCoffin` or `IceRain` [skill](../../Enums%20and%20IDs/Skills.md) AND</li><li>property is one of the following:</li><ul><li>`Poison`</li><li>`Numb`</li><li>`Numb1Turn`</li><li>`Sleep`</li><li>`Freeze`</li><li>`Fire`</li><li>`InkOnBlock`</li><li>`Ink`</li><li>`Sticky`</li><li>`Flip` while target doesn't have the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition</li><li>`NoExceptions`</li></ul></ul></ul>|+ 1 and If `commandsuccess` is true (the player suceeded the action command), weaknesshit is set to true|
|Any to enemy|<ul><li>target.battleentity.`height` is above 0.0</li><li>target.[cantfall](../Actors%20states/Enemy%20features.md#cantfall) is false</li><li>target.[position](../Actors%20states/BattlePosition.md) is `Flying`</li><li>target.`lockposition` is false</li><li>There are no `NoFall` overrides</li></ul> AND (first of the 2 applies)||
|-|<ul><li>target doesn't already have have the [Topple](../Actors%20states/BattleCondition/Topple.md) conditions</li><li>target doesn't have the [Sleep](../Actors%20states/BattleCondition/Sleep.md), [Freeze](../Actors%20states/BattleCondition/Freeze.md) or [Numb](../Actors%20states/BattleCondition/Numb.md) conditions</li><li>target has `ToppleFirst` or `ToppleAirOnly` in its [weakness](../Actors%20states/Enemy%20features.md#weakness) </li></ul>|The [Topple](../Actors%20states/BattleCondition/Topple.md) condition is added directly to target.`condition` array for 1 turn followed by target.battleentity.`basestate` set to 21 (`Woobly`)|
|-|The above didn't apply|The enemy falls<sup>3</sup> (no basevalue changes)|
|Any to Any|<ul><li>target has the [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) condition</li><li>Either property:<ul><li>is null OR</li><li>is not `Flip` (NOTE: this is incorrect<sup>7</sup>) or `NoExceptions` while piercing doesn't apply</li></ul></li></ul>|- 1|
|Any to Any|<ul><li>target has the [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) condition</li><li>piercing doesn't apply</li><li>property isn't `NoExceptions`.</li><li>At least one of the following is true:<ul><li>target.`def` is above 0. NOTE: If the property is `Flip`, this is incorrect if target.`def` is exactly 1<sup>8</sup></li><li>The [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) effect above was just processed. NOTE: This is incorrect<sup>5</sup></li><li>The target is a player party member while HardMode returns true. NOTE: This is inconsistent or incorrect<sup>6</sup></li></ul></li></ul>|+ 1|
|Attacker to any|<ul><li>Attacker has the [AttackUp](../Actors%20states/BattleCondition/AttackUp.md) condition</li><li>property isn't `NoExceptions`</li></ul>|+ 1|
|Attacker to any|<ul><li>Attacker has the [AttackDown](../Actors%20states/BattleCondition/AttackDown.md) condition</li><li>property isn't `NoExceptions`</li></ul>|- 1|
|Any to player|The `DoublePainReal` [medal](../../Enums%20and%20IDs/Medal.md) is equipped|<u>Multiplied by 1.25 floored</u>, then increased by 1|
|Player to enemy|<ul><li>Attacker has an `AntlionJaws` [medal](../../Enums%20and%20IDs/Medal.md)</li><li>`actionid` is 0 or below (this field is UNUSED so it's always 0)</li><li>[currentchoice](../Player%20UI/Actions.md) is `Attack`</li><li>Either the target has the [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) condition OR its target.`def` is above 0</li><li>Piercing doesn't apply</li></ul>|Decreased by the lowest between the amount of the attacker's `AntlionJaws` [medals](../../Enums%20and%20IDs/Medal.md) and the target's defense which is:<ul><li>target.`def` if it's above 0</li><li>1 if target.`def` is 0 AND it has the [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) condition</li><li>0 otherwise</li></ul>NOTE: This logic is incorrect<sup>4</sup>|
|Any to enemy|<ul><li>The target has `DefDownOnFlyHard` in its [weakness](../Actors%20states/Enemy%20features.md#weakness) (This is specific to a `VenusBoss` [enemy](../../Enums%20and%20IDs/Enemies.md))</li><li>target.[position](../Actors%20states/BattlePosition.md) is `Flying`</li><li>[HardMode](HardMode.md) returns true</li></ul>|+ 1|
|Any to Any|target has the [Sturdy](../Actors%20states/BattleCondition/Sturdy.md) condition|- 3|
|Any to player|target has a [Reflection](../Actors%20states/BattleCondition/Reflection.md) condition|- amount of target's `Reflection` [medals](../../Enums%20and%20IDs/Medal.md)|
|Any to Any|<ul><li>target doesn't have `LimitX10` in its [weakness](../Actors%20states/Enemy%20features.md#weakness)</li><li>property is `Atleast1` or `Atleast1pierce`</li></ul>|<u>Clamped from 1 to 99</u>|
|Any to Enemy|<ul><li>target has `LimitX10` in its [weakness](../Actors%20states/Enemy%20features.md#weakness)</li><li>property is `Atleast1` or `Atleast1pierce`</li></ul>|- 10|
|Any to Enemy|target has `LimitX10` in its [weakness](../Actors%20states/Enemy%20features.md#weakness)|<ul><li>If basevalue is <= 1, <u>basevalue is set to 0</u></li><li>Otheriwise, <u>basevalue is divided by 10 ceiled</u></li></ul>|
1: This always counts as a super block if `superblockedthisframe` hasn't expired yet. A super block also causes the following to happen:
- `superblockedthisframe` is reset to 3.0 frames
- superguarded is set to true
- block is overriden to true
For more information on how super blocks are determined, check [GetBlock](../Battle%20flow/GetBlock.md).
2: This is how ice thawing is done (this is done after the sub effect processed):
- [RemoveCondition](../Actors%20states/Conditions%20methods/RemoveCondition.md) is called with the target to remove the [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition
- [BreakIce](../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#breakice) is called on the target.battleentity
- target.`cantmove` is set to 0 if the target is an enemy party member or to 1 if it's a player party member. This allows for the actor to immediately be able to act no matter its party (the enemy party doesn't get their actor turns advanced until the next main turn while the player party have theirs advanced right after enemies).
3: This means the attack happened to a toppled flying enemy or the enemy wasn't topplable and was hit while flying meaning it should be dropped to the ground. This is how this happens:
- [RemoveCondition](../Actors%20states/Conditions%20methods/RemoveCondition.md) is called with the target to remove its [Topple](../Actors%20states/BattleCondition/Topple.md) condition
- target.battleentity.`bobrange` and `bobspeed` are set to 0.0
- If target.`animid` (the [enemy](../../Enums%20and%20IDs/Enemies.md) id) isn't 208, target.battleentity.`basestate` is set to 0 (`Idle`). NOTE: This [enemy](../../Enums%20and%20IDs/Enemies.md) id doesn't exist, the logic was supposed to check for target.battleentity.[animid](../../Enums%20and%20IDs/AnimIDs.md) for not being 207 (`CursedSkull`) which would have allowed it to to remain in its charge animation even when it falls
- If target.[eventonfall](../Actors%20states/Enemy%20features.md#eventonfall) is above -1 (it's defined):
- `calleventnext` is set to target.`eventonfall`
- target.battleentity.`basestate` is set to 11 (`Hurt`)
- Otherwise (target.[eventonfall](../Actors%20states/Enemy%20features.md#eventonfall) isn't defined):
- target.battleentity.`droproutine` is set to a new [Drop](../../Entities/EntityControl/EntityControl%20Methods.md#drop) call on target.battleentity
4: The `AntlionJaws` [medal](../../Enums%20and%20IDs/Medal.md) was supposed to ignore a defense for each instance equipped. However, there are 5 cases in which this doesn't work correctly:
- The [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) condition is ignored
- The defense gained as a result of the [Numb](../Actors%20states/BattleCondition/Numb.md) condition is ignored
- [defenseonhit](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) is ignored on enemies who supports it
- The [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) condition is ignored UNLESS target.`def` is 0 where it works correctly. Specifically, this means that if the target's target.`def` is 1 while having the [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) condition, at most 1 `AntLionJaws` will count still (even if 2 are equipped)
- The property is `Flip`. This will cause both the medal and the 1 defense ignore to apply independently for the same reasons, effectively ignoring the defense that was already ignored befrehand
5: This is incorrect to do because the [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) effect later can still apply which can make it override the numb defense giving +1 erroneous increase to basevalue. For this issue to reproduce, the `DefenseDown` conditions needs to be fufilled while the numb defense conditions also applies which will effectively count 1 less defense than it should. The defense in the HUD reports the correct number, but the calculations are wrong.
Additionally, if the target has all the [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md), [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) and [Numb](../Actors%20states/BattleCondition/Numb.md) conditions, now numb defense won't apply when the other 2 cancel each other resulting in numb defense not being applied when it should have been. This results in the same error.
6: There are 2 ways to look at this because the intent here is unclear:
- Negative defense on the player is allowed due to making it possible via [medals](../../Enums%20and%20IDs/Medal.md) and [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) always apply
- Negative defense shouldn't be allowed in general and medals causes a design issue
The second case is a design bug. The first case isn't consistent because the medals exists no matter if HardMode applies or not, but the [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) effect may or may not apply.
Additionally, this doesn't take into consideration the numb defense even if its logic was correct (that it would apply regardless of [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md)'s presence or not). It now means that the numb defense may or may not be cancelled correctly depending on the difficulty which is a bug.
7: `Flip` always ignore at most 1 of target.`def`, but it also ignores unconditionally other types of defenses on top of this incorrectly:
- [Numb](../Actors%20states/BattleCondition/Numb.md) defense
- [DefenseUp](../Actors%20states/BattleCondition/DefenseUp.md) condition
- [defenseonhit](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) on supported enemies when they are `isdefending`
They are also cumulative: if all 3 are combined, they all get ignored on top of the 1 defense ignored from target.`def` while only at most 1 was supposed to be ignored across all defenses.
8: This is the infamous issue known as the "def bug". If target.`def` is EXACTLY 1 (0 or 2+ are accidentally correct) while it has a [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) condition, the only defense left will be ignored, but [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) will still apply. Only one of the two should apply because there's only 1 defense available to ignore. [DefenseDown](../Actors%20states/BattleCondition/DefenseDown.md) only requires that target.`def` is above 0.
## Status infliction
What happens here depends on the property. These typically attempts to inflict a [condition](../Actors%20states/Conditions.md) on the target when applicable and most of them implies a resistance check.
Here's an explanation of the columns:
- property: The property value the row applies to
- [conditions](../Actors%20states/Conditions.md#conditions) inflicted: The condition to inflict if all the requirements are fufilled
- Requirements: The requirements that must be fufilled for the condition to be inflicted. All statuses requires block to be false and the target to not have the [Sturdy](../Actors%20states/BattleCondition/Sturdy.md) condition. Those checks are implied in this column and won't be mentioned. There are 2 requirements specifically that recurs a lot and will be called with a simplified name:
- Resistance check: A resistance check must pass for the condition to be inflicted. A resistance is an integer field on the target that can be at most 99 for the condition to possibly inflict. If it's 100 or above, the target is immune and the infliction won't occur. This immunity condition also affects if the `StatusMirror` [medal](../../Enums%20and%20IDs/Medal.md) works. This is how the test occurs:
- If this is a `chompyaction` or the attacker is a player party member with a `StatusBoost` [medal](../../Enums%20and%20IDs/Medal.md), the resistance used for the test is decreased by 15 (guaranteed to inflict if this subtraction makes the resistance land at 0 or below)
- A random number between 0 and 99 is generated and it must be higher or equal than the target's resistance for the test to pass. Intuitively, if the target isn't immune, it means the percentage to inflict is 100 - resistance with `StatusBoost` or a `chompyaction` giving 15% more chances (or a guarantee if the percent number is above 100)
- Requires !CanBeToppled?: CanBeToppled needs to return false with the target for the infliction to be allowed. For it to return false, at least one of the following must be true:
- The target has the [Topple](../Actors%20states/BattleCondition/Topple.md) conditions
- target.[position](../Actors%20states/BattlePosition.md) is `Flying` while having the [Sleep](../Actors%20states/BattleCondition/Sleep.md), [Freeze](../Actors%20states/BattleCondition/Freeze.md) or [Numb](../Actors%20states/BattleCondition/Numb.md) conditions
- The target doesn't have `ToppleFirst` or `ToppleAirOnly` in its [weakness](../Actors%20states/Enemy%20features.md#weakness) (if it has the latter, its [position](../Actors%20states/BattlePosition.md) must not be `Flying`)
- Resistance increase: After infliction, it's possible the resistance used with the resistance check gets increased. This column indicates if it will happen, under what conditions it will happen and for how much
- `StatusMirror` Infliction scheme: The `StatusMirror` [medal](../../Enums%20and%20IDs/Medal.md) scheme of infliction. This medal only works in an enemy to player attack direction and it requires the resistance used for the resistance check to be below 100 (not being immune). If these conditions are met upon inflictions, the attacker gets inflicted with the same condition. The scheme of the infliction may vary and this column tells how it's inflicted
- Other effects: Anything the infliction does other than inflicting the condition or giving it to the attacker due to `StatusMirror`. Please note that with the exception of the `Sleep` property, [RemoveCondition](../Actors%20states/Conditions%20methods/RemoveCondition.md) is called with the target to remove its [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition if one of the following is true:
- The target is an enemy party member. NOTE: This contradicts the requirements for [DoDamage](DoDamage.md) to do the same because it does not feature a clause for dealing damages above 0. This means that a an attack that does no damage, but still inflicts can remove [Sleep](../Actors%20states/BattleCondition/Sleep.md) without changing the `cantmove` which is different than if DoDamage removed it.
- The target is a player party member and it doesn't have a `HeavySleeper` [medal](../../Enums%20and%20IDs/Medal.md)
|property|[conditions](../Actors%20states/Conditions.md#conditions) inflicted|Requirements|Resistance increase|`StatusMirror` Infliction scheme|Other effects|
|----|------|-----|-----|-----|-----|
|`Poison`|[Poison](../Actors%20states/BattleCondition/Poison.md) for 2 turns|Pass a resistance check with target.`poisonres`|None|[SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called with the attacker to set the [Poison](../Actors%20states/BattleCondition/Poison.md) condition for 2 turns|The `Poison` sound is played if it wasn't playing already|
|`Numb` or `Numb1Turn`|[Numb](../Actors%20states/BattleCondition/Numb.md) for 2 turns (1 turn instead if it's a `chompyaction` or property is `Numb1Turn`)|<ul><li>Pass a resistance check with target.`numbres`</li><li>Requires !CanBeToppled</li></ul>|If target is an enemy party member, it is increased by 17. The increase is 22 instead if HardMode returns true|AddDelayedCondition is called with the attacker to add the [Numb](../Actors%20states/BattleCondition/Numb.md) as a [delayed condition](../Actors%20states/Delayed%20condition.md) to it|<ul><li>The `Numb` sound is played if it wasn't playing already</li><li>target.`isnumb` is set to true</li><li>If the target is an enemy party member and its `actimmobile` is false, target.`cantmove` is set to 1 (meaning 1 actor turn needs to pass before the target can act again). NOTE: This means a status cleansing action on an enemy party member will still have them loose their actor turn</li><li>If target.[position](../Actors%20states/BattlePosition.md) is `Ground` and its battleentity.`height` is above 0.05, target.battleentity.`droproutine` is set to a new [Drop](../../Entities/EntityControl/EntityControl%20Methods.md#drop) call on target.battleentity</li></ul>|
|`Sleep`|[Sleep](../Actors%20states/BattleCondition/Sleep.md) for 2 turns (3 turns instead if the target is a player party member while it already had a [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition<sup>2</sup>)|<ul><li>Pass a resistance check with target.`sleepres`</li><li>Requires !CanBeToppled</li></ul>|If the target is an enemy party member, target.`numbres` is increased by 9. The increase is 13 instead if HardMode returns true|AddDelayedCondition is called with the attacker to add the [Sleep](../Actors%20states/BattleCondition/Sleep.md) as a [delayed condition](../Actors%20states/Delayed%20condition.md) to it|<ul><li>The `Sleep` sound is played if it wasn't playing already</li><li>target.`isasleep` is set to true</li><li>If the target has the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition, target.battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is set to 25 (`SleepFallen`) and if it doesn't have it, it's set to 14 (`Sleep`)</li><li>If target.[position](../Actors%20states/BattlePosition.md) is `Ground` and its battleentity.`height` is above 0.05, target.battleentity.`droproutine` is set to a new [Drop](../../Entities/EntityControl/EntityControl%20Methods.md#drop) call on target.battleentity</li></ul>|
|`Freeze`|[Freeze](../Actors%20states/BattleCondition/Freeze.md) for 1 turn if the target is an enemy party member or 2 turns if it's a player party member|<ul><li>Pass a resistance check with target.`freezeres`</li><li>Requires !CanBeToppled</li></ul>|If the target is an enemy party member:<ul><li>If the corresponding [endata](../../TextAsset%20Data/Entity%20data.md#animid-data) of the target's `hasiceanim` is true and we are either at the `GiantLairFridgeInside` [map](../../Enums%20and%20IDs/Maps.md) or in any maps outside of the `GiantLair` [area](../../Enums%20and%20IDs/librarystuff/Areas.md), target.`freezeres` is increased by 70</li><li>Otherwise, if target.`frozenlastturn` is true, target.`freezeres` is increased by 25</li><li>Otherwise, target.`freezeres` is increased by 13. The increase is 18 instead if [HardMode](HardMode.md) returns true</li></ul>|AddDelayedCondition is called with the attacker to add the [Freeze](../Actors%20states/BattleCondition/Freeze.md) as a [delayed condition](../Actors%20states/Delayed%20condition.md) to it|<ul><li>[RemoveCondition](../Actors%20states/Conditions%20methods/RemoveCondition.md) is called with the target to remove the [Topple](../Actors%20states/BattleCondition/Topple.md) condition</li><li>If the corresponding [endata](../../TextAsset%20Data/Entity%20data.md#animid-data) of the target's `hasiceanim` is true and we are either at the `GiantLairFridgeInside` [map](../../Enums%20and%20IDs/Maps.md) or in any maps outside of the `GiantLair` [area](../../Enums%20and%20IDs/librarystuff/Areas.md):<ul><li>target.battleentity.`inice` is set to true</li><li>target.[weakness](../Actors%20states/Enemy%20features.md#weakness) is set to a new list with one element being `HornExtraDamage`</li></ul></li><li>[Freeze](../../Entities/EntityControl/Notable%20methods/Freeze%20handling.md#freeze) is called on target.battleentity</li><li>If target.[position](../Actors%20states/BattlePosition.md) is `Ground` and its battleentity.`height` is above 0.05, target.battleentity.`droproutine` is set to a new [Drop](../../Entities/EntityControl/EntityControl%20Methods.md#drop) call on target.battleentity</li></ul>|
|`Fire`|[Fire](../Actors%20states/BattleCondition/Fire.md) for 2 turns|CanBeOnFire must returns true<sup>1</sup>|None|[SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called with the attacker to set the [Fire](../Actors%20states/BattleCondition/Fire.md) condition for 2 turns|The `Flame` sound is played if it wasn't playing already|
|`Ink` or `InkOnBlock` (`InkOnBlock` doesn't have the block requirement)|[Inked](../Actors%20states/BattleCondition/Inked.md) for 3 turns when block is false (2 when block is true)|If the target has the `ResistAll` [medal](../../Enums%20and%20IDs/Medal.md) equipped, a 50% RNG test is performed and it must pass (not applicable if the target doesn't have it equipped)|None|[SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called with the attacker to set the [Inked](../Actors%20states/BattleCondition/Inked.md) condition for 2 turns|<ul><li>The `WaterSplash2` sound is played at 0.7 pitch if it wasn't playing already or it was while its time is higher than 0.25 seconds</li><li>The `InkGet` particles plays at the target.battleentity's position + Vector3.up</li></ul>|
|`Sticky`|[Sticky](../Actors%20states/BattleCondition/Sticky.md) for 3 turns when block is false (2 when block is true)|If the target has the `ResistAll` [medal](../../Enums%20and%20IDs/Medal.md) equipped, a 50% RNG test is performed and it must pass (not applicable if the target doesn't have it equipped)|None|[SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called with the attacker to set the [Sticky](../Actors%20states/BattleCondition/Sticky.md) condition for 2 turns|<ul><li>The `WaterSplash2` sound is played at 0.7 pitch if it wasn't playing already or it was while its time is higher than 0.25 seconds</li><li>The `StickyGet` particles plays at the target.battleentity's position + Vector3.up</li></ul>|
1: The method does the following to determine if the target can be on fire:
- If the target is a player party member, true is returned unless it has the `ResistAll` [medal](../../Enums%20and%20IDs/Medal.md) equipped and a 50% RNG test is failed where false is returned instead
- If it's a `WaspKing` or `EverlastingKing` [enemy](../../Enums%20and%20IDs/Enemies.md), true is returned if a 30% RNG test succeed, false otherwise
- If it's a `Krawler`, `Cape` or `CursedSkull` [enemy](../../Enums%20and%20IDs/Enemies.md) then it's false if the current [map](../../Enums%20and%20IDs/Maps.md) is any in the `GiantLair` [area](../../Enums%20and%20IDs/librarystuff/Areas.md) other than `GiantLairFridgeInside`. Otherwise, the return is decided with a 50% RNG test
- If it's a `KeyR`, `KeyL` or `Tablet` [enemy](../../Enums%20and%20IDs/Enemies.md), false is returned
- If none of the cases applies, true is returned
2: This is due to the first of those 3 turns ending immediately making it really + 2 turns in practice which matches all other cases where it's always + 2 turns.
## `Flip` handing
Each rows of the table contains an effect to basevalue or other additional effects when applicable. Each row contains 3 columns:
- target's party: The party of the target (any for either)
- Condition: The conditions required for this effect to process. If a list is presented, all conditions must be true unless stated otherwise
- Effects: The effects on basevalue if Condition is true. This may contain other effects than changing basevalue. Anything underlined means it's an effect other than increasing or decreasing meaning it's more significant and its position in the calculation is important
These effects are shown in the exact order they appear.
|target's party|Condition|Effects|
|--------------|---------|-------------|
|Any|target doesn't have the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition|basevalue is decreased by the clamp of target.`def` - 1 from 0 to 99|
|Any|<ul><li>target doesn't have the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition</li><li>target has `Flip` in its [weakness](../Actors%20states/Enemy%20features.md#weakness)</li></ul>|wealnesshit is set to true + the first of 3 applicable effects below (mutually exclusive)|
|-|target doesn't have `ToppleFirst` in its [weakness](../Actors%20states/Enemy%20features.md#weakness)|<ul><li>A [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition for 1 turn is added directly to target.`condition`</li><li><u>basevalue is clamped from 1 to 99</u></li></ul>|
|-|target has the [Topple](../Actors%20states/BattleCondition/Topple.md) condition|<ul><li>A [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition for 1 turn is added directly to target.`condition`</li><li><u>basevalue is clamped from 1 to 99</u></li><li>[RemoveCondition](../Actors%20states/Conditions%20methods/RemoveCondition.md) is called with the target to remove its [Topple](../Actors%20states/BattleCondition/Topple.md) condition</li></ul>|
|-|Neither of the above applied|<ul><li>If target.[position](../Actors%20states/BattlePosition.md) is `Ground`, target.battleentity.[animstate](../../Entities/EntityControl/Animations/animstate.md) is set to 21 (`Woobly`)</li><li>A [Topple](../Actors%20states/BattleCondition/Topple.md) condition for 1 turn is added directly to target.`condition`</li></ul>|
|Any|target has `HornExtraDamage` in its [weakness](../Actors%20states/Enemy%20features.md#weakness)|<ul><li>basevalue is incremented</li><li>weaknesshit is set to true</li></ul>|
|Enemy|Always occur|<ul><li>If target.[holditem](../Actors%20states/Enemy%20features.md#holditem-and-helditem) isn't -1 (it was holding an item), [DropItem](../Actors%20states/Enemy%20party%20members/DropItem.md) is called with the target and with additem</li><li>If target.[isdefending](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) is true, it is set to false</li></ul>|
## DefaultDamageCalc
This is a sub method to CalculateBaseDamage which only gets called for most property values (the exceptions being `NoExceptions` where it's never called and `Flip` where it may or may not be called).
It takes the basevalue as ref and despite its name, it only processes optional decreases of the basevalue due to defensive effects.
```cs
private void DefaultDamageCalc(MainManager.BattleData target, ref int basevalue, bool pierce, bool blocked, int def)
```
### Parameters:
- `target`: The target from CalculateBaseDamage
- ref `basevalue`: The basevalue from CalculateBaseDamage
- pierce: Whether defense pierce applies. This value is computed from CalculateBaseDamage, but overriden to false if `target` is a player party member
- `blocked`: UNUSED (this is block from CalculateBaseDamage, but it is never read in the method)
- `def`: target.`def` from CalculateBaseDamage. (NOTE: this is the base value, not the effective one). Overriden to 0 if `pierce` is true while `target` is an enemy party member
### Effects
Each rows of the table contains an effect to basevalue or other additional effects when applicable. Each row contains 3 columns:
- target's party: The party of the target (any for either)
- Condition: The conditions required for this effect to process. If a list is presented, all conditions must be true unless stated otherwise
- Damage effect: The effects on basevalue if Condition is true. This may contain other effects than changing basevalue. Anything underlined means it's an effect other than increasing or decreasing meaning it's more significant and its position in the calculation is important
These effects are shown in the exact order they appear.
|target's party|Condition|Damage effect|
|--------------|---------|-------------|
|Any|target doesn't have the [Flipped](../Actors%20states/BattleCondition/Flipped.md) condition|- def|
|Player|target has the [Poison](../Actors%20states/BattleCondition/Poison.md) condition|- (amount of target's `PoisonDefender` [medals](../../Enums%20and%20IDs/Medal.md) - amount of target's `ReversePoison` medals)|
|Player|target is `playerdata[battle.partypointer[playerdata.lenght - 1]]` (the furthest back in the player party formation)|- amount of target's `BackSupport` [medals](../../Enums%20and%20IDs/Medal.md)|
|Player|target is `playerdata[battle.partypointer[0]]` (the front in the player party formation)|- amount of target's `FrontSupport` [medals](../../Enums%20and%20IDs/Medal.md)|
|Player|target.`hp` is <= 4|- 2 * amount of target's `DefenseUp` [medals](../../Enums%20and%20IDs/Medal.md)|
|Player|<ul><li>target has the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition</li><li>target has a `HeavySleeper` [medal](../../Enums%20and%20IDs/Medal.md)</li></ul>|<u>Divided by 2 floored</u>|
|Any|<ul><li>target.[isdefending](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) is true</li><li>pierce is false</li></ul>|- target.[defenseonhit](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending)|
## Final steps and results
Before the method ends:
- `caninputcooldown` is set to 0.0
- `blockcooldown` is set to 0.0
The final result is determined by the following:
- If a `FrostBite` [medal](../../Enums%20and%20IDs/Medal.md) counter conditions were fufilled:
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 0 (damage) with the basevalue (which is now the final amount) as the ammount starting from the world [CenterPos](../Actors%20states/CenterPos.md) of attacker and ending at Vector3.Up. NOTE: this basevalue may be unclamped here which allows to show a negative number
- The attacker's `hp` is decreased by basevalue clamped from 1 to its `maxhp` (meaning this can't be lethal). NOTE: basevalue may be unclamped here which allows it to be negative and heal the attacker instead of dealing damage to it (the outer clamp is only clamping the final hp, NOT the number by which it is decreased)
- 0 is returned as the final damage value (this is because the calculations are overriden to deal no damages to the target, but they were dealt manually just now to the attacker)
- Otheriwse, if the attack direction is attacker to player while block is false, basevalue is clamped from 1 to 99
- Otherwise, basevalue is clamped from 0 to 99

View File

@@ -0,0 +1,30 @@
# DamageOverride
A DamageOverride is a way to modify some logic in the damage pipeline. Unlike [AttackProperty](AttackProperty.md), they can only be sent to [DoDamage](DoDamage.md) in a parameter, but that parameter takes an array meaning it is possible to send multiple DamageOverrides at once (some however are mutually exclusive against each other).
The order in which they are specified in the parameter matters as they are processed sequentially.
The vast majority are processed in DoDamage, but some are in [CalculateBaseDamage](CalculateBaseDamage.md) and they can influence the logic there.
|Value|Name|Description|
|-----:|----|-----------|
|0|LeftMovement|UNUSED|
|1|RightMovement|UNUSED|
|2|UpMovement|UNUSED|
|3|NoMovement|UNUSED|
|4|HurtStyle|UNUSED|
|5|HealStyle|UNUSED|
|6|TPStyle|UNUSED|
|7|MAXStyle|UNUSED|
|8|ShakeLonger|UNUSED|
|9|NoShake|UNUSED|
|10|ShowCombo|Calls [ShowComboMessage](../Visual%20rendering/ShowSuccessWord.md#showcombomessage) right after the damage amount has been calculated in DoDamage|
|11|NoSound|The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end of DoDamage will have nosound set to true. NOTE: this is ignored if `NoDamageAnim` or `BlockSoundOnly` is processed after|
|12|FailSound|The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end of DoDamage will have fail set to true. NOTE: this is ignored if `NoDamageAnim` is processed after|
|13|NoDamageAnim|There will not be a [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end of DoDamage. NOTE: processing this overrides any `NoSound`, `BlockSoundOnly`, `FailSound` and `FakeAnim` because the call won't happen|
|14|BlockSoundOnly|The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end of DoDamage will have nosound set to true if block is false. NOTE: this is ignored if `NoDamageAnim` or `NoSound` is processed after|
|15|NoCounter|There will not be a [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) call in DoDamage (this does not cover a `Frostbite` [medal](../../Enums%20and%20IDs/Medal.md) counter which is done in CalculateBaseDamage)|
|16|NoFall|Prevents an enemy party member from falling under any circumstances in CalculateBaseDamage if one is the target|
|17|NoIceBreak|Prevents an enemy party member from thawing out when they have the [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition under any circumstances in CalculateBaseDamage if one is the target|
|18|FakeAnim|The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end of DoDamage will have fakeanim set to true. NOTE: this is ignored if `NoDamageAnim` is processed after|
|19|DontAwake|Prevents the attack from removing the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition on the target during the course of DoDamage. NOTE: CalculateBaseDamage can still remove it when inflicting a different status, check its documentation to learn more|
|20|IgnoreNumb|Prevents the [Numb](../Actors%20states/BattleCondition/Numb.md) condition to have its defense apply during CalculateBaseDamage under any circumstances|

View File

@@ -0,0 +1,320 @@
# DoDamage
DoDamage is the entrypoint of the damage pipeline. Any damage must go through it in order to be properly calculated and processed with visual effects and counters.
## Entry point
There are 10 overloads, but all of them ends up at a particular one which is the following (it will be refered to as the final overload):
```cs
private int DoDamage(MainManager.BattleData? attacker, ref MainManager.BattleData target, int damageammount, AttackProperty? property, DamageOverride[] overrides, bool block)
```
It returns the amount of damage actually dealt.
Here are the parameters:
- `attacker`: The actor dealing the damage. If null, the damage didn't come from an attacker. If it exists, it must belong to the opposite party of the `target`
- ref `target`: The actor receiving the damage. Passed as ref to allow modifying the actor's data. If the `attacker` exists, it must belong to its opposite party
- `damageammount`: The base amount of damage to deal. This number can be heavilly changed by the damage pipeline, it is only the base one to deal
- `property`: The [property](AttackProperty.md) of the attack
- `overrides`: The [overrides](DamageOverride.md) to apply to the damage pipeline. May be null or an empty array to have no overrides
- `block`: For an enemy attack, whether or not the player sucessfully blocked it (this is intended to receive `commandsuccess` as it was determined by [GetBlock](../Battle%20flow/GetBlock.md#getblock)). It doesn't matter if it's a regular block or a super block, this parameter is to signal a block of any kind as the damage pipeline will process what to do with it
### General purpose overloads
The following are general purpose overloads which just ends up calling the final one leaving some parameters to default.
(1) Calls the final overload with null/false as the other parameters (no attacker, no property, no overrides and no block)
```cs
private int DoDamage(ref MainManager.BattleData target, int ammount)
```
(2) Calls the final overload with the other parameters being null (No attacker, no property and no overrides)
```cs
private int DoDamage(ref MainManager.BattleData target, int ammount, bool block)
```
(3) Calls the final overload with the parameters sent leaving overrides to an empty array and block to false
```cs
private int DoDamage(MainManager.BattleData? attacker, ref MainManager.BattleData target, int damageammount, AttackProperty? property)
```
(4) Calls (5) with the parameters sent leaving attacker to null (meaning no attacker and no overrides)
```cs
private int DoDamage(ref MainManager.BattleData target, int damage, AttackProperty? property)
```
(5) Calls the final overload with the parameters sent leaving overrides to an empty array
```cs
private int DoDamage(MainManager.BattleData? attacker, ref MainManager.BattleData target, int damageammount, AttackProperty? property, bool block)
```
### Enemy attack overloads
The following overloads are specifically made for an enemy party member attacking a player party member.
(6) Calls the final overload with the attacker being `enemydata[enemyid]`, the target being `playerdata[playertarget]`, overrides being null and the rest being the same as the parameters sent
```cs
private int DoDamage(int enemyid, int playertarget, int damage, AttackProperty? property, bool block)
```
(7) Calls the final overload with the attacker being `enemydata[enemyid]`, the target being `playerdata[playertarget]` and the rest being the same as the parameters sent
```cs
private int DoDamage(int enemyid, int playertarget, int damage, AttackProperty? property, DamageOverride[] overrides, bool block)
```
### Player attack overloads
The following overloads are specifically made for a player party member attacking an enemy party member.
(8) Calls (9) with the parameter sent and enemytarget being the BattleControl's `target`
```cs
private int DoDamage(int playerid, AttackProperty? property)
```
(9) Calls the final overload with the following:
- `attacker`: The player party member whose `trueid` is `playerid` (it will falback to the first player party member if none exists)
- `target`: The enemy party member in `availabletargets` whose index is `enemytarget`. An exception is thrown if no enemy party member exists at that index
- `damageammount`: The return of GetPlayerAttack for the `playerid` and `commandsuccess` which is the `atk` of the corresponding player party member if `commandsuccess` is true and if it's false, it's its `atk` clamped from -99 to 1
- `property`: The same as the parameter sent
- `overrides`: If `commandsuccess` is true, this is null and if it's false, it's an array with one element being `FailSound`
- `block`: false
```cs
private int DoDamage(int playerid, int enemytarget, AttackProperty? property)
```
## Procedure
The following is a high level overview of the damage pipeline divided by sections for each groups of effects that happens.
An actor is considered to be a player party member if its battleentity has the `Player` tag. It's assumed to be an enemy party member if it doesn't. If the attacker exists, its party is assumed to be the opposte of the target's.
### block override
There are ways that block can be overriden to false. Here are all of them (they aren't mutually exclusive, if any is true, block becomes false):
- The target has the [Freeze](../Actors%20states/BattleCondition/Freeze.md) condition
- The target has the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition
- The target has the [Numb](../Actors%20states/BattleCondition/Numb.md) condition
- The target is a player party member with the `Berserker` [medal](../../Enums%20and%20IDs/Medal.md) equipped
- This is a non super block while [flags](../../Flags%20arrays/flags.md) 15 and 615 are true (chapter 1 started after the combat tutorial while FRAMEONE is active) and `overridechallengeblock` is false
### Damage calculation
This is where the final damage amount is determined.
If the target isn't Invulnerable, the final damage amount is set to the return of [CalculateBaseDamage](CalculateBaseDamage.md) with all the parameters sent (with the overriden block if applicable and property to null if it was `None`). The weaknesshit and superguarded ref parameters are passed via locals initially set to false.
Otherwise (the target is invulnerable), it depends if the property is `NoException`:
- If it isn't, the amount is 0
- If it is, it's the original damageammount
The target is invulnerable if any of the following is true:
- Its `plating` is true
- It has the [Shield](../Actors%20states/BattleCondition/Shield.md) condition
- It is a player party member with the [Numb](../Actors%20states/BattleCondition/Numb.md) condition and the `ShockTrooper` [medal](../../Enums%20and%20IDs/Medal.md) equipped
### `plating` expiration
If the target doesn't have the [Shield](../Actors%20states/BattleCondition/Shield.md) condition, its `plating` is set to false. This allows the `plating` to not expire when hit while shielded.
### [DamageOverride](DamageOverride.md) application
8 of the 11 available `DamageOverride` are processed here if they are present in overrides. Each are processed in order they appear in the array. The other 3 were processed by [CalculateBaseDamage](CalculateBaseDamage.md) if it was called earlier:
#### `ShowCombo`
[ShowComboMessage](../Visual%20rendering/ShowSuccessWord.md#showcombomessage) is called with target.battleentity and block as block.
#### `NoSound`
The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end will have nosound set to true. NOTE: this is ignored if `NoDamageAnim` or `BlockSoundOnly` is processed after
#### `BlockSoundOnly`
The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end will have nosound set to true if block is false. NOTE: this is ignored if `NoDamageAnim` or `NoSound` is processed after
#### `FailSound`
The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end will have fail set to true. NOTE: this is ignored if `NoDamageAnim` is processed after
#### `NoDamageAnim`
There will not be a [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end of the method. NOTE: processing this overrides any `NoSound`, `BlockSoundOnly`, `FailSound` and `FakeAnim` because the call won't happen
#### `NoCounter`
There will not be a [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) call later
#### `FakeAnim`
The [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call towards the end will have fakeanim set to true. NOTE: this is ignored if `NoDamageAnim` is processed after
#### `DontAwake`
Prevents the attack from removing the `Sleep` [condition](../Actors%20states/Conditions.md) on the target later even if all conditions to do so are fufilled. This is only used as part of poison and fire damages from [AdvanceTurnEntity](../Battle%20flow/AdvanceTurnEntity.md).
### Player damage processing
This section only happens if the target is a player party member.
#### Block processing
This part is applicable in 2 cases:
- block is true (this is the standard reason to process the block)
- block was overriden to false due to [flags](../../Flags%20arrays/flags.md) 615 being true (FRAMEONE is active) while `commandsuccess` was true (meaning a non super block happened, but it didn't count due to FRAMEONE).
The second case is an edge case where the only thing that happens is `hasblocked` is set to true which is only used in HardSeedVenus meaning exceptionally, a `HardSeed` can be given with that attack with a non super block even if FRAMEONE is active.
The first case is the standard one:
- `hasblocked` is set to true (allows HardSeedVenus to give a `HardSeed` to the player if it gets called later as part of the enemy action)
- If this is a non super block, [ShowComboMessage](../Visual%20rendering/ShowSuccessWord.md#showcombomessage) is called with target.battleentity as the entity and true as the block
- Otherwise (meaning this was a super block):
- `combo` is set to 2
- The `AtkSuccess` sound is played at 1.1 pitch and 0.6 volume if it wasn't playing already (or it was, but its time was past 0.1 seconds)
- [ShowComboMessage](../Visual%20rendering/ShowSuccessWord.md#showcombomessage) is called with target.battleentity as the entity and false as the block
- If the `NeedlePincer` [medal](../../Enums%20and%20IDs/Medal.md) is equipped on the target and the target's battleentity still exists in `playerdata`, the target will get healed later due to the medal
#### `SpikeBod` [medal](../../Enums%20and%20IDs/Medal.md) processing
This part only happens if all of the following are true:
- The `SpikeBod` [medal](../../Enums%20and%20IDs/Medal.md) is equipped
- target.`trueid` is 1 (The target's [animid](../../Enums%20and%20IDs/AnimIDs.md) is `Beetle`)
- block is true
- `nonphysical` is false
- There is an attacker (assumed to be an enemy party member)
In that case, the attacker will get damaged which goes like the following:
- The `Damage0` sound is played with 0.8 pitch and 0.5 volume
- The `hp` of the enemy party member corresponding to the attacker is decreased by 1 + the amount of `SuperBlock` [medals](../../Enums%20and%20IDs/Medal.md) equipped on `Beetle` then clamped from 1 to its `maxhp` (this implies that this damage cannot be lethal)
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 0 (damage) with the amount of damage dealt just now starting from the attacker.battleentity's position + attacker.`cursoroffset` and ending to (0.0, 1.0, 1.0)
#### `PoisonTouch` [medal](../../Enums%20and%20IDs/Medal.md) processing
This part only happens if all of the following are true:
- The `PoisonTouch` [medal](../../Enums%20and%20IDs/Medal.md) is equipped on the target
- The target has the [Poison](../Actors%20states/BattleCondition/Poison.md) condition
- There is an attacker (assumed to be an enemy party member) and its `poisonres` is less than 100 (it's not immune to [poison](../Actors%20states/BattleCondition/Poison.md) inflictions)
- `nonphysical` is false
If all of the above are fufilled, [SetCondition](../Actors%20states/Conditions%20methods/SetCondition.md) is called to set the [Poison](../Actors%20states/BattleCondition/Poison.md) condition on the corresponding enemy party member of the attacker for 2 turns
#### `FavoriteOne` [medal](../../Enums%20and%20IDs/Medal.md) processing
This part only happens if the `FavoriteOne` [medal](../../Enums%20and%20IDs/Medal.md) is equipped on the target.
The only thing that happens is `attackedally` is set to target.`trueid`. This will only take into effect later during [AdvanceMainTurn](../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md).
#### ShakeGUI call
This part always happen as part of the player damage processing.
The only thing that happens here is a ShakeGUI coroutine is started to shake the corresponding `hud` element of the target.battleentity.[animid](../../Enums%20and%20IDs/AnimIDs.md) with a range of (0.1, 0.1, 0.0) for 15.0 frames. This coroutine will change the local position of the `hud`'s first chiled to be random between (0.0 - shake.x, 0.0 - shake.y) and (shake.x, shake.y) for the next 15.0 frames before being reset to Vector3.zero.
### Enemy damage processing
This section happens if the player damage processing didn't meaning the target is an enemy party member
#### [isdefending](../Actors%20states/Enemy%20features.md#isdefending) update
This part only happens if all of the following are true:
- target.[defenseonhit](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) is above 0
- The final amount of damage calculated is above 0
- property isn't `Flip`. NOTE: [CalculateBaseDamage](CalculateBaseDamage.md) can change `isdefending` when property is `Flip` so this is why it can't change here (damage calculation needs to ne able to override this logic hence why this check is done)
If all the above are fufilled, it means the enemy supports defending itself and it sustained damage which causes updates to its guarding state. When that happens, `isdefending` is set to false if the target [IsStopped](../Actors%20states/IsStopped.md) or to true if it's not.
#### [hitaction](../Actors%20states/Enemy%20features.md#hitaction) update
target.`hitaction` can change under 2 conditions (these aren't mutually exclusive, they are applied in order, but `hitaction` may not be set if neither apply):
- It's set to true if target.[defenseonhit](../Actors%20states/Enemy%20features.md#defenseonhit-and-isdefending) is -1 and its [position](../Actors%20states/BattlePosition.md) isn't `Underground`. This is only the case for an `Underling` [enemy](../../Enums%20and%20IDs/Enemies.md) under normal gameplay
- It's set to !`enemy` (false on the [enemy phase](../Battle%20flow/Main%20turn%20life%20cycle.md#enemy-phase) / [delproj](../Actors%20states/Delayed%20projectile.md#delayed-projectile) / enemy `firststrike` / enemy `hitaction`, true otherwise) if the target.[onhitaction](../Actors%20states/Enemy%20features.md#onhitaction) condition is fufilled which is:
- 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`
After, every other enemy party members other than the target who has the target.`animid` (its [enemy](../../Enums%20and%20IDs/Enemies.md) id) in their [chargeonotherenemy](../Actors%20states/Enemy%20features.md#chargeonotherenemy) has their `hitaction` set to !`enemy` (false on the [enemy phase](../Battle%20flow/Main%20turn%20life%20cycle.md#enemy-phase) / [delproj](../Actors%20states/Delayed%20projectile.md#delayed-projectile) / enemy `firststrike` / enemy `hitaction`, true otherwise).
#### Undigging
This part only happens if all of the following are true:
- The final amount of damages calculated earlier is higher than 0
- target.[position](../Actors%20states/BattlePosition.md) is `Underground`
- `mainturn` ([AdvanceMainTurn](../Battle%20flow/Action%20coroutines/AdvanceMainTurn.md)) isn't in progress
If the above conditions are fufilled, then UnDig is called with the target as ref which does the following on it:
- battleentity.`digging` is set to false
- battleentity.`overridejump` is set to true
- [Jump](../../Entities/EntityControl/EntityControl%20Methods.md#jump) is called on the battleentity with a height of 15.0
- [position](../Actors%20states/BattlePosition.md) is set to `Ground`
#### `turnsnodamage` reset
If the final amount of damages calculated earlier is higher than 0, target.`turnsnodamage` is set to -1.
### Player action command success
If `commandsuccess` is true and the attacker is a player party member:
- `wordroutine` is stopped if it was in progress (followed by the destruction of `commandword` if it was)
- `wordroutine` is set to a new [ShowSuccessWord](../Visual%20rendering/ShowSuccessWord.md) call with target.battleenetity as the t, without block and the super being the ref weaknessonhit value obtained from [CalculateBaseDamage](CalculateBaseDamage.md) done earlier (false if it wasn't called)
### target.`hp` decrease and clamping
target.`hp` gets decreased by the final amount of damage calculated earlier, but it also gets clamped after. The higher bound of the clamp is always target.`maxhp`, but the lower bound depends on some conditions.
Here they are in order (they are mutually exclusive, the first one applies):
#### Clamp from 10
This happens if all the following are true:
- The target is an enemy party member
- The target has a `SurviveWith10` weakness
- [currentaction](../Player%20UI/Pick.md) is `ItemList` (meaning this was an item use) or `lastskill` is not 9 (this attack came from any player [skills](../../Enums%20and%20IDs/Skills.md) other than `PeebleToss`)
#### Clamp from 1
This happens if the target is an enemy party member with an `AlwaysSurvive` weakness.
#### Clamp from 0
This is the default clamp that happens if the other 2 didn't.
### Player selection cycle reset
If the target is a player party member with an `hp` of 0 (meaning it just died as a result of the attack), SetLastTurns is called which resets `lastturns` to a new aray with the length being the amount of free players - 1 and all elements being -1 (this resets the player selection cycle).
### Target waking up
This section only applies if all of the following is true:
- The target had the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition at the start of the method
- The property isn't `Sleep`
- target.`hp` is above 0
- The final damage amount calculated earlier is above 0. NOTE: [CalculateBaseDamage](CalculateBaseDamage.md) may override this if the property is one of the status infliction one (except `Flip`) and the infliction occured because this clause isn't part of the damage calculation. This means that if the amount is 0, but an infliction removing `Sleep` occured, the `cantmove` won't change which is a different logic than this method enforces
- There was no [DamageOverride](DamageOverride.md) of `DontAwake` processed earlier
- If the target is an player party member, the `HeavySleeper` [medal](../../Enums%20and%20IDs/Medal.md) must not be equipped
If all of the above are fufilled, the following happens:
- [RemoveCondition](../Actors%20states/Conditions%20methods/RemoveCondition.md) is called to remove the [Sleep](../Actors%20states/BattleCondition/Sleep.md) condition on the target
- target.`isasleep` is set to false
- target.`cantmove` is set to 1. NOTE: This is incorrect because it means for a player party member, that remaining actor turn will advance immeidately after the enemy phase so they get to act, but for an enemy party member, they loose their entire main turn because the actor turn won't advance after the player phase
- [UpdateAnim](../Visual%20rendering/UpdateAnim.md) is called with true as the onlyplayer
### `LifeSteal` processing
This section only happens if the attacker is a player party member with the `LifeSteal` [medal](../../Enums%20and%20IDs/Medal.md) equipped while `nolifesteal` is false.
If the above is fufilled, the following happens:
- The `Heal` sound is played
- The amount to heal is set to the final damage amount calculated earlier / 2.0 (or 4.0 if the `HPFunnel` [medal](../../Enums%20and%20IDs/Medal.md) is equipped on the attacker) then clamped from 1.0 to 99.0 then floored
- The attacker's `hp` is increased by the amount just calculated clamped from 0 to the attacker's `maxhp`
- [ShowDamageCounter](../Visual%20rendering/ShowDamageCounter.md) is called with type 1 (HP) for the amount to heal calculated earlier (without `maxhp` clamp) starting from the attacker's battleentity's position + (0.0, 1.75, 0.0) and ending at (0.0, 3.0, 0.0)
- `nolifesteal` is set to true which prevents the medal from processing until the next [DoAction](../Battle%20flow/Action%20coroutines/DoAction.md) call
### Stat down on block properties processing
This section applies if the target.`hp` is above 0, the target doesn't have the `Shield` [condition](../Actors%20states/Conditions.md) and the property is `DefDownOnBlock` or `AtkDownOnBlock`.
This will call [StatusEffect](../Actors%20states/Conditions%20methods/StatusEffect.md) to give the target a [condition](../Actors%20states/Conditions.md) with visual effect. The amount of turn to inflict is 2 turns unless block is true where it's 1 turn instead. On top of this, it inflicts for one more turn if the target is a player party member (meaning 3 turns or 2 with block).
As for the actual condition, it's `DefenseDown` if the property is `DefDownOnBlock` and it's `AttackDown` if the property is `AtkDownOnBlock`.
### `NeedlePincer` [medal](../../Enums%20and%20IDs/Medal.md) processing
If a heal was requested earlier as a result of blocking as a player party member with a `NeedlePincer` [medal](../../Enums%20and%20IDs/Medal.md), this is where the [Heal](../Actors%20states/Heal.md) call happens with the target as the entity and the ammount being the amount of `NeedlePincer` equipped on the target.
### [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) call
Unless there was a `NoDamageAnim` damage override processed earlier, [DoDamageAnim](../Visual%20rendering/DoDamageAnim.md) is called with these parameters:
- entity: target
- damage: The final amount of damage calculated
- block: block
- noanim: true
- nosound, fail and fakeanim, they are false unless a damage override processed earlier decided otherwise
### Final processing
This section always happen at the end of the method:
- `combo` is incremented
- RefreshMusic is called which is an empty method
- `lastdamage` is set to the final amount of damage calculated earlier
- If the target is an enemy party member, `damagethisturn` is increased by the final amount of damage calculated earlier
- The final amount of damage calculated earlier is returned, ending the method

View File

@@ -0,0 +1,10 @@
# HardMode
This is a helper method that returns a boolean telling whether or not hard difficulty scaling should apply.
It's used primarily in the damage pipeline and in the actions logic to determine the scaling to use.
It only returns true if one of the following is true (false is returned otherwise):
- The `DoublePain` [medal](../../Enums%20and%20IDs/Medal.md) is equipped
- [flags](../../Flags%20arrays/flags.md) 614 is true (HARDEST is enabled)
- [flags](../../Flags%20arrays/flags.md) 166 is true (EX Mode is active when using the B.O.S.S system)

View File

@@ -0,0 +1,11 @@
# Actions
This enum describes the current sub interface the player selected or is in the process of configuring. The current one is stored in the `currentchoice` field. It can be thought as the sub interface to [Pick](Pick.md).
|Value|Name|Description|
|-----:|----|-----------|
|0|Attack|The player chose to use a basic attack|
|1|Skill|The player chose to use a [skill](../../Enums%20and%20IDs/Skills.md)|
|2|Item|The player chose to use an [item](../../Enums%20and%20IDs/Items.md)|
|3|Strategy|The player chose to use a strategy|
|4|Relay|The player chose to relay|
|5|Swap|The player chose the Swap option in the strategy menu|

View File

@@ -0,0 +1,12 @@
# AttackArea
This is a general purpose enum to specify the valid targets of anything.
|Value|Name|Description|
|-----:|----|-----------|
|0|SingleEnemy|Can target an enemy party member|
|1|AllEnemies|Can target the enemy party|
|2|SingleAlly|Can target a player party member|
|3|AllParty|Can target the player party|
|4|All|Can target all actors|
|5|None|No target|
|6|User|Can target the actor itself|

View File

@@ -0,0 +1,8 @@
# CancelList
This method is used to go back to the main vine action menu from an [ItemList](../../ItemList/ItemList.md) during a battle.
- `option` is set to `lastoption`
- `currentaction` is set to `BaseAction` (the main vine action menu)
- `turncooldown` is set to 5.0 (this prevents [GetChoiceInput](GetChoiceInput.md) calls during [PlayerTurn](../Battle%20flow/PlayerTurn.md) for 5 [FixedUpdate](../Visual%20rendering/FixedUpdate.md) cycles)
- [SetMaxOptions](SetMaxOptions.md) is called
- [UpdateText](../Visual%20rendering/UpdateText.md) is called

View File

@@ -0,0 +1,113 @@
# `BaseAction` ChoiceInput logic
This page details the logic of [GetChoiceInput](../GetChoiceInput.md) when [currentaction](../Pick.md) is `BaseAction`.
All of the logic present here involves handling inputs. The input isn't processed if `caninputcooldown` hasn't expired yet and nothing happens except decreasing the cooldown by MainManager.`framestep`.
## Input 7 (toggle HUD)
This input is handled specifically where pressing it will set `idletimer` to 250 when pressed which will show the `hexpcounter` without needing to wait 200 frames. Any other input will cause the `idletimer` to be set to 0 which resets the timer.
## Input 2 / 3 (left / right)
These inputs changes the `option` by one depending on the direction (decrement if right, increment if left with wrap around from 0 to `maxoptions` - 1).
Either input will have `caninputcooldown` set to 2.0 frames, a `Scroll` sound played on `sounds[10]` and [UpdateText](../../Visual%20rendering/UpdateText.md) being called.
## Input 5 (cancel)
This input is only processed if [GetFreePlayerAmmount](../../Actors%20states/Player%20party%20members/GetFreePlayerAmmount.md) returns more than 1 player being free to act.
- `caninputcooldown` is set to 2.0 frames
- The `Money` sound is player with a pitch of 1.0 + `currentturn` / 10.0 which shifts the pitch slightly using a rate that depends on the selected player that we are switching away from
- `lastoption` is set to `option`
- `currentturn` is set to -1 which unselects the player (the new one will be cycle on the next [player phase](../../Battle%20flow/Main%20turn%20life%20cycle.md#player-phase) update)
## Input 6 (switch party)
This input is only processed when AllPartyFree returns true (all `playerdata` have a `cantmove` of 0 or below) or GetAlivePlayerAmmount returns exactly 1 (there is only one player with an `hp` above 0 with no `eatenby`):
- `caninputcooldown` is set to 2.0
- The `Switch` sound is played
- The [SwitchParty](../../Battle%20flow/Action%20coroutines/SwitchParty.md) action coroutine is started (without fast) which changes to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md)
## Input 4 (confirm)
- `caninputcooldown` is set to 2.0
- instance.`inputcooldown` is set to 2.0
- A `Confirm` sound is played on `sounds[10]`
- `lastoption` is set to `option`
- `vineoption` is set to `maxoptions`
- `lastaction` is set to `option`
- [currentchoice](../Actions.md) is set to the `Actions` value whose numerical value is `option`
From there, what happens depends on [currentchoice](../Actions.md) and after, [UpdateText](../../Visual%20rendering/UpdateText.md) is called.
### `Attack`
- [SetTargets](../../Actors%20states/Targetting/SetTargets.md) is called
- If there's no `availabletargets`, PlayBuzzer is called (the attack usage is denied because no targets is available)
- Otherwise (the basic attack is accepted):
- `maxoptions` is set to the length of `availabletargets`
- [currentaction](../Pick.md) is set to `SelectEnemy`
- [itemarea](../../Player%20UI/AttackArea.md) is set to `SingleEnemy`
- `option` is set to 0
### `Skill`
- `excludeself` is set to false
- `playerdata[currentturn].lockskills` is true or it has the [Taunted](../../Actors%20states/BattleCondition/Taunted.md) or [Inked](../../Actors%20states/BattleCondition/Inked.md) condition, PlayBuzzer is called (the skill usage is denied)
- Otherwise (the skill usage is accepted):
- [currentaction](../Pick.md) is set to `SkillList`
- MainManager.[RefreshSkills](../../RefreshSkills.md) is called
- A couple of [ItemList](../../../ItemList/ItemList.md) fields are initialised (with an instance.`inputcooldown` of 5.0):
- `storeid`: 0
- [listtype](../../../ItemList/listtype.md): -`currentturn` - 1 which is the [skills list type](../../../ItemList/List%20Types%20Group%20Details/Skills%20List%20Type.md) of the corresponding player party member
- `listammount`: 5
- `listdesc`: true
- `listsell`: false
- [ShowItemList](../../../ItemList/ShowItemList.md) is called with -`currentturn` - 1 as the list type, MainManager.`defaultlistpos` as the position with showdescription and without sell
### `Item`
- `excludeself` is set to false
- [GetAvaliableTargets](../../Actors%20states/Targetting/GetAvaliableTargets.md) is called with onlyground without onlyfront using -1 as the acttackid
- If instance.`items[0]` is empty (no standard items) or `playerdata[currentturn].lockitems` is true or it has the [Taunted](../../Actors%20states/BattleCondition/Taunted.md) or [Sticky](../../Actors%20states/BattleCondition/Sticky.md) condition, PlayBuzzer is called (the item usage is denied)
- Otherwise (the item usage is accepted):
- [currentaction](../Pick.md) is set to `ItemList`
- A couple of [ItemList](../../../ItemList/ItemList.md) field are initialised (with an instance.`inputcooldown` of 5.0):
- `storeid`: 0
- [listtype](../../../ItemList/listtype.md): 0 which is the [standard items list type](../../../ItemList/List%20Types%20Group%20Details/Items%20List%20Type.md)
- `listammount`: 5
- `listdesc`: true
- `listsell`: false
- [ShowItemList](../../../ItemList/ShowItemList.md) is called with 0 as the list type, MainManager.`defaultlistpos` as the position with showdescription and without sell
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
### `Strategy`
- [currentaction](../Pick.md) is set to `StrategyList`
- A couple of [ItemList](../../../ItemList/ItemList.md) field are initialised (with an instance.`inputcooldown` of 5.0):
- `storeid`: 0
- [listtype](../../../ItemList/listtype.md): 9 which is the [battle strategy list type](../../../ItemList/List%20Types%20Group%20Details/Battle%20Strategy%20List%20Type.md)
- `listammount`: 6
- `listdesc`: true
- `listsell`: false
- [ShowItemList](../../../ItemList/ShowItemList.md) is called with 9 as the list type, MainManager.`defaultlistpos` as the position with showdescription and without sell
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
### `Relay`
- If there's 1 or less `playerdata` or `playerdata[currentturn].locktri` (unable to relay) or `haspassed` is true (already relayed on the same main turn) or it has the [Taunted](../../Actors%20states/BattleCondition/Taunted.md) condition, PlayBuzzer is called (the relay is denied)
- Otherwise (the relay is accepted):
- `excludeself` is set to true
- `option` is set to 0
- `helpboxid` is set to -1
- `maxoptions` is set to the length of `playerdata`
- `itemarea` is set to `SingleAlly`
- `option` is incremented with wrap around to `maxoptions` - 1 repeatedly via IncreaseOption until its value is `currentturn`
- [currentaction](../Pick.md) is set to `SelectPlayer`
### `Swap`
- `excludeself` is set to true
- `option` is set to 0
- `helpboxid` is set to -1
- `maxoptions` is set to the length of `playerdata`
- `option` is incremented with wrap around to `maxoptions` - 1 repeatedly via IncreaseOption until its value is `currentturn`
- [currentaction](../Pick.md) is set to `SelectPlayer`

View File

@@ -0,0 +1,46 @@
# `SelectEnemy` ChoiceInput logic
This page details the logic of [GetChoiceInput](../GetChoiceInput.md) when [currentaction](../Pick.md) is `SelectEnemy`.
[CreateHelpBox](../../Visual%20rendering/CreateHelpBox.md) is called followed by `excludeself` being set to false.
The rest is input handling logic.
## Input 2 / 3 (left / right)
These 2 inputs are only processed if [itemarea](../../Player%20UI/AttackArea.md) isn't `AllParty`, `AllEnemies` or `All`.
These inputs changes the `option` by one depending on the direction (decrement if left, increment if right with wrap around from 0 to `maxoptions` - 1 using DecreaseOption and IncreaseOption).
Additionally, a `Scroll` sound played on `sounds[10]` before changing the `option` and [UpdateText](../../Visual%20rendering/UpdateText.md) is called after changing it.
## Input 5 (cancel)
ReturnToMainSelect is called which does the following:
- The `Cancel` sound is played on AudioSource 10
- [currentaction](../Pick.md) is set to `BaseAction`
- `option` is set to `lastoption`
- `selecteditem` is set to -1
- DestroyHelpBox is called which sets `helpboxid` to -1 and destroys `helpbox` if it existed in 0.5 seconds with shrink before setting it to null
- [SetMaxOptions](../SetMaxOptions.md) is called
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
## Input 4 (confirm)
A `Confirm` sound is played on `sounds[10]` followed by `target` being set to `option`.
What happens after depends on the [currentchoice](../Actions.md) (nothing happen if it's not among these `Actions`).
### `Attack`
A [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md) action coroutine is started changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md) on `playerdata[currentturn].battleentity` using -1 as the action id (the basic attack id).
### `Item`
CheckItemUse is called with the `selecteditem` which ends starting a [UseItem](../../Battle%20flow/Action%20coroutines/UseItem.md) action coroutine changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md).
### `Skill`
- `lastskill` is set to `selecteditem`
- A [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md) action coroutine is started changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md) on `playerdata[currentturn].battleentity` using `selecteditem` as the action id (the [skill](../../../Enums%20and%20IDs/Skills.md) id).
### `Strategy`
- [ItemList](../../../ItemList/ItemList.md)'s `listredirect` is set to -1 (this workarounds a potential [inlist issue](../../../ItemList/inlist%20issue.md))
- [currentaction](../Pick.md) is set to `BaseAction`
- A [Tattle](../../Battle%20flow/Action%20coroutines/Tattle.md) action coroutine is started changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md) if `disablespy` is false.

View File

@@ -0,0 +1,62 @@
# `SelectPlayer` ChoiceInput logic
This page details the logic of [GetChoiceInput](../GetChoiceInput.md) when [currentaction](../Pick.md) is `SelectPlayer`.
All the logic present here is input handling logic.
## Input 2 / 3 (left / right)
These 2 inputs are only processed if [itemarea](../../Player%20UI/AttackArea.md) isn't `AllParty`, `AllEnemies` or `All`.
These inputs changes the `option` by one depending on the direction (decrement if left, increment if right with wrap around from 0 to `maxoptions` - 1 using DecreaseOption and IncreaseOption). However, there are 2 exceptions (only one is applied)
- If `excludeself` is true, the increment/decrement is redone over and over until `option` isn't `currentturn` (meaning the player that will be selected isn't the one performing an action)
- Otherwise, if PartyInOrder returns false (meaning more than 1 member exists and swaps occured such that it is no longer in one of the 3 expected order), the reverse change will be done instead. This works because all combinations where the party is out of order happens to cycle in reverse order (intuitively, think of fixing the first number, your only choices are +1 and -1 in the cycle which locks in the last one and the latter choice is out of order while the former choice is in order)
Additionally, a `Scroll` sound played on `sounds[10]` before changing the `option` and [UpdateText](../../Visual%20rendering/UpdateText.md) is called after changing it.
## Input 5 (cancel)
ReturnToMainSelect is called which does the following:
- The `Cancel` sound is played on AudioSource 10
- [currentaction](../Pick.md) is set to `BaseAction`
- `option` is set to `lastoption`
- `selecteditem` is set to -1
- DestroyHelpBox is called which sets `helpboxid` to -1 and destroys `helpbox` if it existed in 0.5 seconds with shrink before setting it to null
- [SetMaxOptions](../SetMaxOptions.md) is called
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
## Input 4 (confirm)
If [itemarea](../../Player%20UI/AttackArea.md) is `AllParty`, `option` is set to `currentturn`.
What happens after depends on the [currentchoice](../Actions.md) (nothing happen if it's not among these `Actions`).
### `Item`
CheckItemUse is called with the `selecteditem` which may end starting a [UseItem](../../Battle%20flow/Action%20coroutines/UseItem.md) action coroutine changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md).
However, this item usage may be denied which won't cause UseItem to be called and instead, PlayBuzzer will be called.
The condition for the item usage to be allowed is `playerdata[option].eatenby` must not exist and either `playerdata[option].hp` is above 0 or it's not, but the [item data](../../../TextAsset%20Data/Items%20data.md) of `selecteditem` has a `Revive` or `ReviveAll` `ItemUsage` (meaning the player party member isn't eaten, but it's dead while the item can revive them). It is disallowed otherwise.
### `Relay`
If CanBeRelayed returns true on `option`, a [Relay](../../Battle%20flow/Action%20coroutines/Relay.md) action coroutine is started changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md) otherwise, PlayBuzzer is called.
For CanBeRelayed to return true, all of the following must be true on `playerdata[option]` (false is returned otherwise):
- Its `hp` is above 0
- Its `lockrelayreceive` is false (nothing is preventing the actor from being relayed to)
- It doesn't have the [Numb](../../Actors%20states/BattleCondition/Numb.md) condition
- It doesn't have the [Sleep](../../Actors%20states/BattleCondition/Sleep.md) condition
- It doesn't have the [Freeze](../../Actors%20states/BattleCondition/Freeze.md) condition
- It doesn't have the [Taunted](../../Actors%20states/BattleCondition/Taunted.md) condition
- It doesn't have the [Sturdy](../../Actors%20states/BattleCondition/Sturdy.md) condition
- It doesn't have the [EventStop](../../Actors%20states/BattleCondition/EventStop.md) condition
- It doesn't have an `eatenby`
### `Swap`
A [SwitchPos](../../Battle%20flow/Action%20coroutines/SwitchPos.md) action coroutine is started changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md) to swap `currentturn` as the called with `option` as the target.
### `Skill`
For the [skill](../../../Enums%20and%20IDs/Skills.md) to be used, if the [skilldata](../../../TextAsset%20Data/Skills%20data.md#skilldata) of `tempskill` reports that it can only target alive party members, `playerdata[target].hp` must be above 0. Alternatively, if the`skilldata` of `tempskill` reports that it can only target dead party members, `playerdata[target].hp` must be 0 or below. This doesn't apply if neither restrictions applies on the skill, but no matter what, `playerdata[target].eatenby` must not exist.
If the skill can be used, a [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md) action coroutine is started changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md) on `playerdata[currentturn].battleentity` using `tempskill` as the action id.
Otherwise, PlayBuzzer is called

View File

@@ -0,0 +1,10 @@
# GetChoiceInput
This method manages the UI naviguation called from [PlayerTurn](../Battle%20flow/PlayerTurn.md) when `turncooldown` expired.
The logic depends on the [currentaction](Pick.md) and most of the logic involves input handling through the different menus. The logics are located in their own page matching the corresponding [Pick](Pick.md) value handled by this method (the others are handled somewhere else such as MainManager in the case of an [ItemList](../../ItemList/ItemList.md)).
|`currentaction`|Link to its UI handling logic page|
|--------------:|---------------------------------|
|`BaseAction`|[BaseAction](Confirmation%20handling/BaseAction.md)|
|`SelectEnemy`|[BaseAction](Confirmation%20handling/SelectEnemy.md)|
|`SelectPlayer`|[BaseAction](Confirmation%20handling/SelectPlayer.md)|

View File

@@ -0,0 +1,36 @@
# GotoSelect
If the confirmation handling needs to move to target selection (which happens from [SetItem](SetItem.md)), a method called GotoSelect is involved receiving a boolean called overridemax which prepares the state for [GetChoiceInput](GetChoiceInput.md) to handle this.
```cs
private void GotoSelect(bool overridemax)
```
Here is the logic of that method depending on the [itemarea](../Player%20UI/AttackArea.md) (nothing happens if it's not among them):
## `SingleAlly`
- `maxoptions` is set to the length of `playerdata`
- [currentaction](Pick.md) is set to `SelectPlayer`
## `SingleEnemy`
- If overridemax is false, `maxoptions` is set to the length of `availabletargets`
- [currentaction](Pick.md) is set to `SelectEnemy`
## `AllEnemies`
- `option` is set to 0
- `maxoptions` is set to 1
- [currentaction](Pick.md) is set to `SelectEnemy`
## `AllParty`
- `option` is set to `currentturn`
- `maxoptions` is set to 1
- [currentaction](Pick.md) is set to `SelectPlayer`
## `All`
- `option` is set to 0
- `maxoptions` is set to 1
- [currentaction](Pick.md) is set to `SelectEnemy`

View File

@@ -0,0 +1,70 @@
# Battle strategy list type confirmation handling
This page describes the logic [SetItem](../SetItem.md) has when handling a [listtype](../../../ItemList/listtype.md) of [Battle strategy](../../../ItemList/List%20Types%20Group%20Details/Battle%20Strategy%20List%20Type.md).
The logic depends on the `listvar` option:
## 271 (Swap)
This acts as if 0 (Switch) was selected if there is 2 or less `playerdata`.
Otherwise:
- [itemarea](../../Player%20UI/AttackArea.md) is set to `SingleAlly`
- [currentchoice](../Actions.md) is set to `Swap`
- `helpboxid` is set to -1
- `excludeself` is set to true
- If `currentturn` is 0, `option` is set to 1
- [GotoSelect](../GotoSelect.md) without overridemax is called
## 2 (Do Nothing)
DoNothing is called which does the following:
- If `playerdata[currentturn].didnothing` is false (the player party member didn't already did nothing), several effects can happen depending on at least 1 instance of a specific [medal](../../../Enums%20and%20IDs/Medal.md) being equipped on the `currentturn` player party member (more can stack, these aren't mutually exclusive):
- `Meditation`: instance.`tp` is incremented by the amount of medals equipped then clamped from 0 to instance.`maxtp`. This is followed by the `Heal2` sound being played and `MagicUp` particles playing at `playerdata[currentturn].battleentity` position + (0.0, 0.5, 0.0)
- `Prayer`: `playerdata[currentturn].hp` is incremented by the amount of medals equipped * 2 then clamped from 0 to `playerdata[currentturn].maxhp`. This is followed by the `Heal` sound being played (If no `Meditation` is equipped) and `Heal` particles playing at `playerdata[currentturn].battleentity` position + (0.0, 0.5, 0.0)
- `Reflection`: If no `Prayer` or `Meditation` medals is equipped, the `StatUp` sound is played. This is followed by a [StatEffect](../../Visual%20rendering/StatEffect.md) starting on the battleentity with type 1 (blue, up arrow) and if the player party member doesn't have the [Reflection](../../Actors%20states/BattleCondition/Reflection.md) condition, [SetCondition](../../Actors%20states/Conditions%20methods/SetCondition.md) is called with `Reflection` on the player party member with a turn amount being the amount of medals equipped
- `playerdata[currentturn].didnothing` is set to true which prevents the medals effects to apply on a second do nothing
- [EndPlayerTurn](../../Battle%20flow/EndPlayerTurn.md) is called
- [CancelList](../CancelList.md) is called
## 0 (Switch)
The `Switch` sound is played followed by a [SwitchParty](../../Battle%20flow/Action%20coroutines/SwitchParty.md#switchparty) action coroutine starting switching to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md).
## 1 (Spy)
- [ItemList](../../../ItemList/ItemList.md)'s `listredirect` is set to -1 (this is to workaround a potential [inlist issue](../../../ItemList/inlist%20issue.md))
- `availabletargets` is set to the return of GetTattleable which is all `enemydata` whose `notattle` is false
- If `availabletargets` is empty, PlayBuzzer is called followed by ReloadStrategy being called and invoked another time in 0.1 seconds. The method does the following (essentially denies the spy):
- [currentaction](../Pick.md) is set to `StrategyList`
- `helpboxid` is set to -1
- A couple of [ItemList](../../../ItemList/ItemList.md) field are initialised (with an instance.`inputcooldown` of 5.0):
- `storeid`: 0
- [listtype](../../../ItemList/listtype.md): 9 which is the [battle strategy list type](../../../ItemList/List%20Types%20Group%20Details/Battle%20Strategy%20List%20Type.md)
- `listammount`: 6
- `listdesc`: true
- `listsell`: false
- [ShowItemList](../../../ItemList/ShowItemList.md) is called with 9 as the list type, MainManager.`defaultlistpos` as the position with showdescription and without sell
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- Otherwise (the spy is accepted):
- [CreateHelpBox](../../Visual%20rendering/CreateHelpBox.md) with id 0 is called
- [itemarea](../../Damage%20pipeline/AttackProperty.md) is set to `SingleEnemy`
- `maxoptions` is set to the length of `availabletargets`
- [currentaction](../Pick.md) is set to `SelectEnemy`
## 3 (Flee)
If `canflee` is true, a [TryFlee](../../Battle%20flow/Action%20coroutines/TryFlee.md) action coroutine is started changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md). This ends the handler.
If it's false however (this denies the flee with a message):
- [CancelList](../CancelList.md) is called
- [ItemList](../../../ItemList/ItemList.md)'s `listredirect` is set to -1 (this is to workaround a potential [inlist issue](../../../ItemList/inlist%20issue.md))
- [SetText](../../../SetText/SetText.md) is called in [dialogue mode](../../../SetText/Dialogue%20mode.md) using `|`[boxstyle](../../../SetText/Individual%20commands/Boxstyle.md)`,4||`[spd](../../../SetText/Individual%20commands/Spd.md)`,0|` followed by `menutext[73]` (a message informing the player they cannot flee) as the text and the following:
- [fonttype](../../../SetText/Notable%20states.md#fonttype) of 0 (`BubblegumSans`)
- linebreak of MainManager.`messagebreak`
- No tridimensional
- position of Vector3.zero
- No cameraoffset
- size of Vector2.one
- No parent
- No caller
- A `WaitForMessage` coroutine is started which yields as long as the [message](../../../SetText/Notable%20states.md#message) lock is grabbed followed by calling [UpdateText](../../Visual%20rendering/UpdateText.md) followed by a frame yield
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called

View File

@@ -0,0 +1,15 @@
# Skills list type confirmation handling
This page describes the logic [SetItem](../SetItem.md) has when handling a [listtype](../../../ItemList/listtype.md) of [Skills](../../../ItemList/List%20Types%20Group%20Details/Skills%20List%20Type.md).
- `maxoptions` is set to the length of `availabletargets`. This should be up to date as [SetTargets](../../Actors%20states/Targetting/SetTargets.md) was called the last time [PlayerTurn](../../Battle%20flow/PlayerTurn.md) happened while we were in the main vine menu
- `tempskill` is set to the sent `listvar` option which is the chosen [skill](../../../Enums%20and%20IDs/Skills.md) id
- [currentchoice](../Actions.md) is set to `Skill`
- `helpboxid` is set to the one that comes from the [skilldata](../../../TextAsset%20Data/Skills%20data.md#skilldata), but if MainManager.`mashcommandalt` is true (sequential keys is set in the settings):
- 4 (`TappingKey`) is overriden to 8 (`RandomTappingKeysTimer`)
- 10 (`RandomTappingBar`) is overriden to 8 (`RandomTappingKeysTimer`)
- 11 (`RandomPressKeyTimer`) is overriden to 8 (`RandomTappingKeysTimer`)
- 9 (`RandomPressBar`) is overriden to 12 (`MultiPressBar`)
- [itemarea](../../Player%20UI/AttackArea.md) is set to the `AttackArea` from [skilldata](../../../TextAsset%20Data/Skills%20data.md)
- `excludeself` is set to the the value from [skilldata](../../../TextAsset%20Data/Skills%20data.md)
- If [itemarea](../../Player%20UI/AttackArea.md) is `User`, there is no need to have [GetChoiceInput](../GetChoiceInput.md) handle this so it is handled immediately by starting a [DoAction](../../Battle%20flow/Action%20coroutines/DoAction.md) action coroutine changing to an [uncontrolled flow](../../Battle%20flow/Update%20flows/Uncontrolled%20flow.md)
- Otherwise, [GotoSelect](../GotoSelect.md) is called with overridemax

View File

@@ -0,0 +1,19 @@
# Standard items list type confirmation handling
This page describes the logic [SetItem](../SetItem.md) has when handling a [listtype](../../../ItemList/listtype.md) of [standard items](../../../ItemList/List%20Types%20Group%20Details/Items%20List%20Type.md).
- We first check if the item is usable. There are 2 ways in which an item may not be usable:
- Any `ItemUse` from [itemdata](../../../TextAsset%20Data/Items%20data.md#itemdata) has an `UsageType` of `None`
- The [AttackArea](../../Player%20UI/AttackArea.md) from [itemdata](../../../TextAsset%20Data/Items%20data.md#itemdata) is `AllEnemies` or `SingleEnemy` and [GetAvaliableTargets](../../Actors%20states/Targetting/GetAvaliableTargets.md) for attackid -1 without onlyground or onlyground, but with excludeunderground causes `availabletargets` to become empty (in other words, the item affects one or all enemy party members, but there's no one above ground to be targetted)
- If the item isn't usable, ReturnToMainSelect is called which does the following:
- The `Cancel` sound is played on AudioSource 10
- [currentaction](../Pick.md) is set to `BaseAction`
- `option` is set to `lastoption`
- `selecteditem` is set to -1
- DestroyHelpBox is called which sets `helpboxid` to -1 and destroys `helpbox` if it existed in 0.5 seconds with shrink before setting it to null
- [SetMaxOptions](../SetMaxOptions.md) is called
- [UpdateText](../../Visual%20rendering/UpdateText.md) is called
- Otherwise, if the item is usable:
- [currentchoice](../Actions.md) is set to `Item`
- [itemarea](../../Player%20UI/AttackArea.md) is set to the one from [itemdata](../../../TextAsset%20Data/Items%20data.md#itemdata)
- `helpboxid` is set to -1
- [GotoSelect](../GotoSelect.md) is called without overridemax

Some files were not shown because too many files have changed in this diff Show More