diff --git a/docs/_data/tech/data-files/character_table.csv b/docs/_data/tech/data-files/character_table.csv new file mode 100644 index 0000000..9948c5c --- /dev/null +++ b/docs/_data/tech/data-files/character_table.csv @@ -0,0 +1,22 @@ +"Value","Character","Notes" +"0x00","Tidus","" +"0x01","Yuna","" +"0x02","Auron","" +"0x03","Kimahri","" +"0x04","Wakka","" +"0x05","Lulu","" +"0x06","Rikku","" +"0x07","Seymour","" +"0x08","Valefor","" +"0x09","Ifrit","" +"0x0A","Ixion","" +"0x0B","Shiva","" +"0x0C","Bahamut","" +"0x0D","Anima","" +"0x0E","Yojimbo","" +"0x0F","Cindy","" +"0x10","Sandy","" +"0x11","Mindy","" +"0x12","Dummy1","Unused dummy aeon" +"0x13","Dummy2","Unused dummy aeon" +"0xFF","None","" diff --git a/docs/_data/tech/data-files/ctb_data_block.csv b/docs/_data/tech/data-files/ctb_data_block.csv new file mode 100644 index 0000000..0ab6a18 --- /dev/null +++ b/docs/_data/tech/data-files/ctb_data_block.csv @@ -0,0 +1,3 @@ +"Offset","Type","Name","Notes" +"0x0","byte","tickSpeed","Base ticks per turn" +"0x1","byte","ICV_reduction","Max possible reduction to base ICV" \ No newline at end of file diff --git a/docs/_data/tech/data-files/formula_table.csv b/docs/_data/tech/data-files/formula_table.csv new file mode 100644 index 0000000..e563313 --- /dev/null +++ b/docs/_data/tech/data-files/formula_table.csv @@ -0,0 +1,20 @@ +"Value","Formula" +"0x00","None" +"0x01","StrVsDef" +"0x02","StrIgnoreDef" +"0x03","MagVsMDef" +"0x04","MagIgnoreMDef" +"0x05","CurrentDiv16" +"0x06","Multiple50" +"0x07","Healing" +"0x08","MaxDiv16" +"0x09","Multiple50WithVariance" +"0x0D","TicksDiv16" +"0x0F","SpecialMag" +"0x10","FixedUserMaxHP" +"0x11","CelestialHP" +"0x12","CelestialMP" +"0x13","CelestialLowHP" +"0x15","FixedChosenGil" +"0x16","FixedKills" +"0x17","Fixed9999" diff --git a/docs/_data/tech/data-files/gear_rate_block.csv b/docs/_data/tech/data-files/gear_rate_block.csv new file mode 100644 index 0000000..8c77997 --- /dev/null +++ b/docs/_data/tech/data-files/gear_rate_block.csv @@ -0,0 +1,2 @@ +"Offset","Type","Name","Notes" +"0x0","int","value","The value of the auto-ability" \ No newline at end of file diff --git a/docs/_data/tech/data-files/mix_table_block.csv b/docs/_data/tech/data-files/mix_table_block.csv new file mode 100644 index 0000000..31bdb78 --- /dev/null +++ b/docs/_data/tech/data-files/mix_table_block.csv @@ -0,0 +1,2 @@ +"Offset","Type","Name","Notes" +"0x0","short[112]","mixList","IDs of resulting Mix Overdrives" \ No newline at end of file diff --git a/docs/game-mechanics/damage.md b/docs/game-mechanics/damage.md new file mode 100644 index 0000000..7e84a70 --- /dev/null +++ b/docs/game-mechanics/damage.md @@ -0,0 +1,144 @@ +--- +parent: "Game Mechanics" +title: "Damage" +--- +# {{ page.title }} +{: .no_toc } + +## Table of contents +{: .no_toc } + +1. TOC +{:toc} + +## Mechanics +Every weapon and ability (magic, skills, etc.) is assigned one of several damage formulas to use. An ability's damage formula can be overridden by a weapon's if the ability has the `use_weapon_props` flag set (see Commands). Note that whether an attack is considered physical or magical is determined by a separate variable in the command data, *not* the formula. + +The ID table for each formula is as follows: + +{% for row in site.data.tech.data-files.gear_block -%} +{%- if forloop.first -%} +|{% for cell in row %} {{ cell[0] }} |{% endfor %} +|{% for cell in row %} :---: |{% endfor %} +{% endif -%} +|{% for cell in row %} {{ cell[1] }} |{% endfor %} +{% endfor %} + +## Formulas +Several variables used in the following formula descriptions will be defined here: +- $d$ is damage. +- $u_{hp}$, $u_{maxHP}$, $u_{mp}$, $u_{maxMP}$, $u_{str}$, $u_{def}$, $u_{mag}$, and $u_{mdf}$ are the user's statistics. +- $u_{cheer}$ and $u_{focus}$ are the user's Cheer and Focus counts. + - For simplicity, $u_{str} + u_{cheer}$ and $u_{mag} + u_{focus}$ will both be denoted with $x$. + - The "buff factor" $b_{(cheer|focus)} = {15 - t_{(cheer|focus)} \over 15}$ +- Target statistics are the same as user statistics, but are denoted with $t$ instead of $u$. +- $p$ is the move's power. + - For simplicity, ${p \over 16}$ will be denoted with $p'$. +- $v$ is random variance, where $v = {k \over 256}$ and $k = \text{random}(240,271)$. + +Additionally, some formulas use an additional factor $r$ calculated from the target's defense to reduce the damage taken: + +$$ r = {730 - {t_{(def|mdf)} \cdot 51 - {t_{(def|mdf)}^2 \over 11} \over 10} \over 730} \cdot b_{(cheer|focus)} $$ + +Note that if the target is Armor Broken or Mental Broken, their defense or magic defense, respectively, are considered 0. + +### STR vs. DEF +$$ d = \left({x^3 \over 32} + 30\right) \cdot r \cdot p' \cdot v $$ + +Neglect $r$ if defense is ignored. + +### MAG vs. MDF +$$ d = \left({x^2 \over 6} + p\right) \cdot r \cdot 4p' \cdot v $$ + +Neglect $r$ if defense is ignored. + +### Current or Max (Statistic) +$$ d = t_{stat} \cdot p' $$ + +### Multiple of 50 +$$ d = 50 \cdot p $$ + +with variance: + +$$ d = 50 \cdot p \cdot v $$ + +### Healing +$x$ is magical. + +$$ d = (x + p) \cdot 8p' \cdot v $$ + +### Special Magic +$x$ is magical. + +$$ d = \left({x^3 \over 32} + 30\right) \cdot p' \cdot v $$ + +### User Max HP +$$ d = {u_{maxHP} \over 10} \cdot p $$ + +### Celestial - High HP/MP +This damage formula uses an additional factor $c$, the celestial factor. +$x$ is physical. + +$$ c = {{u_{(hp|mp)} \cdot 100 \over u_{(maxHP|maxMP)} + 10} \over 110} $$ + +$$ d = \left({x^3 \over 32} + 30\right) \cdot c \cdot p' \cdot v $$ + +### Celestial - Low HP +This damage formula uses an additional factor $c$, the celestial factor. +$x$ is physical. + +$$ c = {{130 - {u_{hp} \cdot 100 \over u_{maxHP}}} \over 60} $$ + +$$ d = \left({x^3 \over 32} + 30\right) \cdot c \cdot p' \cdot v $$ + +### Chosen Gil +This damage formula uses an additional factor $g$, equal to the amount of gil chosen. + +$$ d = {g \over 10} $$ + +### Target Kills +This damage formula uses the amount of enemies the target has killed, denoted with $k$. It only works against player characters. + +$$ d = k \cdot p $$ + +### Multiple of 9999 + +$$ d = 9999 \cdot p $$ + +## Additional Modifiers +### HP Damage +Additional modifiers are applied to the calculated damage in the following order: +1. If the target is under the effects of the Shield command, the damage is multiplied by `0.25`. +2. If the target is under the effects of the Boost command, the damage is multiplied by `1.5`. +3. If the attack is magical and the target is under the effects of Shell, the damage is halved. +4. If the attack is physical and the target is under the effects of Protect, the damage is halved. +5. If the attack is a critical hit, the damage is doubled. +6. If the user is berserked, the damage is multiplied by `1.5`. +7. If the user has Magic Booster and the command is located in the black or white magic submenus, the damage is multipled by `1.5`. +8. If the user has Alchemy, the command is an item, is healing, and uses either the `Multiple of 50` or `Target Max HP` damage formulae, damage is doubled. +9. Apply Strength +%, Magic +%, Defense +%, and Magic Def +% auto-abilities accordingly. These multiply the raw damage, not the stats. +10. If the command uses either the `Target Max HP` or the `Current Statistic` damage formulae, and the target is immune to fractional damage, the damage is set to 0. +11. If the command makes the user absorb the damage and either user or the target (but not both) are under the effects of Zombie, the damage is negated (that is, multiplied by `−1`). +12. Elemental weaknesses and resistances are applied: + – If the enemy is weak to any element of the attack, only weaknesses are considered: for each weakness that matches one of the attack’s elements, the damage is multiplied by `1.5`, then truncated to an integer. + – If the enemy is neutral to any element of the attack, further steps are skipped. + – If the enemy is resistant to any element of the attack, the damage is halved and further steps are skipped. + – If the enemy is immune to any element of the attack, the damage is set to 0 and further steps are skipped. + – If the enemy absorbs any element of the attack, the damage is negated. +13. If the attack is not piercing, the user's weapon does not have Piercing, and the target is armored, damage is divided by `3`. +14. If the attack is physical and target is defending, the damage is halved. +15. If the attack is physical and the user is under the effects of Power Break, the damage is halved OR if the attack is magical and the user is under the effects of Magic Break, the damage is halved. +16. If the attack is physical and the target is immune to physical damage, the damage is set to 0. +17. If the attack is magical and the target is immune to magical damage, the damage is set to 0. +18. If the target is invincible, the damage is set to 0. +19. If attack was an overdrive with a timed component an additional bonus is applied, derived from the remaining overdrive time (up to 50% at 100% time remaining). +### MP Damage +Additional modifiers are applied to the calculated damage in the following order: +1. If the user has Magic Booster and the command is located in the black or white magic submenus, the damage is multiplied by `1.5`. +2. If the user has Alchemy, the command is an item, is healing, and uses either the `Multiple of 50` or `Target Max HP` damage formulae, damage is doubled. +3. If the command makes the user absorb the damage and either user or the target (but not both) are under the effects of Zombie, the damage is negated (that is, multipled by `−1`). +### CTB Damage +An additional modifier is applied to the calculated damage: +1. If the command makes the user absorb the damage and either user or the target (but not both) are under the effects of Zombie, the damage is negated (that is, multipled by `−1`). + +Written by [{{ site.contributors.evelyntsmg.name }}]({{ site.contributors.evelyntsmg.url }}) diff --git a/docs/tech/data-files/ctb-data.md b/docs/tech/data-files/ctb-data.md new file mode 100644 index 0000000..de57a5c --- /dev/null +++ b/docs/tech/data-files/ctb-data.md @@ -0,0 +1,41 @@ +--- +grand_parent: "Tech" +parent: "Data Files" +title: "CTB Data" +--- +# {{ page.title }} +{: .no_toc } + +## Table of contents +{: .no_toc } + +1. TOC +{:toc} + +## CTB Data files +The general data file mapping CTB values to Agility values is called `ctb_base.bin` and can be found inside the `FFX_Data/ffx_ps2/ffx/master/jppc/battle/kernel` folder in the VBF archive. + +The Agility stat determines two parameters used in the Conditional Turn-Based Battle system. The first is **Tick Speed**, and the second is **Initial Counter Value** (or **ICV**). Every action taken by a character generates a **Tick Counter** according to the following formula: + +```Counter = TickSpeed * Rank * HasteStatus``` + +where `rank` is the move's rank (specified in command data) and `HasteStatus` is 0.5 when the character is under the Haste status, 2 when under Slow, and 1 otherwise. Non-integer results are rounded up. Every character's counter is reduced by 1 each "tick", and the character's next turn occurs when their counter reaches 0. + +During a Pre-emptive Strike or Ambush, the disadvantaged side's counters are initialized to `TickSpeed * 3` at the start of battle. Otherwise, this is only the *maximum possible* initial counter value, and the ICV has a chance to be reduced by a number based on Agility. For enemies, `TickSpeed * 3` is instead the *minimum* possible ICV, and ranges are much greater; however, that data is not stored here. + +The lowest possible tick speed is 3, which is achieved at 170 Agility. Agility has sharply diminishing returns above the value of 62, with extremely large gaps between further reductions in tick speed and some increments not even conferring a greater reduction in ICV. + +### Block +The CTB data block is 2 (0x2) bytes long and consists of two 8-bit integers. + +{% for row in site.data.tech.data-files.ctb_data_block -%} +{%- if forloop.first -%} +|{% for cell in row %} {{ cell[0] }} |{% endfor %} +|{% for cell in row %} :---: |{% endfor %} +{% endif -%} +|{% for cell in row %} {{ cell[1] }} |{% endfor %} +{% endfor %} + +The block is repeated for every value of Agility, up to the stat maximum of 255. + +Written by [{{ site.contributors.irin.name }}]({{ site.contributors.irin.url }}) diff --git a/docs/tech/data-files/gear-data.md b/docs/tech/data-files/gear-data.md new file mode 100644 index 0000000..d7a7232 --- /dev/null +++ b/docs/tech/data-files/gear-data.md @@ -0,0 +1,49 @@ +--- +grand_parent: "Tech" +parent: "Data Files" +title: "Equipment Data" +--- +# {{ page.title }} +{: .no_toc } + +## Table of contents +{: .no_toc } + +1. TOC +{:toc} + +## Equipment Data files +Equipment data is defined in three files: `buki_get.bin`, `shop_arms.bin`, and `weapon.bin`. These files can be found inside the `FFX_Data/ffx_ps2/ffx/master/jppc/battle/kernel` folder in the VBF archive. `buki_get.bun` defines gear obtained from treasure chests, `shop_arms.bin` defines gear sold in shops, and `weapon.bin` defines other pre-existing gear (starting gear, gear obtained in scenes, Celestial weapons, etc.). + +### Block +In each file the data block is 22 (0x16) bytes long. + +{% for row in site.data.tech.data-files.gear_block -%} +{%- if forloop.first -%} +|{% for cell in row %} {{ cell[0] }} |{% endfor %} +|{% for cell in row %} :---: |{% endfor %} +{% endif -%} +|{% for cell in row %} {{ cell[1] }} |{% endfor %} +{% endfor %} + +where `character_id` can be mapped to the following values: + +{% for row in site.data.tech.data-files.character_table -%} +{%- if forloop.first -%} +|{% for cell in row %} {{ cell[0] }} |{% endfor %} +|{% for cell in row %} :---: |{% endfor %} +{% endif -%} +|{% for cell in row %} {{ cell[1] }} |{% endfor %} +{% endfor %} + +and `damage_formula` can be mapped to the following values: + +{% for row in site.data.tech.data-files.formula_table -%} +{%- if forloop.first -%} +|{% for cell in row %} {{ cell[0] }} |{% endfor %} +|{% for cell in row %} :---: |{% endfor %} +{% endif -%} +|{% for cell in row %} {{ cell[1] }} |{% endfor %} +{% endfor %} + +Written by [{{ site.contributors.irin.name }}]({{ site.contributors.irin.url }}) \ No newline at end of file diff --git a/docs/tech/data-files/gear-prices.md b/docs/tech/data-files/gear-prices.md new file mode 100644 index 0000000..dc7aa94 --- /dev/null +++ b/docs/tech/data-files/gear-prices.md @@ -0,0 +1,44 @@ +--- +grand_parent: "Tech" +parent: "Data Files" +title: "Equipment Prices" +--- +# {{ page.title }} +{: .no_toc } + +## Table of contents +{: .no_toc } + +1. TOC +{:toc} + +## Equipment Price files +Equipment price is partially determined by its auto-abilities, each of which have an associated gil value. The general data file containing the value of each auto-ability is called `arms_rate.bin` and can be found inside the `FFX_Data/ffx_ps2/ffx/master/jppc/battle/kernel` folder in the VBF archive. + +The full formula for determining equipment price is: + +```(50 + sum(ability_value)) * slots_factor * empty_slots_factor``` + +where `slots_factor` and `empty_slots_factor` are arrays with indices corresponding to the number of filled and empty slots, respectively. The values for each are as follows: + +``` +EQUIPMENT_SLOTS_GIL_MODIFIERS = (1, 1, 1.5, 3, 5) +EQUIPMENT_EMPTY_SLOTS_GIL_MODIFIERS = (1, 1, 1.5, 3, 400) +``` + +The location of the formula data is currently unknown. + +### Block +The gear price block is 4 (0x4) bytes long and consists only of a single integer determining an auto-ability's value. + +{% for row in site.data.tech.data-files.gear_rate_block -%} +{%- if forloop.first -%} +|{% for cell in row %} {{ cell[0] }} |{% endfor %} +|{% for cell in row %} :---: |{% endfor %} +{% endif -%} +|{% for cell in row %} {{ cell[1] }} |{% endfor %} +{% endfor %} + +The block is repeated for every existing auto-ability (and more if unmodified). The index of the block, that is, the point at which it appears in the file, determines which auto-ability it contains the value for. The first block contains the value of Sensor, the second contains the value of First Strike, the third of Initiative, and so on. + +Written by [{{ site.contributors.irin.name }}]({{ site.contributors.irin.url }}) diff --git a/docs/tech/data-files/index.md b/docs/tech/data-files/index.md index cc29b60..b32268a 100644 --- a/docs/tech/data-files/index.md +++ b/docs/tech/data-files/index.md @@ -11,7 +11,7 @@ Unless otherwise stated, all data is written in little endian. General data files header: -{% for row in site.data.tech.data-files.general_headers -%} +{% for row in site.data.tech.data-files.general_header -%} {%- if forloop.first -%} |{% for cell in row %} {{ cell[0] }} |{% endfor %} |{% for cell in row %} :---: |{% endfor %} diff --git a/docs/tech/data-files/mix-table.md b/docs/tech/data-files/mix-table.md new file mode 100644 index 0000000..10a2ffd --- /dev/null +++ b/docs/tech/data-files/mix-table.md @@ -0,0 +1,33 @@ +--- +grand_parent: "Tech" +parent: "Data Files" +title: "Mix Table" +--- +# {{ page.title }} +{: .no_toc } + +## Table of contents +{: .no_toc } + +1. TOC +{:toc} + +## Mix Table files +The general data file mapping item combinations to Mix Overdrives is called `prepare.bin` and can be found inside the `FFX_Data/ffx_ps2/ffx/master/jppc/battle/kernel` folder in the VBF archive. + +### Block +The data block is 224 (0xE0) bytes long and consists of a short array of length 112. + +{% for row in site.data.tech.data-files.mix_table_block -%} +{%- if forloop.first -%} +|{% for cell in row %} {{ cell[0] }} |{% endfor %} +|{% for cell in row %} :---: |{% endfor %} +{% endif -%} +|{% for cell in row %} {{ cell[1] }} |{% endfor %} +{% endfor %} + +The block is repeated for each consumable item in the game. This effectively produces a `u16[112][112]` 2-dimensional array. The first index corresponds to the first item selected, and the second index corresponds to the second item selected. Each value of the array is the ID of the resulting Mix Overdrive. + +Each block only has entries up to the combination of the item with itself, with all of the following entries being blank. So for example, block 0 only has an ID in its first index, corresponding to the combination of Potion \+ Potion, with the other 111 entries having a null value of `0x0000`. + +Written by [{{ site.contributors.irin.name }}]({{ site.contributors.irin.url }}) \ No newline at end of file