├── .gitignore ├── README.md ├── _config.yml ├── deeper ├── AssetStorage │ └── README.md ├── README.md ├── battle │ ├── 32-bit-float.md │ ├── README.md │ ├── buff.md │ ├── critstars.md │ ├── damage.md │ ├── dsl.md │ └── np.md └── master │ ├── README.md │ ├── mstBuff.md │ ├── mstFunc.md │ ├── mstSkillLv.md │ ├── mstSvt.md │ └── mstSvtTreasureDevice.md └── images ├── Musashi_damage.png ├── OK_Lancelot.png ├── OK_MHXA.png ├── OK_Scathach.png ├── taunt_1.x.png ├── taunt_2.x.png └── use_big_sl.png /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Miscellaneous information on FGO gameplay 3 | 4 | [![Discord server invite](https://discordapp.com/api/guilds/502554574423457812/embed.png)](https://discord.gg/TKJmuCR) 5 |
↥Top
6 |
7 | 8 | Below is a collection of small posts about FGO mechanics. Most are originally discussed in the Atlas Academy discord server. Some more techy information such as the [damage formula](deeper/battle/damage.md) can be found in the [deeper](deeper/README.md) folder. 9 | 10 | - [Range of randomModifier in the damage formula](#range-of-randommodifier-in-the-damage-formula) 11 | - [Arash and Chen Gong NP OC effect randomModifier](#arash-and-chen-gong-np-oc-effect-randommodifier) 12 | - [Maximum value of total powerMod](#maximum-value-of-total-powermod) 13 | - [Lower and upper bounds of buffs](#lower-and-upper-bounds-of-buffs) 14 | - [Unstackable buffs](#unstackable-buffs) 15 | - [enemyServerMod in the NP gain formula](#enemyservermod-in-the-np-gain-formula) 16 | - [How MISS and GUARD are determined](#how-miss-and-guard-are-determined) 17 | - [How enemy's Critical Miss is determined](#how-enemys-critical-miss-is-determined) 18 | - [How the special summoning effects work](#how-the-special-summoning-effects-work) 19 | - [How hit damage is distributed](#how-hit-damage-is-distributed) 20 | - [How the Overkill bug happens](#how-the-overkill-bug-happens) 21 | - [Enemy behavior after killing taunt servant](#enemy-behavior-after-killing-taunt-servant) 22 | - [Pre 2.0 update behavior](#pre-20-update-behavior) 23 | - [What affects whether a card procs critical hit](#what-affects-whether-a-card-procs-critical-hit) 24 | - [~~Lists of Mystic Code skills that have 500% chance in JP but 100% in NA~~](#lists-of-mystic-code-skills-that-have-500-chance-in-jp-but-100-in-na) 25 | 26 | ### Range of randomModifier in the damage formula 27 | 28 | An integer in the range [900, 1100): 29 | 30 | - 900: inclusive lower bound (0.9 `randomModifier` is possible) 31 | - 1100: exclusive upper bound (1.1 `randomModifier` is **not** possible) 32 | 33 | [C# method reference](https://docs.microsoft.com/en-us/dotnet/api/system.random.next?view=netframework-4.8#System_Random_Next_System_Int32_System_Int32_). 34 | 35 | ### Arash and Chen Gong NP OC effect randomModifier 36 | Because [Arash](https://apps.atlasacademy.io/db/JP/servant/16/noble-phantasms) and [Chen Gong](https://apps.atlasacademy.io/db/JP/servant/258/noble-phantasms) NP OC effect is an extra deal damage function, they use a different `randomModifier`, independent from the main damage function's `randomModifier`. 37 | 38 | ### Maximum value of total powerMod 39 | 40 | 1000%. 41 | 42 | ### Lower and upper bounds of buffs 43 | 44 | - Some common factors in the damage formula 45 | 46 | | Damage formula term | Buff Action | Default Value | Lower Bound | Upper Bound | 47 | | --- | --- | --- | --- | --- | 48 | | atkMod | atk | 100% | 0 | 500% | 49 | | defMod | defence | 100% | 0 | N/A | 50 | | cardMod | commandAtk | 100% | 0 | 500% | 51 | | cardMod | commandDef | 100% | N/A | 500% | 52 | | powerMod | damage | 0% | N/A | 1000% | 53 | | critDamageMod | criticalDamage | 0% | N/A | 500% | 54 | | npDamageMod | npdamage | 0% | N/A | 500% | 55 | | specialDefMod | specialdefence | 0% | -100% | 500% | 56 | 57 | - NP gain 58 | 59 | | NP gain formula term | Buff Action | Default Value | Lower Bound | Upper Bound | 60 | | --- | --- | --- | --- | --- | 61 | | cardMod | commandNpAtk | 100% | 0 | 500% | 62 | | cardMod | commandNpDef | 100% | N/A | 500% | 63 | | npChargeRateMod | dropNp | 100% | 0 | 500% | 64 | 65 | - Crit stars 66 | 67 | | Crit stars formula term | Buff Action | Default Value | Lower Bound | Upper Bound | 68 | | --- | --- | --- | --- | --- | 69 | | cardMod | commandStarAtk | 100% | 0 | 500% | 70 | | cardMod | commandStarDef | 100% | N/A | 500% | 71 | | starDropMod | criticalPoint | 100% | 0 | 500% | 72 | | enemyStarDropMod | criticalPoint | 100% | 0 | 500% | 73 | 74 | Here's how the buff values are collected and summed up in the game code: 75 | - Each term in the damage formula corresponds to one or many buff actions. Buff actions are like buff categories containing positive and negative buff types. 76 | - The mapping of damage formula terms to buff actions can be found [here](deeper/battle/damage.md). 77 | - The mapping of buff actions to positive and negative buff types can be found [here](https://api.atlasacademy.io/export/JP/NiceBuffList.ActionList.json). 78 | - For example: `atkMod` refers to the `atk` buff action which contains `upAtk` plusTypes and `downAtk` minusTypes. [Charisma buff](https://apps.atlasacademy.io/db/#/NA/buff/126) has buff type `upAtk`. 79 | 80 | - Buff actions values are calculated using the following formula: 81 | ```python 82 | num = buffAction.baseParam + (total plusTypes buffs values) - (total minusTypes buff values) 83 | 84 | if buffAction.limit in (normal, lower): 85 | if num < 0: 86 | num = 0 87 | 88 | num = num - buffAction.baseValue; 89 | 90 | if buffAction.limit in (normal, upper): 91 | if maxRate < num: 92 | num = maxRate 93 | 94 | return num 95 | ``` 96 | - Explanation of the variables: 97 | - Buff action variables can be found [here](https://api.atlasacademy.io/export/JP/NiceBuffList.ActionList.json): 98 | - `baseParam` 99 | - `baseValue` 100 | - `limit` 101 | - `maxRate` is a property of the buff item. This value can be found in the [DB](https://apps.atlasacademy.io/db/#/) or [API](https://api.atlasacademy.io/docs). If there are multiple buffs, the max `maxRate` is used. Different buffs of the same buff action usually have the same `maxRate` value. 102 | - For example: we are trying to calculate `cardMod` with 10 level 10 Merlin's [Hero Creation](https://apps.atlasacademy.io/db/#/NA/skill/323650) applied and no buster damage down: 103 | - `cardMod` -> buff action `commandAtk` -> `plusTypes` [buff type](https://apps.atlasacademy.io/db/#/NA/buff/102) `upCommandall` 104 | - `baseParam`: 1000 105 | - `baseValue`: 0 106 | - `limit`: normal 107 | - `maxRate`: 5000 108 | - `num` = 1000 + 500 * 10 = 6000 (`baseParam` = 1000 and there are 10 Hero Creation, each has `Value` of 500) 109 | - `limit` is normal but `num` > 0 so lower bound is not applied 110 | - `num` = `num` - `baseValue` = 6000 - 0 = 6000 111 | - `limit` is normal and `num` > `maxRate` so upper bound is applied -> `num` = 5000 112 | - The final `cardMod` value is 5000 or 500%. 113 | 114 | Notes: 115 | - It's not quite correct to say the max value of `powerMod` is 1000%. As seen in [the formula mapping](deeper/battle/damage.md), `powerMod` consists of 4 buff actions and each of them has their own limits. However, most of the common `powerMod` buffs fall into buff action `damage` which has an upper limit of 1000%. 116 | - The interaction can get pretty messy so when in doubt, follow the formula step by step. I purposefully used "Default Value" in the table above instead of "baseParam" or "baseValue". 117 | - There are also some floors in the [damage formula](deeper/battle/damage.md) that might affect the effective buff value. 118 | 119 | ### Unstackable buffs 120 | 121 | Buffs which have the __same non-zero buff group__ are unstackable. For example: 122 | - Both [Petrify](https://apps.atlasacademy.io/db/#/NA/buff/176) from Gorgon's [Mystic Eyes A++](https://apps.atlasacademy.io/db/#/NA/skill/93552) and [Stun](https://apps.atlasacademy.io/db/#/NA/buff/178) from Plugsuit's [Gandr](https://apps.atlasacademy.io/db/#/NA/skill/980005) have buff group 500 so they don't stack. 123 | - [Guts](https://apps.atlasacademy.io/db/#/JP/buff/180) from [Herc's bond CE](https://apps.atlasacademy.io/db/#/JP/craft-essence/197) is of buff group 600 and [Guts](https://apps.atlasacademy.io/db/#/JP/buff/2932) from [Herc's 3rd skill post strengthening](https://apps.atlasacademy.io/db/#/JP/buff/2932) has buff group 601 so they can stack. 124 | - Both [Cu's 2nd skill](https://apps.atlasacademy.io/db/#/NA/servant/17/skill-2) and the CE [Under the Sun](https://apps.atlasacademy.io/db/#/NA/craft-essence/773) use the same [buff 151](https://apps.atlasacademy.io/db/#/NA/buff/151) for the Evade effect. This buff has buff group 200 so Cu's skill and the CE's effects can't stack. 125 | - A lot of skills use the same [buff 102](https://apps.atlasacademy.io/db/#/NA/buff/102) for the Buster Up effect. This buff has buff group 0 so a servant can carry multiple Buster Up buffs. 126 | 127 | ### enemyServerMod in the NP gain formula 128 | 129 | [The NP gain formula](https://blogs.nrvnqsr.com/entry.php/3306-How-much-NP-do-I-get-in-combat). 130 | 131 | The `enemyServerMod`s in the attacking and defending formulas refer to two different variables in the enemy data: `tdRate` for attacking NP gain and `tdAttackRate` for defending NP gain. They are usually the same but there's no code requirement for them to be identical. 132 | 133 | ### How MISS and GUARD are determined 134 | 135 | The status effect proc check is still as described in [Kyte's post](https://blogs.nrvnqsr.com/entry.php/3311-How-is-effect-success-rate-calculated). MISS and GUARD are only for display. Here's how they are determined: 136 | 137 | * num3 = status effect chance 138 | * random roll = random integer in range [0, 1000) 139 | * num2 = target's resistance + random roll 140 | * if num2 > num3: buff fails 141 | * if num2 > 1000 (100%): it displays GUARD, otherwise MISS 142 | 143 | As a result of this, a failed 100% chance status effect can only display GUARD. 144 | 145 | For example, with Shuten's first skill (60% chance Charm, 100% chance DEF down) against shadow Medusa in the X-E FQ with 17.5% resistance: 146 | 147 | * Charm effect: 148 | * Example 1: 149 | * num3 = 600 150 | * random roll = 876 151 | * num2 = 876 + 175 = 1051 152 | * 1051 > 600 -> buff fails 153 | * 1051 > 1000 -> displays GUARD 154 | * Example 2: 155 | * num3 = 600 156 | * random roll = 598 157 | * num2 = 598 + 175 = 773 158 | * 773 > 600 -> buff fails 159 | * 773 < 1000 -> displays MISS 160 | * DEF down effect: 161 | * Example 1: 162 | * num3 = 1000 163 | * random roll = 928 164 | * num2 = 928 + 175 = 1103 165 | * 1103 > 1000 -> buff fails 166 | * 1103 > 1000 -> displays GUARD 167 | * Example 2: 168 | * num3 = 1000 169 | * random roll = 761 170 | * num2 = 761 + 175 = 936 171 | * 936 < 1000 -> buff procs 172 | 173 | ### How enemy's Critical Miss is determined 174 | 175 | The critical miss sign appears if the enemy has a crit chance down debuff and would have crit without the debuff assuming the rng roll is the same. 176 | 177 | ### How the special summoning effects work 178 | 179 | [Reddit post](https://www.reddit.com/r/grandorder/comments/9pmta4/the_truth_in_code_summoning_gold_orbs_rainbow/) about gold orbs, rainbow orbs and silver to gold conversions. 180 | 181 | ### How hit damage is distributed 182 | 183 | The following formula applies to all hits' damage except for the last one: 184 | 185 | Hit damage = Card damage × Hit Percentage / Sum of hits percentage (Note that `/` is [integer division](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#integer-division)) 186 | 187 | The last hit's damage is calculated by subtracting the previous hits' damage from the card damage. 188 | 189 | Therefore, the last hit's damage can be different from a prior hit's even with the same hit percentage. For example, Musashi's Buser card has `[33, 67]` damage distribution. With her first skill active, the damage distribution array becomes `[33, 33, 67, 67]`. With card damage of 15,228, the hits damage are `[2512, 2512, 5101, 5103]`: 190 | 191 | ```python 192 | >>> 15228 * 33 // 200 # Hit 1; "//" is integer division 193 | 2512 194 | >>> 15228 * 33 // 200 # Hit 2; 33+33+67+67=200 195 | 2512 196 | >>> 15228 * 67 // 200 # Hit 3 197 | 5101 198 | >>> 15228 - 2512 - 2512 - 5101 # Hit 4 199 | 5103 200 | ``` 201 | 202 |
203 | 204 | ### How the Overkill bug happens 205 | 206 | What is the Overkill bug? 207 | 208 | > In various circumstances, face cards (not NPs) can get 1.5x NP gain similar to the overkilling effect, despite the card not killing the enemy. 209 | 210 | To determine which hit should have the overkill effect, the game keeps track of provisional damage between hits and compares it with the target's HP value. The target's HP is updated between cards while the provisional damage counter is not reset between cards. This leads to double counting of damage dealt and "overkilling" when the target is still alive. 211 | 212 | Here are some examples of how the game determines when the overkill effect applies and the overkill bug in action. 213 | 214 | * Explanations of the tables' columns: 215 | * `reducedhp` is the provisional damage counter: 216 | * `reducedhp` is updated every hit 217 | * `reducedhp` starts at 0 218 | * `start reducedhp` + `damage` = `end reducedhp` 219 | * `start reducedhp` = usually previous hit's `end reducedhp` (see the Lancelot NP case for a different case) 220 | * `hp` is the target's HP value used for comparision with `reducedhp`: 221 | * `hp` is updated between cards 222 | * `OK` is whether the hit has overkill effect: 223 | * `end reducedhp` < `hp` -> Normal 224 | * `end reducedhp` >= `hp` -> OK 225 | 226 | * Scathach BQAE: 227 | 228 | Scathach's quick card and first hit of the arts card experience overkill effect before she kills the target. Because the `hp` value is updated after the first card (14409 to 7300) while `reducedhp` is carried over from the first card, the overkill bug happens. 229 | 230 |
231 | 232 | * Lancelot NP: 233 | 234 | `reducedhp` is properly reset for Lancelot's NP card so the bug doesn't happen here. NP gain value is also shown in the table. 235 | 236 |
237 | 238 | * MHXA BAQE: 239 | 240 | A video of the bug in action: https://www.bilibili.com/video/av34113229 @ 1:42. MHXA Arts card 2nd hit has the overkill bug. 241 | 242 |
243 | 244 | * `reducedhp` is also reset when a `deadFunction` (Trigger skill on Death [Trigger skill on Death](https://apps.atlasacademy.io/db/NA/buffs?type=deadFunction)) or a `gutsFunction` (Trigger skill on Guts [Trigger skill on Guts](https://apps.atlasacademy.io/db/NA/buffs?type=gutsFunction)) activates. For example, as seen in [this video of the behaviour in Valentine's 2023 (NA) CQ](https://www.youtube.com/watch?v=CGVNWn8ZBRc), the observed charge gain on Romulus-Quirinus's Arts card is **54.15%** with the card dealing **0** overkill hits on Artemis; however the expected charge gain should be **72.19%** with the card dealing **2** overkill hits on Artemis: 245 | 246 | |   | Enemy HP | `reducedhp` before arts card | Damage dealt | `reducedhp` after arts card | Overkill (`reducedhp` > enemy HP) 247 | | - | - | - | - | - | - 248 | | Expected | `84543` | `68435` | `67922` | `136357` | true 249 | | Observed | `84543` | `0` (reset) | `67922` | `67922` | false 250 | 251 | i.e. The `reducedhp` *should have been* `68435` *before* the first hit of the arts card; this would have made the `reducedhp` *after* the arts card (`136357`) greater than the enemy HP (`84543`). This is what the first row in the above table shows. However, as we see in the second row, the `reducedhp` was reset by the time the arts card hit; meaning that the *actual* `reducedhp` *after* the arts card was merely `67922` (which is not greater than the enemy HP). Thus, no OK hits are observed on this card. 252 | 253 | > **Note** 254 | > `deadFunction` and `gutsFunction` also reset the `reducedHp` for *all enemies* (i.e., In a wave where an AOE attack that kills one enemy with `deadFunction`/`gutsFunction`, the `reducedHp` for the other enemy/eneemies is also reset; subsequent face cards that attack a surviving enemy start at 0 `reducedHp` 255 | > It is likely that there are functions apart from `deadFunction` and `gutsFunction` which can reset the `reducedHp` 256 | > Regardless of `deadFunction` and `gutsFunction`, guts proc itself (`createResurrection`) also resets reducedHp on the associated enemy 257 | 258 | ### Enemy behavior after killing taunt servant 259 | 260 | With the 2.0 update*, DW fixed this enemy behavior to be mostly consistent. Enemy will stop attacking after killing the taunt servant except for the following case: 261 | 262 | > If an enemy kills the taunt servant in the **first** attack action and the taunt servant has guts, the **second** attack action will not happen but the **third** attack action will. 263 | 264 | You can see this scenario in this [gif](https://imgur.com/WSxjitJ). Lalter attacked and killed Spartacus with guts. Tesla didn't attack and Siegfried attacked instead. 265 | 266 | **Note:** With the 2.0 update, I'm quite sure the behavior is the same even with enemy NP attack or attack with on-hit effects (e.g. Hokusai 3rd skill). 267 | 268 | You can see in the following image the reasons for the enemy behavior. 269 | 270 | * Table columns: 271 | * Scenario number: `1-6` 272 | * `tested`: whether all of the variables values are verified in the actual game 273 | * `1st attack`: outright kills the taunt servant, deals more than 50% hp or deals less than 50% hp of damage 274 | * `2nd attack`: kills the taunt servant or doesn't happen 275 | * `3rd attack`: happens or doesn't happen 276 | * Internal game variables and functions during the 3rd attack: 277 | * `hp`: the hp value 278 | * `isAlive`, `isGuts`, `checkDeadTurn`: 3 boolean flags of the **taunt servant** 279 | * `narrowDownHate`: returns the list of player servants with taunt. For example, the input of the function is `[1, 2, 3]` and the first servant has taunt, the output is `[1]`. 280 | * `getTargetBase`: returns the first "eligible" servant of the input list 281 | 282 |
283 | 284 | In all scenarios, even after the taunt servant is killed with or without guts, `narrowDownHate` returns the taunt servant, `[1]`. In scenarios 1, 2, 4-6, `getTargetBase` still considers `1` to be "dead" so it returns no eligible servant, `-1`, and there's no attack. 285 | 286 | In scenario 3, the flag `isAlive` is switched to `True` in the 3rd attack as the guts servant `hp` value is updated. `getTargetBase` found an eligible servant and the 3rd attack happens (For the 2nd attack, `isAlive` is still `False`). 287 | 288 | #### Pre 2.0 update behavior 289 | 290 | The table below details the enemy behavior before the 2.0 update. The cells that changed with the 2.0 update are highlighted. 291 | 292 | Generally, if the enemy deals more than 50% starting hp of damage and kills in the 2nd attack, there will be a 3rd attack. 293 | 294 | **Note:** This doesn't apply to enemy NP attack or attack with on-hit effects (e.g. Hokusai 3rd skill). 295 | 296 |
297 | 298 | The above conditions sound familiar? Yes, the overkill bug rears its head again. Because of the overkill bug, `checkDeadTurn` is set to `False` and wreaks havoc on the downstream functions: 299 | * Because the first attack deals more than 50% starting hp of damage, on the 2nd attack, `reducedhp` is greater than `hp`. Therefore, the game thinks the taunt servant is already dead and doesn't record `deadTurn` when the enemy kills the taunt servant. 300 | * As the overkill bug prevents `deadTurn` from being recorded on the 2nd attack, `checkDeadTurn` returns `False` on the 3rd attack. 301 | * `narrowDownHate` and `getTargetBase` behave differently with and without guts but essentially there will be a 3rd attack. 302 | 303 | **Note:** I don't track the game code closely enough to know for sure that this behavior changes with the 2.0 update but the NA game code is definitely different between version 1.35.1 and 2.1.0. There's still this pre-2.0 [video](https://youtu.be/_5bFrrDGvro?t=140) that I haven't been able to explain. 304 | 305 | ### What affects whether a card procs critical hit 306 | 307 | Skills with random chance like imperial privilege can have different outcomes if you savescum and use additional skills beforehand. In the same vein, critical hits can also be tampered with, and anything that affects skills will also affect critical proc rng. However, unlike skills, critical hits only enter the scene after the player selects their cards and starts their turn. Nevertheless, the player still has options to change whether cards crit or not. 308 | 309 | Let us consider [King Hassan](https://apps.atlasacademy.io/db/NA/servant/154), whose deck is described below: 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 |
CardHits
Arts (A)3
Buster (B)1
Quick (Q)5
Extra (E)6
323 | 324 | Let's assume we have a hand of his 5 cards (A-B-B-B-Q), and each card has a non-zero and non-100% chance to crit. 325 | 326 | Example scenario: B-B-Q chain and we are interested in whether the third card crits or not. Different inputs from the player can change whether it crits or not. These inputs will "advance" or "change" the rng. If the card has a 50% change to crit, a dice with 100 faces is rolled and it will crit if the number is above 50. This exact dice will always land with the same number — this is why you can't savescum while not using any skills and get a different result. When you push the rng by "1", you're going to the next dice which will give a completely dice roll. Despite getting a different dice roll, it's still possible to not crit or get the desired outcome, you're just getting another chance at it. 327 | 328 |
329 | 330 | - **Skills, CS:** 331 | 332 | - Each skill will advance the rng by a different amount depending on the number of effects it has and how many units it affects. For example, a basic charisma is going to advance rng following the amount of units on the field. However, skadi battery or a command seal only advances the rng by 1. The amount of rng change may come in relevant given the chosen command cards. 333 | 334 | - **The maximum amount of stars that CAN be generated:** 335 | 336 | - A common misconception is that it is the hit count up to the current card that changes whether it crits. For example, doing B-A-Q instead of B-B-Q would be 4 hits as opposed to 2 hits, thus leading to a different crit outcome. This generalization is true in most scenarios, but it is possible to get different crit result with the same hitcount or the same crit result with different hitcount. 337 | 338 | - Another misconception is that it is the amount of stars that has been generated that plays a determining factor. Once again that is true in most scenarios, but both these generalizations are a byproduct of the following: 339 | 340 | - What the hitcount actually does is affect how many stars can be generated. The stars that a card produces is the sum of the stars produced by each hit inside. This is why a card with a higher hitcount will typically generate more stars. Every time that a hit calculates the amount of stars, the rng will advance. 341 | 342 | - The rng will advance by a different amount depending on your stargen bracket. These brackets are `[1-100]`, `[101-200]` and `[201-300]`. Your position in these bracket is based on things like your stargen and card multiplier(like quick buff). If you are in the first bracket, each hit will generate up to one star, thus advance the rng by 1. If you are in the second bracket, each hit will always make 1 star and then have a chance of making a second one. However, this will still advance rng by 2. The same principle holds true for the third bracket. 343 | 344 | - Different things can change your stargen bracket. Alongside stargen and card multiplier, overkill and critical increase stargen by 30% and 20% respectively. All factors affecting stargen can be found in [the complete formula](deeper/battle/critstars.md). The amount of crits prior to the card does not play a direct role, they only matter if the critical(s) push the card to the next stargen bracket through the aforementioned 20% or by overkill shenanigans. Lastly, the class of the enemy can also slightly alter the stargen based on their [server rate](https://blogs.nrvnqsr.com/entry.php/3307-How-many-crit-stars-do-I-get-in-combat?bt=31528#comment31528). The exact value for each specific enemy can be found under `crit star mod` on the Atlas DB. 345 | 346 | - Certain command codes can also play a role. The command cards which increases the card stargen may change the rng. Using King Hassan arts card, if the card stargen is at 90%, the stargen would push the rng three times. With a command code that gives 20% stargen, it would change the card's bracket thus push the rng 6 times. However, if the stargen started at 60%, the bracket would remain the same thus would not change the rng. 347 | 348 | - Other command codes can also play a role. For example, the Da Vinci command code. In the B-B-Q chain, if either of the first cards contain this cc. It will push the rng by 1 and thus the quick card may differ. 349 | 350 | This description was focused for one of the cards to crit. However, most random events in battle use the same aforementioned dice. For example, the damage on the cards and the AI of the enemy is also different based on that dice. The only exception is guts calculation. Whether a servant comes back to life using guts is calculated using a separate dice so advancing the main dice counter won't affect whether [Necromancy CE](https://apps.atlasacademy.io/db/NA/craft-essence/73) procs guts and vice versa. 351 | 352 | 353 | 354 | ### ~~Lists of Mystic Code skills that have 500% chance in JP but 100% in NA~~ 355 | 356 | **UPDATE: All MC skills' chances were fixed on 2021-03-12** 357 | 358 | * Mystic Code: Chaldea 359 | * 2: Instant Enhancement 360 | * 3: Emergency Evade 361 | * Mystic Code: Chaldea Combat Uniform 362 | * 1: Buff All Allies 363 | * 2: Gandr 364 | * Mystic Code: Atlas Institute Uniform 365 | * 1: Dust of Osiris 366 | * 2: Rain of Isis 367 | * Anniversary Blonde 368 | * 1: Mana Burst 369 | * 3: Knight's Oath 370 | * Royal Brand 371 | * 1: Reaction Reinforcement 372 | * 2: Iron Devotion 373 | * 3: Inescapable 374 | * Brilliant Summer 375 | * 1: Rumble Party 376 | * 2: Deadly Trident 377 | * Memories of the Lunar Sea 378 | * 1: Spiritron Boost 379 | * 2: Stepping Stone to Ultimate Victory 380 | * Memories of the Far Side of the Moon 381 | * 1: Spiritron Boost (All) 382 | * 2: Stepping Stone To Survival 383 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Jekyll configuration 2 | markdown: GFM 3 | -------------------------------------------------------------------------------- /deeper/AssetStorage/README.md: -------------------------------------------------------------------------------- 1 | ## File : `AssetStorage.txt` 2 | 3 | This file holds assets directory. Example file: 4 | 5 | ``` 6 | ~4182764457 7 | @FgoDataVersion0066,20160420_1,20191217_11:54 8 | 1,DATA0,381064,1737938264,Audio/Servants_100300.cpk.bytes 9 | 1,SYSTEM,112832,89377592,CharaGraph/100000 10 | ``` 11 | 12 | 1. First line 13 | ``` 14 | ~4182764457 15 | ``` 16 | - `4182764457`: CRC32 in decimal of the rest of the file 17 | 18 | 2. Second line 19 | ``` 20 | @FgoDataVersion0066,20160420_1,20191217_11:54 21 | ``` 22 | - `FgoDataVersion0066`: MasterDataCacheVer 23 | - `20160420_1`: dataVersion 24 | - `20191217_11:54`: dateVersion 25 | 26 | 3. Asset data line 27 | ``` 28 | 1,DATA0,15520,2437962836,NoblePhantasm/Sequence/401500 29 | ``` 30 | - `1`: 31 | - `DATA0` or `SYSTEM`: 32 | - `SYSTEM`: required download before playing the game 33 | - `DATA0`: optional download 34 | - `15520`: Encrypted asset size in bytes 35 | - `2437962836`: CRC32 in decimal of the encrypted asset 36 | - `NoblePhantasm/Sequence/401500`: Unencrypted name of the asset -------------------------------------------------------------------------------- /deeper/README.md: -------------------------------------------------------------------------------- 1 | This folder contains more mathy information about FGO mechanics and internal data. 2 | 3 | - Battle: 4 | - [Damage Formula](battle/damage.md) 5 | - [Buff Value Calculation](battle/buff.md) 6 | - [Critical Stars](battle/critstars.md) 7 | - [NP Gain](battle/np.md) 8 | - [32-bit Float Calculation](battle/32-bit-float.md) 9 | - [Big and Deep SL](battle/dsl.md) -------------------------------------------------------------------------------- /deeper/battle/32-bit-float.md: -------------------------------------------------------------------------------- 1 | ### Floating-point format 2 | 3 | If possible, use 32-bit floating-point numbers for calculation in FGO. Here are several examples of how to to do it in several languages: 4 | 5 | - C++: https://repl.it/@squaresmile/FGO-NP-gain-in-C 6 | - Python: https://repl.it/@squaresmile/FGO-NP-gain-in-Python 7 | - Javascript: 8 | ```js 9 | let f = (v) => Math.fround(v), 10 | perhit = f(25), 11 | cardBonus = f(f(1) + f(f(6) * f(f(1) + f(f(800) / f(1000))))), 12 | finalEnemyMod = f(1), 13 | gainBonus = f(f(1) + f(300) / f(1000)), 14 | critBonus = f(2), 15 | base_gain_no_round = f(f(f(f(perhit * cardBonus) * finalEnemyMod) * gainBonus) * critBonus); 16 | 17 | console.log(Math.floor(base_gain_no_round)); 18 | console.log(base_gain_no_round); 19 | console.log(cardBonus); 20 | console.log(gainBonus); 21 | ``` 22 | 23 | The expected base NP gain output is 766. If 64-bit floating-point is used, the result will be 767. 24 | 25 | If you start the calculation from the numbers the game stores (200, 300, ... which are what the [API](http://api.atlasacademy.io/docs) returns), the boundary between int and float are pretty clear. Buffs' values are summed up in ints and then divided by 1000f when applicable. 26 | 27 | #### Test cases 28 | - `!test melt m180 hp10000000 quick crit third af`: 1243 per hit, 4972 total 29 | - Melt, third quick card, first arts card, 180% quick up + 8% quick up from passive, crit, no overkill hit 30 | - `!test abby m80 hp1 arts crit third ng30 af`: 1149 per hit, 6894 total 31 | - Abby, third arts card, first arts card, 80% arts up, 30% NP Gain up, crit, all overkill hits 32 | -------------------------------------------------------------------------------- /deeper/battle/README.md: -------------------------------------------------------------------------------- 1 | - [Damage Formula](damage.md) 2 | - [Buff Value Calculation](buff.md) 3 | - [Critical Stars](critstars.md) 4 | - [NP Gain](np.md) 5 | - [32-bit Float Calculation](32-bit-float.md) 6 | - [Big and Deep SL](dsl.md) -------------------------------------------------------------------------------- /deeper/battle/buff.md: -------------------------------------------------------------------------------- 1 | Buff actions values are calculated using the following formula: 2 | ```python 3 | num = buffAction.baseParam + (total plusTypes buffs values) - (total minusTypes buff values) 4 | 5 | if buffAction.limit in (normal, lower): 6 | if num < 0: 7 | num = 0 8 | 9 | num = num - buffAction.baseValue; 10 | 11 | if buffAction.limit in (normal, upper): 12 | if maxRate < num: 13 | num = maxRate 14 | 15 | return num 16 | ``` 17 | 18 | - Buff action variables can be found [here](https://api.atlasacademy.io/export/JP/NiceBuffList.ActionList.json): 19 | - `baseParam` 20 | - `baseValue` 21 | - `limit` 22 | - `maxRate` is a property of the buff item. This value can be found in the [DB](https://apps.atlasacademy.io/db/#/) or [API](https://api.atlasacademy.io/docs). If there are multiple buffs, the last `maxRate` is used. Different buffs of the same buff action usually have the same `maxRate` value. 23 | - For example: we are trying to calculate `cardMod` with 10 level 10 Merlin's [Hero Creation](https://apps.atlasacademy.io/db/#/NA/skill/323650) applied and no buster damage down: 24 | - `cardMod` -> buff action `commandAtk` -> `plusTypes` [buff type](https://apps.atlasacademy.io/db/#/NA/buff/102) `upCommandall` 25 | - `baseParam`: 1000 26 | - `baseValue`: 0 27 | - `limit`: normal 28 | - `maxRate`: 5000 29 | - `num` = 1000 + 500 * 10 = 6000 (`baseParam` = 1000 and there are 10 Hero Creation, each has `Value` of 500) 30 | - `limit` is normal but `num` > 0 so lower bound is not applied 31 | - `num` = `num` - `baseValue` = 6000 - 0 = 6000 32 | - `limit` is normal and `num` > `maxRate` so upper bound is applied -> `num` = 5000 33 | - The final `cardMod` value is 5000 or 500%. 34 | -------------------------------------------------------------------------------- /deeper/battle/critstars.md: -------------------------------------------------------------------------------- 1 | ### Crit stars 2 | 3 | [Crit stars formula](https://blogs.nrvnqsr.com/entry.php/3307-How-many-crit-stars-do-I-get-in-combat) 4 | 5 | ``` 6 | dropChancePerHit = 7 | ( 8 | (30) baseStarRate 9 | (31) + firstCardBonus + (cardStarValue * max(1 + cardMod, 0)) 10 | (32) + serverRate 11 | (33) + starDropMod 12 | (34) + enemyStarDropMod 13 | (35) + criticalModifier 14 | ) 15 | (36) * overkillModifier 16 | (37) + overkillAdd 17 | ``` 18 | 19 | Mapping of damage formula terms to [buff actions](buff.md): 20 | 21 | * cardMod = atkSvt.commandStarAtk - defSvt.commandStarDef 22 | * starDropMod = atkSvt.criticalPoint 23 | * enemyStarDropMod = defSvt.criticalStarDamageTaken 24 | * Previously: enemyStarDropMod = -defSvt.criticalPoint 25 | 26 | Other constants lookup: 27 | 28 | * baseStarRate: [NiceServant](https://api.atlasacademy.io/docs#/nice/get_servant_nice__region__servant__item_id__get).starGen 29 | * firstCardBonus, cardStarValue: 30 | * firstCardBonus: [NiceCard](https://api.atlasacademy.io/export/JP/NiceCard.json).card.order.addCritical 31 | * cardStarValue: [NiceCard](https://api.atlasacademy.io/export/JP/NiceCard.json).card.order.adjustCritical 32 | * serverRate: sent from server `cache.replaced.battleInfo.userSvt.starRate` 33 | * criticalModifier: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).CRITICAL_STAR_RATE = 0.2 34 | * overkillModifier: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).OVER_KILL_STAR_RATE = 1 35 | * overkillAdd: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).OVER_KILL_STAR_ADD = 0.3 -------------------------------------------------------------------------------- /deeper/battle/damage.md: -------------------------------------------------------------------------------- 1 | ### Damage 2 | 3 | [Damage formula](https://blogs.nrvnqsr.com/entry.php/3309-How-is-damage-calculated): 4 | 5 | ``` 6 | damage for this card = 7 | (01) servantAtk 8 | (02) * npDamageMultiplier 9 | (03) * {firstCardBonus + [cardDamageValue * max(1 + cardMod, 0)]} 10 | (04) * classAtkBonus 11 | (05) * triangleModifier 12 | (06) * attributeModifier 13 | (07) * randomModifier 14 | (08) * 0.23 15 | (09) * max(1 + atkMod - defMod, 0) 16 | (10) * criticalModifier 17 | (11) * extraCardModifier 18 | (12) * max(1 - specialDefMod, 0) 19 | (13) * max([1 + powerMod + selfDamageMod + (critDamageMod * isCrit) + (npDamageMod * isNP)], 0.001) 20 | (18) * max(1 + damageSpecialMod, 0.001) 21 | (14) * [1 + ((superEffectiveModifier - 1) * isSuperEffective)] 22 | (15) + dmgPlusAdd 23 | (16) + selfDmgCutAdd 24 | (17) + (servantAtk * busterChainMod) 25 | 26 | damage = Math.Floor(Math.Max(damage, 0)) 27 | ``` 28 | 29 | Mapping of damage formula terms to [buff actions](buff.md): 30 | 31 | * cardMod = actor.commandAtk - target.commandDef 32 | * atkMod = actor.atk 33 | * defMod = target.defence or target.defencePierce if it's a defence piercing NP 34 | * specialDefMod = target.specialdefence 35 | * powerMod = actor.damage + actor.damageIndividuality + actor.damageIndividualityActiveonly + actor.damageEventPoint 36 | * selfDamageMod = target.selfdamage 37 | * critDamageMod = actor.criticalDamage 38 | * npDamageMod = actor.npdamage 39 | * damageSpecialMod = actor.damageSpecial 40 | * superEffectiveModifier = function Correction value 41 | * dmgPlusAdd = actor.givenDamage 42 | * selfDmgCutAdd = target.receiveDamage 43 | 44 | Other constants lookup: 45 | 46 | * npDamageMultiplier: only applies to NP card, 1 otherwise 47 | * firstCardBonus, cardDamageValue: 48 | * firstCardBonus: [NiceCard](https://api.atlasacademy.io/export/JP/NiceCard.json).card.order.addAtk 49 | * cardDamageValue: [NiceCard](https://api.atlasacademy.io/export/JP/NiceCard.json).card.order.adjustAtk 50 | * classAtkBonus: [NiceClassAttackRate](https://api.atlasacademy.io/export/JP/NiceClassAttackRate.json).class 51 | * triangleModifier: [NiceClassRelation](https://api.atlasacademy.io/export/JP/NiceClassRelation.json).actor.target 52 | * attributeModifier: [NiceAttributeRelation](https://api.atlasacademy.io/export/JP/NiceAttributeRelation.json).actor.target 53 | * criticalModifier: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).CRITICAL_ATTACK_RATE = 2 (only applies if critical, 1 otherwise) 54 | * busterChainModifier: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).CHAINBONUS_BUSTER_RATE = 0.2 if buster card in buster chain, 0 otherwise 55 | * extraCardModifier: 56 | * [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).EXTRA_ATTACK_RATE_GRAND = 3.5 if it's a color brave chain 57 | * [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).EXTRA_ATTACK_RATE_SINGLE = 2 otherwise 58 | * 1 if not extra card 59 | -------------------------------------------------------------------------------- /deeper/battle/dsl.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## Big SL and Deep SL 4 | This page will discuss other SL methods that give players a lot more chances to get good RNG rolls compared to mormal SL. 5 | 6 | ### Motivation 7 | Some TA scripts require a lot of favorable and unlikely RNG rolls to succeed. To change the outcome of a particular RNG roll, you can close the game and [advance the RNG state](../../README.md#what-affects-whether-a-card-procs-critical-hit) to get a different RNG roll. I will refer to this method as normal SL. 8 | 9 | However, normal SL has some major drawbacks. Firstly, you can only return to the state right before the RNG advancing action is taken. Secondly, you are limited to a short list of RNG advancing actions possible and if you run out of them, you will have to restart the quest. Big and Deep SL are a way to overcome these limitations. 10 | 11 | Note that both Big and Deep SL work on the unmodified game client. 12 | 13 | ### Background 14 | - The game uses the [Random](https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netframework-4.6) C# class for the RNG calculations. 15 | - The game gets [the RNG seed](https://docs.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=netframework-4.6#system-random-ctor(system-int32)) from the server and uses it to initialize the RNG. The server will return the same seed when the player resumes the quest on the same device. 16 | - The game saves the battle state in a save file stored on the device. That's why if you are [logged in on multiple devices](https://www.reddit.com/r/grandorder/comments/hfbz0h/fgo_save_files_for_na_and_jp_play_on_multiple/), you can start the quest on one device but can't resume the quest on another device at the same battle state. 17 | - The battle state is saved after major actions including but not limited to end of turn and skill use. That's why you need to close the game before those actions finish to do normal SL. 18 | - In order to restore the RNG state, the number of times the RNG has been advanced is stored in the save file. When the player resumes the quest, the game initializes the RNG using the seed from the server and [advances the RNG](https://docs.microsoft.com/en-us/dotnet/api/system.random.next?view=netframework-4.6#system-random-next) for the same number of times. 19 | - Besides the number of RNG advances, the battle state save file also stores all parameters of field entities including ATK, HP, skill cooldowns, active buffs, ... 20 | 21 | ### Big SL 22 | Big SL refers to the act of making copies of the battle state save file at different points in time and restoring them later. This allows one to return to any earlier save point instead of being limited to the moment before the latest RNG changing action. After returing to an earlier save point, one is free to try different RNG advancing actions to get different outcomes. 23 | 24 | Some actions, such as command spell usage, are not saved in the save file but sent to the server so they can't be restored using an earlier save file. 25 | 26 | ### Deep SL 27 | Deep SL goes further and edits the battle save file directly. One can edit the number of RNG advances in the save file, repackage it and resume the quest with a new RNG roll without using any in game action. Combining with big SL, this allows one a lot of freedom to try as many RNG rolls as possible. 28 | 29 | Note that with an unmodified client, Deep SL can only manipulate the number of RNG advances but not the RNG seed that comes from the server. There's no guarantee that a different number of RNG advances will be favorable. One would still need to check the game client to see if the RNG rolls succeeds. 30 | 31 | If one can record the RNG seed, either from dumping the memory or looking at the traffic, one can replicate the RNG state on another device without having to use the game client. After that, they can simply run as many RNG rolls as possible to look for a favorable number of RNG advances and edit the save file accordingly. 32 | 33 | It's also possible to edit other variables in the battle state save file. For example, one can increase the servant's attack or attack buff value to get higher damage. 34 | -------------------------------------------------------------------------------- /deeper/battle/np.md: -------------------------------------------------------------------------------- 1 | ### NP Gain 2 | 3 | [NP Gain formula](https://blogs.nrvnqsr.com/entry.php/3306-How-much-NP-do-I-get-in-combat) 4 | 5 | #### Attacking NP 6 | ``` 7 | NP% per hit = 8 | (17) Round Down( 9 | (18) Round Down( 10 | (19) offensiveNPRate 11 | (20) * (firstCardBonus + (cardNpValue * max(1 + cardMod, 0))) 12 | (21) * enemyServerMod 13 | (22) * (1 + npChargeRateMod) 14 | (23) * criticalModifier 15 | ) 16 | (24) * overkillModifier 17 | ) 18 | ``` 19 | 20 | Mapping of damage formula terms to [buff actions](buff.md): 21 | 22 | * cardMod = atkSvt.commandNpAtk - target.commandNpDef 23 | * npChargeRateMod = atkSvt.dropNp 24 | 25 | Other constants lookup: 26 | 27 | * offensiveNPRate: [NiceServant](https://api.atlasacademy.io/docs#/nice/get_servant_nice__region__servant__item_id__get).noblePhantasms.npGain 28 | * firstCardBonus, cardNpValue: 29 | * firstCardBonus: [NiceCard](https://api.atlasacademy.io/export/JP/NiceCard.json).card.order.addTdGauge 30 | * cardNpValue: [NiceCard](https://api.atlasacademy.io/export/JP/NiceCard.json).card.order.adjustTdGauge 31 | * enemyServerMod: sent from server `cache.replaced.battleInfo.userSvt.tdRate` 32 | * criticalModifier: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).CRITICAL_TD_POINT_RATE = 2 33 | * overkillModifier: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).OVER_KILL_NP_RATE = 1.5 34 | 35 | #### Defending NP 36 | 37 | ``` 38 | NP% per hit = 39 | Round Down( 40 | (25) Round Down( 41 | (26) defensiveNPRate 42 | (27) * enemyServerMod 43 | (28) * (1 + npChargeRateMod) 44 | (29) * (1 + defensiveChargeRateMod) 45 | ) 46 | * overkillModifier 47 | ) 48 | ``` 49 | 50 | Mapping of damage formula terms to [buff actions](https://api.atlasacademy.io/export/JP/NiceBuffList.ActionList.json): 51 | 52 | * npChargeRateMod = defSvt.dropNp 53 | * defensiveChargeRateMod = defSvt.dropNpDamage 54 | 55 | Other constants lookup: 56 | * defensiveNPRate: [NiceServant](https://api.atlasacademy.io/docs#/nice/get_servant_nice__region__servant__item_id__get).npGain.defence 57 | * enemyServerMod: sent from server `cache.replaced.battleInfo.userSvt.tdAttackRate` (Note that this is a different variable from the enemyServerMod in the attacking NP formula above. They are usually the same but they can be different.) 58 | * overkillModifier: [NiceConstant](https://api.atlasacademy.io/export/JP/NiceConstant.json).OVER_KILL_NP_RATE = 1.5 59 | -------------------------------------------------------------------------------- /deeper/master/README.md: -------------------------------------------------------------------------------- 1 | This folder isn't being maintained anymore. You should check the [API repo](https://github.com/atlasacademy/fgo-game-data-api) or the [Apps repo](https://github.com/atlasacademy/apps) for how the internal data is structured. 2 | 3 | - [mstBuff](mstBuff.md) 4 | - [mstFunc](mstFunc.md) 5 | - [mstSkillLv](mstSkillLv.md) 6 | - [mstSvt](mstSvt.md) 7 | - [mstSvtTreasureDevice](mstSvtTreasureDevice.md) 8 | -------------------------------------------------------------------------------- /deeper/master/mstBuff.md: -------------------------------------------------------------------------------- 1 | ## File : `mstBuff.json` 2 | This file holds buff objects. 3 | 4 | ```json 5 | { 6 | "vals": [3004, 3007, 3040], 7 | "tvals": [], 8 | "individualities": [], 9 | "ckOpIndv": [], 10 | "script": {}, 11 | "id": 218, 12 | "buffGroup": 0, 13 | "type": 74, 14 | "name": "Death Resist Up", 15 | "detail": "Increase Death resistance", 16 | "iconId": 306, 17 | "maxRate": 5000 18 | } 19 | ``` 20 | 21 | Breakdown: 22 | 23 | - `vals`: list of individualities 24 | - `tvals`: list of target individualities 25 | - `ckOpIndv`: 26 | - `script`: 27 | - `id`: buff id 28 | - `buffGroup`: 29 | - `type`: buff type, maps to `BuffList.TYPE`, used to map to buff action 30 | - `name`: buff name 31 | - `detail`: more detailed name of buff 32 | - `iconId`: 33 | - `maxRate`: used to calculate the maximum value of buff action. The effective max of additional buff is `maxRate + baseValue - baseParam`. Default value of `baseValue` is 0 and of `baseParam` is 1000. `baseValue` and `baseParam` are set when the corresponding `BuffList.ActInfo` is created. 34 | -------------------------------------------------------------------------------- /deeper/master/mstFunc.md: -------------------------------------------------------------------------------- 1 | ## File : `mstFunc.json` 2 | This file holds function objects. 3 | 4 | ```json 5 | { 6 | "vals": [219], 7 | "tvals": [], 8 | "questTvals": [], 9 | "effectList": [340], 10 | "popupTextColor": 3, 11 | "id": 706, 12 | "cond": 0, 13 | "funcType": 16, 14 | "targetType": 6, 15 | "applyTarget": 3, 16 | "popupIconId": 506, 17 | "popupText": "Death Resist\nDown" 18 | } 19 | ``` 20 | 21 | Breakdown: 22 | 23 | - `vals`: list of buff id `id` in `mstBuff` 24 | - `tvals`: list of target individualities 25 | - `questTvals`: 26 | - `effectList`: 27 | - `popupTextColor`: 28 | - `id`: function id 29 | - `cond`: 30 | - `funcType`: function type, maps to enum `FuncList.Type` 31 | - `targetType`: 32 | - `applyTarget`: 33 | - `popupIconId`: 34 | - `popupText`: 35 | -------------------------------------------------------------------------------- /deeper/master/mstSkillLv.md: -------------------------------------------------------------------------------- 1 | ## File : `mstSkillLv.json` 2 | This file holds servants' skills level details. 3 | 4 | ```json 5 | { 6 | "funcId": [358, 338, 470], 7 | "svals": ["[5000,1,-1,2600]", "[1000,1,-1,3600]", "[1000,1]"], 8 | "script": {}, 9 | "skillId": 133000, 10 | "lv": 9, 11 | "chargeTurn": 7, 12 | "skillDetailId": 133000, 13 | "priority": 0 14 | } 15 | ``` 16 | 17 | Breakdown: 18 | 19 | - `funcId`: list of functions id: `mstFunc.id`. 20 | - `svals`: list of values passed to the function objects. DataVals will process this list differently depending on function's types. Check out the DataVals class for specifics. 21 | - `script`: 22 | - `skillId`: `id` in `mstSkill` 23 | - `lv`: level of the skill 24 | - `chargeTurn`: skill cooldown 25 | - `skillDetailId`: `id` in `mstSkillDetail` 26 | - `priority`: 27 | -------------------------------------------------------------------------------- /deeper/master/mstSvt.md: -------------------------------------------------------------------------------- 1 | ## File : `mstSvt.json` 2 | This file holds Servants' (including the unplayables) and Craft Essences' data. Mostly. 3 | 4 | A Servant object would look like this : 5 | ```json 6 | { 7 | "relateQuestIds": [91600501], 8 | "individuality": [5000, 600500, 2, 105, 201, 301, 304, 1000, 2001, 2008, 2011, 2037], 9 | "classPassive": [50551], 10 | "cardIds": [3, 3, 3, 1, 2], 11 | "script": {}, 12 | "id": 600500, 13 | "baseSvtId": 600500, 14 | "name": "Jack the Ripper", 15 | "ruby": "Jack the Ripper", 16 | "battleName": "Jack", 17 | "classId": 6, 18 | "type": 1, 19 | "limitMax": 4, 20 | "rewardLv": 90, 21 | "friendshipId": 1049, 22 | "maxFriendshipRank": 10, 23 | "genderType": 2, 24 | "attri": 3, 25 | "combineSkillId": 600500, 26 | "combineLimitId": 600500, 27 | "sellQp": 5000, 28 | "sellMana": 9, 29 | "sellRarePri": 5, 30 | "expType": 25, 31 | "combineMaterialId": 5, 32 | "cost": 16, 33 | "battleSize": 2, 34 | "hpGaugeY": -250, 35 | "starRate": 255, 36 | "deathRate": 440, 37 | "attackAttri": 1, 38 | "illustratorId": 12, 39 | "cvId": 10, 40 | "collectionNo": 75, 41 | "materialStoryPriority": 1000 42 | } 43 | ``` 44 | 45 | I'll go through each line. 46 | 47 | - `relateQuestIds` : Quests relating to this Servant. Their IDs are defined here. 48 | The respective quests seem to be defined in `mstQuest.json`: 49 | ```json 50 | { 51 | "afterActionVals": [], 52 | "id": 91600501, 53 | "name": "Jack Kills Jack", 54 | "nameRuby": "", 55 | "type": 3, 56 | "consumeType": 1, 57 | "actConsume": 20, 58 | "chaldeaGateCategory": 0, 59 | "spotId": 10402, 60 | "giftId": 0, 61 | "priority": 639949, 62 | "bannerType": 0, 63 | "bannerId": 0, 64 | "iconId": 0, 65 | "charaIconId": 6005000, 66 | "giftIconId": 8, 67 | "forceOperation": 0, 68 | "afterClear": 1, 69 | "displayHours": 0, 70 | "intervalHours": 0, 71 | "chapterId": 1, 72 | "chapterSubId": 1, 73 | "chapterSubStr": "", 74 | "recommendLv": "70", 75 | "hasStartAction": 1, 76 | "flag": 0, 77 | "scriptQuestId": 0, 78 | "noticeAt": 946684800, 79 | "openedAt": 946684800, 80 | "closedAt": 1893456000 81 | } 82 | ``` 83 | - `individuality` : Traits. This actually maps to certain functions in the game code. 84 | For example, `2008` seems to stand for Servants without the Star attribute (which means immunity to Enuma Elish's Special Attack) 85 | - `classPassive` : Passive skills. IDs of skill objects defined in `mstSkill.json`, with respective details in `mstSkillDetail.json`. 86 | In this case, `50551` stands for Presence Concealment : 87 | - `mstSkill.json`: 88 | ```json 89 | { 90 | "effectList": [], 91 | "actIndividuality": [], 92 | "script": {}, 93 | "id": 50551, 94 | "type": 2, 95 | "name": "Presence Concealment A+", 96 | "ruby": "Presence Concealment ", 97 | "maxLv": 10, 98 | "iconId": 105, 99 | "motion": 101 100 | } 101 | ``` 102 | - `mstSkillDetail.json`: 103 | ```json 104 | { 105 | "id": 50551, 106 | "detail": "Increase your C. Star Drop Rate", 107 | "detailShort": "Increase your C. Star Drop Rate" 108 | } 109 | ``` 110 | - `cardIds` : Card set. Consult the following TypeScript line: 111 | ```ts 112 | enum CardType { ARTS = 1 as 1, BUSTER = 2 as 2, QUICK = 3 as 3 }; 113 | ``` 114 | - `script` : Unknown to me at the time I write this, probably be added when I know more details. 115 | - `id`, `baseSvtId` : Internal (I mean, really internal) game ID of this servant. 116 | The game refers to servants with this ID, not the ID you see in **Spirit Origin List**. 117 | The first two digits define the class. The meaning is as follows : 118 | ```ts 119 | enum ClassType { 120 | Saber = 1 as 1, 121 | Archer = 2 as 2, 122 | Lancer = 3 as 3, 123 | Rider = 4 as 4, 124 | Caster = 5 as 5, 125 | Assassin = 6 as 6, 126 | Berserker = 7 as 7, 127 | Shielder = 8 as 8, 128 | Ruler = 9 as 9, 129 | AlterEgo = 10 as 10, 130 | Avenger = 11 as 11, 131 | MoonCancer = 23 as 23, 132 | Foreigner = 25 as 25 133 | } 134 | ``` 135 | The next two digits are unique for every Servant in the same class. See [here](http://blogs.nrvnqsr.com/entry.php/3471-Internal-Servant-s). 136 | Not sure about the last two digits though. 137 | - `name`, `ruby` : Self-explanatory. If you don't know what is `ruby`, see [this Wikipedia article](https://en.wikipedia.org/wiki/Ruby_character). 138 | - `battleName` The name you see during battle, under the HP and NP bar. 139 | - `classId` : Class ID. See above. 140 | - `type` : Defines the object type. If you know C# enums, you will know which (numeral) values correspond to which type. 141 | ```cs 142 | public enum Type 143 | { 144 | NORMAL = 1, 145 | HEROINE, 146 | COMBINE_MATERIAL, 147 | ENEMY, 148 | ENEMY_COLLECTION, 149 | SERVANT_EQUIP, 150 | STATUS_UP, 151 | SVT_EQUIP_MATERIAL, 152 | ENEMY_COLLECTION_DETAIL, 153 | ALL, 154 | COMMAND_CODE 155 | } 156 | ``` 157 | - `1` is definitely a normal Servant. 158 | - `4` is an enemy, surely. It is even hardcoded : 159 | ```cs 160 | public static bool IsEnemy(int type) 161 | { 162 | return type == 4; 163 | } 164 | ``` 165 | - `6` seems to define Craft Essences. Proven here : 166 | ```json 167 | { 168 | "relateQuestIds": [], 169 | "individuality": [], 170 | "classPassive": [], 171 | "cardIds": [3, 3, 3, 3, 3], 172 | "script": {}, 173 | "id": 9400340, 174 | "baseSvtId": 9400340, 175 | "name": "Kaleidoscope", 176 | "ruby": "Kaleidoscope", 177 | "battleName": "-", 178 | "classId": 1001, 179 | "type": 6 180 | } 181 | ``` 182 | Didn't figure out other types, maybe I will when time allows. 183 | - `limitMax` : Not sure what for. 184 | > `limitMax` is usually found when drawing servants and equips 185 | 186 | _Cereal#5579_ 187 | - `rewardLv` : Doesn't seem to be used for anything. Maybe max level without grails? 188 | - `friendshipId` : Bond set ID. See `mstFriendship.json`. 189 | ```json 190 | [{ 191 | "id": 1049, 192 | "rank": 0, 193 | "friendship": 5000 194 | }, { 195 | "id": 1049, 196 | "rank": 1, 197 | "friendship": 20000 198 | }, { 199 | "id": 1049, 200 | "rank": 2, 201 | "friendship": 30000 202 | }, { 203 | "id": 1049, 204 | "rank": 3, 205 | "friendship": 32000 206 | }, { 207 | "id": 1049, 208 | "rank": 4, 209 | "friendship": 50000 210 | }, { 211 | "id": 1049, 212 | "rank": 5, 213 | "friendship": 200000 214 | }, { 215 | "id": 1049, 216 | "rank": 6, 217 | "friendship": 630000 218 | }, { 219 | "id": 1049, 220 | "rank": 7, 221 | "friendship": 970000 222 | }, { 223 | "id": 1049, 224 | "rank": 8, 225 | "friendship": 1290000 226 | }, { 227 | "id": 1049, 228 | "rank": 9, 229 | "friendship": 1695000 230 | }, { 231 | "id": 1049, 232 | "rank": 10, 233 | "friendship": -1 234 | }] 235 | ``` 236 | These are the bond amounts required each level for Jack. Note the `-1` at the end, seems to be infinity - you can't go past bond 10 (unless you're on JP, I'm documenting NA). 237 | - `maxFriendshipRank` : maximum bond levels. Seems to be 10 for servants, 0 for anything else. 238 | - `genderType` : Gender. `2` is Female. `1` is Male. `3` is... well, Astolfo has it. 239 | My theory is that these values are bitmasks and ANDed each other, representing Astolfo "having" both genders. 240 | 241 | To be continued... -------------------------------------------------------------------------------- /deeper/master/mstSvtTreasureDevice.md: -------------------------------------------------------------------------------- 1 | ## File : `mstSvtTreasureDevice.json` 2 | This file holds a pivot object linking servants and noble phantasms(treasure device). 3 | 4 | ```json 5 | { 6 | "damage":[10,20,30,40], 7 | "strengthStatus":2, 8 | "svtId":600500, 9 | "num":1, 10 | "priority":102, 11 | "flag":0, 12 | "imageIndex":0, 13 | "treasureDeviceId":600502, 14 | "condQuestId":91600501, 15 | "condQuestPhase":3, 16 | "condLv":0, 17 | "condFriendshipRank":0, 18 | "motion":50, 19 | "cardId":3 20 | } 21 | ``` 22 | 23 | Breakdown: 24 | 25 | - `damage` : Damage distribution. `damage.length` = number of hits. Each hit is `(damage[i]/sum(damage)) * np_damage`. Note: due to some data entry issues, there is a possibility of the sum of `damage` to not equal 100. In such cases, the total damage of the NP can be over 100% of the np_damage. 26 | - `strengthStatus` : Unknown 27 | - `svtId` : Servant id. See `mstSvt.json` 28 | - `num` : Unknown 29 | - `priority` : Servants can have multiple noble phantasms they have unlocked due to interludes, rank ups, story missions, etc. In such cases, the noble phantasm applied (unless set otherwise) is the noble phantasm with the highest priority. Cases otherwise include enemy servants with Extra attack as noble phantasms instead of their default one. 30 | - `flag` : Unknown 31 | - `imageIndex` : Unknown 32 | - `treasureDeviceId` : Noble Phantasm id. See `mstTreasureDevice.json` 33 | - `condQuestId` : Quest required to unlock this noble phantasm. Interludes and rank up quests can be identified by the id. `91######` = Interlude. `94######` = Rank Up. See `mstQuest.json` 34 | - `condQuestPhase` : Arrow for quest required to unlock noble phantasm. The specific arrow can be identified by `mstQuestPhase.json` 35 | - `condLv` : Unknown. Implies level required for unlock but no entires have non-zero values. 36 | - `condFriendshipRank` : Unknown. Implies bond required for unlock but no entries have non-zero values. 37 | - `motion` : Unknown 38 | - `cardId` : Card type. See following enum: 39 | ```ts 40 | enum CardType { ARTS = 1 as 1, BUSTER = 2 as 2, QUICK = 3 as 3 }; 41 | ``` 42 | -------------------------------------------------------------------------------- /images/Musashi_damage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atlasacademy/fgo-docs/4d905267350e8078f46889ab19f6fc54f564a3ed/images/Musashi_damage.png -------------------------------------------------------------------------------- /images/OK_Lancelot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atlasacademy/fgo-docs/4d905267350e8078f46889ab19f6fc54f564a3ed/images/OK_Lancelot.png -------------------------------------------------------------------------------- /images/OK_MHXA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atlasacademy/fgo-docs/4d905267350e8078f46889ab19f6fc54f564a3ed/images/OK_MHXA.png -------------------------------------------------------------------------------- /images/OK_Scathach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atlasacademy/fgo-docs/4d905267350e8078f46889ab19f6fc54f564a3ed/images/OK_Scathach.png -------------------------------------------------------------------------------- /images/taunt_1.x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atlasacademy/fgo-docs/4d905267350e8078f46889ab19f6fc54f564a3ed/images/taunt_1.x.png -------------------------------------------------------------------------------- /images/taunt_2.x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atlasacademy/fgo-docs/4d905267350e8078f46889ab19f6fc54f564a3ed/images/taunt_2.x.png -------------------------------------------------------------------------------- /images/use_big_sl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atlasacademy/fgo-docs/4d905267350e8078f46889ab19f6fc54f564a3ed/images/use_big_sl.png --------------------------------------------------------------------------------