Resonant Battles growth settings[ | ]
The internal level of all thieves and guardians is the highest level of the player's units in the team, plus a value (lv_offset*
) that depends on the player's Interval and chosen battle difficulty:
Interval | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Beginner | -8 | -8 | -7 | -7 | -6 | -6 | -5 | -5 | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Intermediate | -4 | -4 | -3 | -3 | -2 | -2 | -1 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
Advanced | 0 | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
For example, entering a Resonant Battle at Advanced difficulty with a Lv. 40 team on Interval 21 results in an internal level of 56. Enemy stats are then calculated from their base stat values and growth rates. After that, thief stats are corrected as follows:
- The HP stat is multiplied by 150%. (
multiplier
) - The Def/Res stats are raised to 50% of the unit's internal level if they are lower than that. (
min_final_growth
) - A random bonus between 0 and 3 (inclusive) is added to every stat. (
random_add
)
Guardian stats are corrected as follows:
- The HP and Atk stats are multiplied by 150%.
- The Def/Res stats are raised to 75% of the unit's internal level if they are lower than that.
- A random bonus between 0 and 3 (inclusive) is added to every stat.
Random skills[ | ]
Training Tower, Tempest Trials, and Allegiance Battles may equip random skills on units.
Game mode | Heroes | Enemy units | ||
---|---|---|---|---|
When random skills may be filled | Random skill pool | When random skills may be filled | Random skill pool | |
Training Tower | Never ~ always (2nd Stratum and below never equip non-weapon skills, 10th Stratum always equip all skills) | Skills owned by the Hero in that category, plus skill on the corresponding unit from the base map (at Normal difficulty), if its tt_inherit_base is true (10th Stratum only), promoted according to derived map rules; all skills with random_mode == 1 if this pool has no legal skills
|
Never ~ often (2nd Stratum and below never equip non-weapon skills) | All skills with random_mode == 1
|
Tempest Trials | When the Hero owns any skill from that category (it seems empty slots are also filled at above LV.40) | Skills owned by the Hero in that category; all skills with random_mode == 1 if this pool has no legal skills
|
N/A | N/A |
Allegiance Battles | When the Hero does not own a skill at their rarity, otherwise the Hero equips that skill; Assists are never filled | All skills with random_mode == 1
|
All non-Assist skills may be filled | All skills with random_mode == 1
|
Only legal skills from the random pool may be equipped. This means:
- The unit must be able to inherit the skill normally;
- The unit's level is between
skill_definition::min_lv
andmax_lv
; random_allowed
is non-zero;random_mode
is 1 or 2.
Heroes do not own evolved and refined weapons; additionally, random Heroes cannot equip any weapons they do not already own (note that weapon skills never have tt_inherit_base
set).
Growth percentages[ | ]
The game internally stores growth rates of all Heroes and generic units as percentages. Only multiples of 5% are ever used; however, growth rates are defined for growth percentages that are not multiples of 5 (this has been verified by a debugger). The growth percentage is multiplied by an additional rarity factor:
1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|
0.86 | 0.93 | 1.00 | 1.07 | 1.14 |
The truncated result produces the following master growth table:
GP | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
-4 | 0 | 0 | 0 | 0 | 0 |
-3 | 4 | 4 | 5 | 5 | 5 |
-2 | 8 | 9 | 10 | 10 | 11 |
-1 | 12 | 13 | 15 | 16 | 17 |
0 | 17 | 18 | 20 | 21 | 22 |
1 | 21 | 23 | 25 | 26 | 28 |
2 | 25 | 27 | 30 | 32 | 34 |
3 | 30 | 32 | 35 | 37 | 39 |
4 | 34 | 37 | 40 | 42 | 45 |
5 | 38 | 41 | 45 | 48 | 51 |
6 | 43 | 46 | 50 | 53 | 57 |
7 | 47 | 51 | 55 | 58 | 62 |
8 | 51 | 55 | 60 | 64 | 68 |
9 | 55 | 60 | 65 | 69 | 74 |
10 | 60 | 65 | 70 | 74 | 79 |
11 | 64 | 69 | 75 | 80 | 85 |
12 | 68 | 74 | 80 | 85 | 91 |
13 | 73 | 79 | 85 | 90 | 96 |
This table is used directly for the randomization of stat growth tables (see below). Stat growth values can be derived from this table by GrowthValue = trunc(0.39 × GrowthPercent)
, or directly calculated by GrowthValue = trunc(0.39 × trunc((GrowthPoint × 5 + 20) × (0.79 + 0.07 × Rarity)))
.
Enemy stats for derived maps[ | ]
Certain game modes (Chain Challenge, Squad Assault, Blessed Gardens) derive their maps from existing story / paralogue maps. Chain Challenge scenarios use base maps at their respective difficulties, whereas the other two game modes always use base maps at Lunatic. Their stats are determined as follows:
- First, if the unit's rarity is increased, then the usual base stat changes for playable Heroes apply, using the base stats defined in either
hero_definition
orenemy_definition
. - Each stat is increased by
trunc((newGP × (newLv - 1) - oldGP × (origLv - 1)) ÷ 100)
, whereorigLv
is the unit's original level,newLv
≥origLv
is the new level,oldGP
is the growth percentage at the unit's old rarity, andnewGP
≥oldGP
is the growth percentage at the new rarity. Levels above 40 are defined as follows:
Game mode Difficulty Levels Chain Challenge Lunatic, single-chapter Story 40/41/42/43/45 Hard, double-chapter Story 40/40/41/41/43/42/42/43/43/45 Lunatic, double-chapter Story 45/45/46/46/48/47/47/48/48/50 Lunatic, single-chapter Paralogue 40/42/45 Hard, double-chapter Paralogue 40/41/43/42/43/45 Lunatic, double-chapter Paralogue 45/46/48/47/48/50 Squad Assault Lunatic 50/50/50/50/50 Blessed Gardens Lunatic 45 Infernal 50 Blessed Grounds Odd-numbered Grounds 45 Even-numbered Grounds 50 Tempest Trials Lunatic, Lv. 40 40/41/42/43/44/45/45
- A few special cases:
- If only the level is changed, the formula reduces to
trunc(GP × (newLv - origLv) ÷ 100)
. - If only the rarity is changed, the formula reduces to
trunc((newGP - oldGP) × (Lv - 1) ÷ 100)
. - If both rarity and level are unchanged, no stat boosts occur at this stage.
- If only the level is changed, the formula reduces to
- The HP of all enemies is further calculated as
trunc(HP × HPFactor)
, whereHPFactor
is a global multiplier that depends only on the game mode:
Game mode Difficulty HP factor Chain Challenge Normal, single-chapter 1.1 Hard, single-chapter 1.2 Lunatic, single-chapter 1.3 Normal, double-chapter Story 1.1 for first half, 1.2 for second half Hard, double-chapter Story 1.2 for first half, 1.3 for second half Lunatic, double-chapter Story 1.3 for first half, 1.4 for second half Normal, double-chapter Paralogue 1.1 Hard, double-chapter Paralogue 1.2 Lunatic, double-chapter Paralogue 1.3 Squad Assault Lunatic 1.3 Blessed Gardens Normal 0.8 Hard 0.8 Lunatic 1.1 Infernal 1.5 Blessed Grounds Odd-numbered Grounds 1.1 Even-numbered Grounds 1.5 Tempest Trials Normal, Lv. 8 0.90/0.90/0.90 Normal, Lv. 14 0.90/0.90/0.95 Normal, Lv. 20 0.95/0.95/1.00 Hard, Lv. 25 1.00/1.00/1.00/1.05 Hard, Lv. 30 1.00/1.00/1.05/1.05/1.10 Lunatic, Lv. 35 1.00/1.05/1.10/1.15/1.20 Lunatic, Lv. 40 1.00/1.05/1.10/1.15/1.20/1.25/1.30
- Skills are promoted as follows:
- While
skill_definition::next_skill
points to a valid skill name, and the unit's rarity is higher than or equal toskill_definition::promotion_rarity
, the current skill is replaced byskill_definition::next_skill
; this continues until no more promotions can be made. Skills are never demoted, and promotion takes place even if the unit's rarity does not change between the base map and the derived map. Empty skill slots in the base map are never occupied in derived maps. - Additionally, only skills with
skill_definition::promotion_tier
nonzero and also less than or equal to a per-map tier are allowed to promote. Currently this tier number is always 1 on scenarios for derived maps, so Staff weapons, Assists, and Specials are never promoted (see table below). - Slight deviations occur for weapon promotion depending on whether the unit is a Hero or an enemy:
- If a Hero owns the original weapon skill, and the
promotion_tier
check passes, their default weapon at the new rarity is chosen. - If an enemy unit is at 5 and its
enemy_definition::top_weapon
refers to a valid weapon skill, that skill is chosen, regardless of itspromotion_tier
value, and regardless of which original weapon skill the unit has (unless it didn't have a weapon).
- If a Hero owns the original weapon skill, and the
- While
(Random enemy stats, like those in Tempest Trials and Training Tower, have not been determined. HP factors for Tempest Trials are shown for convenience.)
next_skill
exists if and only if the skill is inheritable, not a Sacred Seal, and both promotion_rarity
and promotion_tier
are nonzero. The table below lists the skill types that have canonical upgrades:
Skills | promotion_rarity | promotion_tier | next_skill |
---|---|---|---|
Rank 1 non-staff weapons | 3 | 1 | Corresponding rank 2 weapon |
Rank 2 non-staff weapons | 4 | 1 | Rank 3 weapon with same effect and higher Might |
Rank 3 non-staff weapons (excluding generic beast weapons e.g. Adult (Flier)) | 5 | 1 | Corresponding rank 4 weapon |
Rank 1 staff weapons ( Assault) | 3 | 2 | Fear |
Rank 2 staff weapons | 5 | 2 | Corresponding rank 3 weapon |
Rank 1 staff Assists ( Heal) | 3 | 2 | Mend |
Rank 2 staff Assists ( Mend, Reconcile) | 4 | 2 | Recover and Martyr respectively |
Rank 3 staff Assists | 5 | 2 | Corresponding rank 4 Assist |
Rank 1 offensive / defensive Specials | 4 | 2 | Rank 2 Special with stronger effect but same cooldown count (e.g. New Moon → Luna |
Rank 1 Passives (excluding single-rank skills e.g. Lunge) | 4 | 1 | Corresponding rank 2 Passive |
Rank 2 Passives | 5 | 1 | Corresponding rank 3 Passive |
Growth vectors[ | ]
The file Common/SRPG/Grow.bin.lz
contains the seemingly random growth vectors used in the game. The decompressed file contains 2496 XOR-encrypted 64-bit little-endian bit vectors starting from address 0x30
, where the n-th bit indicates whether a given stat should increase when the hero reaches level n. An example of reading the vectors directly from the binary file:
#!/usr/bin/env ruby
# this cipher is hardcoded inside libcocos2dcpp.so and appears exactly once
CIPHER = [0x0C, 0xE6, 0xBB, 0x0C, 0x1D, 0x0F, 0x1E, 0xA8]
File.open(File.join('Common', 'SRPG', 'Grow.bin'), 'rb') do |f|
f.seek 0x30
(39 * 64).times do |vec_id|
bytes = f.read(8).bytes
bytes_xor = bytes.zip(CIPHER).map {|x, y| x ^ y}
bits = Array.new(64) {|i| bytes_xor[i / 8][i % 8]}
puts vec_id.to_s + ': ' + bits.join
end
end
For example, Brave Lyn's neutral growth vectors are: (the used portions are shown in boldface)
Stat | Vector | ID |
---|---|---|
HP | 00100011 01100010 10110110 11100100 01001100 10000000 00000000 00000000 |
29 |
Atk | 00011111 11001111 01110110 10101101 10101110 00000000 00000000 00000000 |
26 |
Spd | 00001111 00110111 01011101 11111110 11010100 10000000 00000000 00000000 |
39 |
Def | 00001010 00000000 01110010 00111111 00010000 00000000 00000000 00000000 |
00 |
Res | 00011111 00001110 01110010 10011101 01110100 10000000 00000000 00000000 |
33 |
Here ID is the lowest 6 bits of the vec_id
field, as there are 64 possible variations for each stat growth amount between 1 and 39. This growth vector ID, together with the growth amount determined by the hero's rarity and the stat's GP, uniquely identifies the growth vector used by that stat. It is possible to infer missing entries from the complete stat tables as long as exactly one out of 64 variations correlates with the given entries, or even guess the vector ID if one or two of the given stats are incorrect.
Growth vector IDs change with the hero's IVs: (they warp around 00-63)
Hero | Rarity | Variation | HP | Atk | Spd | Def | Res |
---|---|---|---|---|---|---|---|
Lyn: Brave Lady | 5 | Bane | 23 | 20 | 33 | 58 | 27 |
Lyn: Brave Lady | 5 | Neutral | 29 | 26 | 39 | 00 | 33 |
Lyn: Brave Lady | 5 | Boon | 35 | 32 | 45 | 05 | 38 |
the hero's rarity:
Hero | Rarity | Variation | HP | Atk | Spd | Def | Res |
---|---|---|---|---|---|---|---|
Olivia: Blushing Beauty | 1 | Neutral | 41 | 20 | 38 | 31 | 35 |
Olivia: Blushing Beauty | 2 | Neutral | 44 | 23 | 42 | 34 | 38 |
Olivia: Blushing Beauty | 3 | Neutral | 48 | 27 | 47 | 38 | 42 |
Olivia: Blushing Beauty | 4 | Neutral | 51 | 30 | 51 | 41 | 45 |
Olivia: Blushing Beauty | 5 | Neutral | 54 | 34 | 55 | 45 | 49 |
and a single byte (hero_definition::base_vector_id
) from the structs under Common/SRPG/Person
that hold hero data:
Hero | Rarity | Variation | BVID | HP | Atk | Spd | Def | Res |
---|---|---|---|---|---|---|---|---|
Robin: High Deliverer | 5 | Neutral | 43 | 15 | 53 | 60 | 03 | 56 |
Robin: Mystery Tactician | 5 | Neutral | BF | 11 | 49 | 56 | 63 | 52 |
Lucina: Future Witness | 5 | Neutral | C2 | 22 | 02 | 15 | 57 | 46 |
Marth: Enigmatic Blade | 5 | Neutral | 12 | 38 | 18 | 31 | 09 | 62 |
Deriving growth vector IDs[ | ]
Growth vector IDs can be calculated as the sum of the following terms, keeping only the 6 lowest bits (i.e. modulo 64):
- 3 × (5-star level 1 neutral base stat);
- A constant offset depending on the stat being calculated for, which increases "randomness":
HP Atk Spd Def Res -35 -28 -21 -14 -7
- The growth percentage corresponding to the Hero's rarity and the stat's GP;
- The hero's base vector ID (
hero_definition::base_vector_id
). It is currently unknown if the highest 2 bits are computationally meaningful since the modulo operation discards them.
Brave Lyn's base vector ID is 0x9D
. The growth vector IDs for her neutral stats can be computed as follows:
- HP: (3 × 16 + (−35) + 51 + 157) mod 64 = 221 mod 64 = 29
- Atk: (3 × 7 + (−28) + 68 + 157) mod 64 = 218 mod 64 = 26
- Spd: (3 × 9 + (−21) + 68 + 157) mod 64 = 231 mod 64 = 39
- Def: (3 × 5 + (−14) + 34 + 157) mod 64 = 192 mod 64 = 0
- Res: (3 × 6 + (−7) + 57 + 157) mod 64 = 225 mod 64 = 33
This matches her vector IDs given at the top. This has been verified to match all pre-existing 5-star stat tables on this wiki.
Identical stat growths[ | ]
Due to the modulo operation it is theoretically possible that two completely different stats on the same hero use the same growth vector: (currently this is limited to HP/Atk base being 7 higher than Def/Res and GPs being the same)
Hero | Stat A | Base | GP | Stat B | Base | GP | GVID | Growth Vector |
---|---|---|---|---|---|---|---|---|
Chrom: Gifted Leader | Atk Flaw | 11 | 8 | Res Asset | 6 | 8 | 1 | 01100110 11000111 11100001 11110110 11111101
|
Tiki: Dragon Scion | HP Flaw | 14 | 7 | Def Neutral | 8 | 7 | 22 | 00101111 01111011 00111100 01010110 10111100
|
Tiki: Dragon Scion | HP Neutral | 15 | 8 | Def Asset | 9 | 8 | 28 | 01001001 11000111 10110011 11111101 11110110
|
Out-of-bound growth rates[ | ]
After rarity correction, if the growth rate is 0%, the stat uses a fixed growth vector, regardless of the Hero's base vector ID:
01100000 11001111 10111010 01100001 01110001
This is in fact the XOR cipher used for the growth vectors (see example code above). Because the growth vector files does not store empty vectors, it is possible that the game is accessing memory before the list of growth vectors; if it reads zeroes, the resulting growth vector is simply the XOR value itself. It is also possible that, depending on the Hero's base vector ID, the game may read the file's HSDArc header instead of zeroed memory.
If the growth rate is 100% or above, the integral part is applied to every level up, and the fractional part uses the growth vector mechanism as above. Growth rates can never be below 0%.