Skip to content

Commit

Permalink
Add and correct docs about the firststrike system
Browse files Browse the repository at this point in the history
  • Loading branch information
aldelaro5 committed Aug 1, 2024
1 parent 9d3ecea commit 1fbc202
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ This section happens for each player party member.

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
- This isn't a [firststrike](../firststrike%20system.md) 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)
Expand Down
12 changes: 6 additions & 6 deletions docs/Battle system/Battle flow/Action coroutines/DoAction.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ From there, the next phase depends on the entity itself. It can either be a play

- 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
- [firststrike](../firststrike%20system.md) 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.
Effectively, it always allow the first `enemydata` to take their action during a `firststrike`, but other enemy party members requires to be on hardmode or HARDEST to act in a `firststrike`. Check the [firststrike](../firststrike%20system.md) documentation to learn more.

### Player action
This phase applies only if the entity has a `Player` tag.
Expand Down Expand Up @@ -117,7 +117,7 @@ The actionid directly tells what action will be performed by a switch on it. Unl
For more information on the player actions logic, consult the main [player actions](../../Player%20actions/Player%20actions.md) documentation page.

### 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.
This phase applies if the entity doesn't have a `Player` tag unless the enemy party member was denied their action during a [firststrike](../firststrike%20system.md).

#### Enemy action setup
This part of the enemy action phase occurs before any action is performed:
Expand Down Expand Up @@ -244,10 +244,10 @@ In either cases, they both end by setting all enemy party members's `lockpositio
- 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`:
- If this isn't a [firststrike](../firststrike%20system.md):
- 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:
- Otherwise, `action` is set to false switching to a [controlled flow](../Update%20flows/Controlled%20flow.md)
- If this isn't a [firststrike](../firststrike%20system.md) 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)
Expand Down
4 changes: 2 additions & 2 deletions docs/Battle system/Battle flow/AdvanceTurnEntity.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ This section only does something if the condition's turn counter just reached 0
- [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 [firststrike](firststrike%20system.md) is false (the enemy party isn't performing a first strike), 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`:
- Otherwise, if the actor's `hp` is above 0 and it's not a [firststrike](firststrike%20system.md):
- `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
Expand Down
61 changes: 61 additions & 0 deletions docs/Battle system/Battle flow/firststrike system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# `firststrike` system
There is an exceptional case to the regular battle flow where half a main turn can be processed completely while [StartBattle](../StartBattle.md) is ongoing. This is the case where `adv` had a value of 3 which allows the enemy party to perform what is called a `firststrike`.

A `firststrike` is a main turn that occurs before the first one recognised by the battle system. It's a special main turn because the [player phase](Main%20turn%20life%20cycle.md#player-phase) is completely skipped. Only the [Enemy phase](Main%20turn%20life%20cycle.md#enemy-phase) and the [end of turn phase](Main%20turn%20life%20cycle.md#turn-end-phase) occurs on that main turn.

The way it works is when StartBattle receives an adv of 3, it setups the battle like the following:

- `enemy` is set to true
- `action` is set to true
- `firststrike` is set to true
- [DoAction](Action%20coroutines/DoAction.md) is called with `enemydata[0]`
- Yield until `action` goes to false

The overall effect is it changes the battle flow to an [uncontrolled flow](Update%20flows/Uncontrolled%20flow.md) as if the battle was in the enemy phase with the first enemy party member taking their actor turn.

However, there is one key difference with this actor turn: `firststrike` is set to true. This has some implications:

- The [enemy action](Action%20coroutines/DoAction.md#enemy-action) can behave differently depending on if they are in a `firststrike` or not
- DoAction will not call a [CheckDead](Action%20coroutines/CheckDead.md) in [post action](Action%20coroutines/DoAction.md#post-action) when no enemy fled
- DoAction won't froce drops the enemy party members in [post action](Action%20coroutines/DoAction.md#post-action)

In a normal situation, DoAction gets done, `action` gets set to false and the battle switches to a [controlled flow](Update%20flows/Controlled%20flow.md). However, keep in mind that StartBattle is yielding until `action` goes to false so at this point, StartBattle is ready to take over from now.

Except that's not going to happen immediately due to coroutine's lower priority.

## What happens after the first enemy action?
StartBattle is a corotuine. It means that no matter what happens, Update gets processed BEFORE it resumes. It means that Update does get a chance to run before StartBattle realises that the battle already set `action` to false and can continue.

Update however won't let StartBattle resume right away. Since StartBattle setup the battle system in such a way that the system already started and setup, it will act like normal. On that next Update, it will find that `enemydata[0]` spent an actor turn, but it will also process the next enemy actor turn available. Effectively, the battle proceeds like it would normally in the enemy phase despite the fact StartBattle isn't done and is actually still waiting!

`firststike` is still set to true when the enemy phase goes on like this. This gives an additional difference to a regular main turn: DoAction will NOT let other enemy party members act other than the first one if the `DoublePainReal` [medal](../../Enums%20and%20IDs/Medal.md) isn't equipped and [flags](../../Flags%20arrays/flags.md) 614 is false (HARDEST is inactive). This is a difficulty scaling feature: on hard mode or HARDEST, the entire enemy party member can act during a `firststrike`, but without either applying, only the first can act during a `firststrike`. If the action is skipped, DoAction will process as if the enemy did nothing in their action, but still consume their actor turn like normal.

This keeps going until all enemy actor turns were consumed. All enemy actor turns will be consumed before StartBattle resumes because it only takes a single Update cycle to process the next enemy action. Effectively, the battle system switches back and forth between [controlled flow](Update%20flows/Controlled%20flow.md#controlled-flow) and [uncontrolled flow](Update%20flows/Uncontrolled%20flow.md#uncontrolled-flow).

## A special main turn advance
Since all enemy actor turns gets processed, it eventually leads the main turn to be in the [turn end phase](Main%20turn%20life%20cycle.md#turn-end-phase). This will call [AdvanceMainTurn](Action%20coroutines/AdvanceMainTurn.md) preventing once again StartBattle to resumes since this also changes to an uncontrolled flow.

The main turn doesn't get advanced like normal however. For the most part, most of the procedure is the usual, but with some key differences due to `firststrike` being true still:

- [AdvanceTurnEntity](AdvanceTurnEntity.md) won't increment `turnssincealive` and `turnssincedeath`
- [AdvanceTurnEntity](AdvanceTurnEntity.md) won't advance the `cantmove` or `moreturnnextturn` if the entity's `hp` is above 0. Effectively, their actor turn availability is frozen
- [AdvanceMainTurn](Action%20coroutines/AdvanceMainTurn.md) won't process the `MiracleMatter` [medal](../../Enums%20and%20IDs/Medal.md) effects

The main turn however still gets advanced normally other than that. It means things like [conditions](../Actors%20states/Conditions.md), [delproj](../Actors%20states/Delayed%20projectile.md) process as normal, but the turn counters don't advance like normal.

From there, AdvanceMainTurn eventually switches back to a controlled flow, but that Update won't lead to `action` being set to true this time. This finally gives a chance for StartBattle to resume as it's still been waiting.

## Cleaning up
From there, a main turn was advanced, but StartBattle would like to proceed as if it didn't happen. This leads to the following final steps to cleanup:

- A [CheckDead](Action%20coroutines/CheckDead.md) happens just in case
- All enemy party members gets their `cantmove` and `tired` reset to 0 which resets their exhaustion and gives them 1 actor turn on this main turn. NOTE: This is incorrect and it should been set to -[moves](../Actors%20states/Enemy%20features.md#moves) + 1. The overall effect of this error is enemies with a `moves` of 2 or above looses all, but one actor turn on the battle's first main turn
- `currentturn` is reset to -1 (the previous Update potentially set the value, but it's undesired here as StartBattle isn't done yet)
- `action` is set to false (it already was false so this makes doubly sure the battle is in a controlled flow)
- `enemy` is set to false (same reason)
- `firststrike` is set to false (ends the `firststrike`)
- 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)

On top of this, later on, StartBattle ends by setting `turns` to 0. It effectively means that the main turn that was just advanced doesn't count towards the global main turn counter. It can be seen as if it was "main turn number -1".

From there, the battle continues as normal.
2 changes: 1 addition & 1 deletion docs/Battle system/Battle state.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ This is all the BattleControl fields.
|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)|
|[firststrike](Battle%20flow/firststrike%20system.md)|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) which changes [CleanKill](Actors%20states/CleanKill.md) and the post action logic of DoAction|
|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|
Expand Down
4 changes: 4 additions & 0 deletions docs/Battle system/BattleControl.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Here are all the terms that will be used throughout the battle system documentat
- `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
- `move`: Refer to a series of tasks an [enemy action](Enemy%20actions/Enemy%20actions.md) performs at the expense of others.
- [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
Expand Down Expand Up @@ -92,6 +93,9 @@ When all the actor turns available are consumed, the actor needs to wait their a
### 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.

### The [firststrike](Battle%20flow/firststrike%20system.md) system
Another exception to the main turn flow can occur during StartBattle where the enemy party is able to act before the player party. This is called a `firststrike`, check the documentation to learn more about how this system works.

## 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).

Expand Down
2 changes: 1 addition & 1 deletion docs/Battle system/Enemy actions/Enemies/DeadLanderA.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ HardMode being true does the following changes:

Move 2 is always used if all of the following conditions are fufilled:

- `firststrike` is false (the enemy party isn't performing their first turn advantage)
- [firststrike](../../Battle%20flow/firststrike%20system.md) is false (the enemy party isn't performing their first main turn advantage)
- This enemy [position](../../Actors%20states/BattlePosition.md) wasn't `Underground` at the start of the action (before the pre move logic)
- A 50% RNG check passes

Expand Down
2 changes: 1 addition & 1 deletion docs/Battle system/Enemy actions/Enemies/GoldenSeedling.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Move 4 is always used (and can only be used) when [position](../../Actors%20stat
Move 3 usage is always considered first and it is used if all of the following conditions are fufilled:

- The enemy party isn't doing a `firststrike`
- The enemy party isn't doing a [firststrike](../../Battle%20flow/firststrike%20system.md)
- This enemy doesn't have the [Taunted](../../Actors%20states/BattleCondition/Taunted.md) condition
- A 49% RNG check passes

Expand Down
Loading

0 comments on commit 1fbc202

Please sign in to comment.