Reverse-engineering notes · Digimon UP (com.bandainamcoent.dgup_ww) · client v1.1.1 WW

Stat & Combat Formula Reference

How GameData.json's 117 tables actually get consumed by the Unity/IL2CPP client — extracted by dumping libil2cpp.so + global-metadata.dat and reading the compiled ARM64 for the stat-aggregation and damage-calculation routines directly.

Confirmed Inferred Data-only read against the disassembly / matched by strong naming & structural evidence / from GameData.json alone, application point not yet traced

01 Method

Two independent sources were cross-referenced against each other rather than trusted alone.

The data. assets/GameData.json is the full server-authored design database — 117 tables (Stat, CombatPower, BuffStat, ItemStat, RuneStat, SoulStat, TrainingStatRate, ArenaCorrectionStat, Skill, Buff, Character…). This tells you what numbers exist, but not how they combine.

The code. This is a Unity IL2CPP build: there is no C# IL to decompile, only ARM64 machine code plus a metadata file that names every class, field and method. libil2cpp.so was pulled from the arm64-v8a split APK and paired with global-metadata.dat; a metadata-v39-compatible build of Il2CppDumper (compiled from an open PR that adds Unity 6 support) reconstructed every class/field/method signature with its address. From there, the specific routines that touch stats and damage were disassembled by hand with Capstone and read instruction-by-instruction.

So: table shape and field names below come from the metadata dump directly (fully reliable). Arithmetic — what gets added, multiplied, clamped, and in what order — comes from reading the actual machine code of those routines, which is why it's marked Confirmed rather than guessed from variable names.

02 Data architecture

117 tables total. The ones that feed the stat/combat pipeline:

TableRowsRole
Stat93Named stat presets — each row is a full 54-stat bundle ("Attack:130", "CriticalRate:0.5"…), referenced by key from CharacterStat.
CharacterStat52Per-character link: which Stat row is the base, which is the per-level curve, which is the per-grade curve.
Character295Roster (playable Digimon + monsters): name, grade, evolution/tribe/attribute type, points at a CharacterStat row.
CombatPower52Per-stat weight used to compute the displayed CP number.
ItemStat / ItemParts330 / 523Gear stat rolls.
RuneStat / Rune87 / 216Rune stat rolls and rune definitions.
SoulStat / Soul46 / 77Soul (accessory-ish system) stat rolls.
BuffStat / Buff747 / 740In-battle buff/debuff stat modifiers and their carriers.
PossessionBuffStat / PossessionBuff496 / 447Passive "possession" bonuses (support-slot style permanent buffs).
TrainingStatRate297Training-system stat gain rates by grade.
ArenaCorrectionStat3Flat % correction applied in PVP context only.
EvolutionLevel / EvolutionCharacter99 / 90Evolution-form stat/behaviour changes.
Skill598Skill definitions (coefficients not yet traced — see §10).
ExpInfo150Level curve.

03 The stat system

Every character/monster carries exactly one array of 54 stats (E_STAT, confirmed against the metadata enum, byte-identical to the names used throughout GameData.json). Each stat is one of three storage kinds — this classification comes straight out of the compiled GetStatType(E_STAT) switch, which is a plain 3-way range check on the enum's integer value:

Decimal — raw values (0–2)

  • Attack
  • Defense
  • HP

Float — raw values (3–4)

  • AttackSpeed
  • MoveSpeed

Percent — stored as a 0–1 fraction (5–53)

  • AttackBonus / DefenseBonus / HPBonus / AttackSpeedBonus / MoveSpeedBonus
  • CriticalRate, CriticalDamage(+Resist), SkillCritical…
  • ComboRate, CounterRate, StunRate, EvadeRate, AirborneRate (+ their …Decrease pairs)
  • Reduction (universal flat mitigation, see §06)
  • Normal/Skill/Combo/Counter/Pet/Boss Damage & …Reduction pairs
  • Normal/Combo/Counter/Critical/Skill/Pet …Amplify & …AmplifyDecrease pairs
  • HPRecovery, HPRegenRate, HPRegenValue

Only 49 of the 54 stats are Percent-type — meaning almost the entire kit of combat modifiers (crit, damage bonuses, reductions, amplifies, rates) is one uniform fraction system. Attack/Defense/HP are the only "big number" stats; speed stats are a separate small-number system that doesn't feed Combat Power at all (see §05).

04 Stat aggregation confirmed

Read from CharacterInfoStat.CompleteStat(), RVA 0x18EE2A8. Every character holds 11 parallel 54-float arrays — one per source — and the "live" stat pool is just their sum.

Base character's innate stats
+
Item equipped gear
+
Rune socketed runes
+
Soul souls
+
Possession passive support-slot bonuses
+
Training training system
+
DimensionalBoxDeco collection/decoration bonuses
= "Growth" — the permanent build total this is what Combat Power reads
+
Evolution current evolution form's modifiers
+
Buff active in-battle buffs/debuffs
+
Edit debug/GM override, unused in live play
= "All" — the live stat pool used in battle

Every layer is plain float addition, stat-by-stat, with no weighting or scaling between sources. One point of Attack from a Rune adds exactly as much as one point of Attack from Training or a Possession buff — including for Percent-type stats, which just add their fractions directly (two +5% CriticalDamage rolls make +10%, not a compounded 1.05×1.05). There is no separate multiplicative "gear multiplier" or "buff multiplier" step anywhere in this routine.

CompleteStat() — the two summing loops, as read from ARM64 RVA 0x18EE2A8
Growth.Clear(); All.Clear(); for layer in [Base, Item, Rune, Soul, Possession, Training, DimensionalBoxDeco]: for stat in 0..<54: Growth[stat] += layer[stat] // fadd, plain float add for layer in [Growth, Evolution, Buff, Edit]: for stat in 0..<54: All[stat] += layer[stat] this.combatPower = ComputeCombatPower(Growth) // see §05 — reads Growth, not All

05 Combat Power confirmed

The helper CompleteStat() calls immediately after summing (RVA 0x18EE430) — this is what fills the CP number on the character screen.

For every stat s in the 54-stat array, using the Growth layer only:
value = Growth.get(s)
skip if value == 0
displayValue = isPercent(s) ? value × 100 : value
skip if s has no row in the CombatPower table
contribution = round( displayValue × CombatPower[s].Value )

CombatPower = Σ contribution (accumulated as a 64-bit integer)
  • CP is computed from Growth, not All — it deliberately excludes the current Evolution form's stat changes and any active Buffs. A Digimon that leans on a strong evolved form or heavy self-buffing will read weaker on the CP screen than it fights.
  • Only 52 of the 54 stats have a weight. MoveSpeed and MoveSpeedBonus are the two stats absent from the CombatPower table — investing in movement speed is CP-invisible (and, per the damage formula in §06, has no other combat payoff either — it's purely a clear-speed/QoL stat).
  • Percent stats are converted to "percentage points" (×100) before weighting, so a CriticalRate of 0.5 (50%) is weighted as 50, not 0.5 — this is why rate/damage% stats can carry meaningful CP despite being stored as small fractions.

Practically: because every one of the 52 weighted stats is summed with a fixed, public per-stat weight (right there in the CombatPower table), CP is close to a genuine linear power index of the permanent build — not just marketing fluff — as long as you're comparing builds that don't lean on Evolution/Buff layers or MoveSpeed. Use the table itself as your master stat-weight sheet — and try it live in the Calculators tab.

06 Damage formula confirmed

The full pipeline, traced across three routines: SimulateDamageInfo.DamagePreProcess() (RVA 0x1BDEB04), BattleDamageProcessor.GetTypeDamage() (RVA 0x1BCDA14), and SimulateDamageInfo.CriticalProcess() (RVA 0x1BDEE60). One hit runs through four independent multiplier stages in sequence — Defense → Type → Boss → Critical — each gated by its own condition, which is what lets them combine.

6.1 — Defense mitigation (the base hit)

D₁ = D² / (D + Defense)
D = the raw hit value going in (attacker's Attack × whatever skill coefficient produced it — not yet traced, see §10)
Defense = target's Defense stat

A smooth diminishing-returns curve, not a flat subtraction: at Defense = 0 the hit lands for full D; at Defense = D it's cut exactly in half; beyond that it keeps shrinking asymptotically but never hits zero. This whole stage is skipped entirely — D passes through unchanged — if the hit carries the TrueDamage attribute flag (fixed/true damage, e.g. execute effects or DoTs that are meant to ignore Defense).

Working hypothesis for D screenshot-supported: AttackBonus is the one stat in the entire 54-stat sheet that never shows up anywhere in the confirmed §06/§07 chain — it's not consumed by Defense mitigation, any of the five type multipliers, the Boss axis, or Critical. That makes it the strongest remaining candidate for exactly where it does apply: turning base Attack into the raw hit, i.e. D = Attack × (1 + AttackBonus). A real Character Info screenshot backs this up: its "Combined ATK" ÷ "Basic ATK" ratio matched 1 + AttackBonus% to within 0.02%, and the same relationship held for DEF and HP against their own Bonus stats (HP matched to 4 significant figures) — see the Calculators tab's In-game style readout, built to replicate that exact screen for further comparison. Still not independently confirmed by disassembling the function that actually computes "Combined" stats, but this is now good empirical evidence rather than a guess from naming alone.

6.2 — Type multiplier (which "kind" of hit this is)

Every hit is tagged with attribute flags (E_DAMAGE_ATTR) set elsewhere in the attack pipeline. DamagePreProcess reads them in a fixed priority order to decide which of the five types to run through GetTypeDamage():

PriorityCondition checkedType applied
1attackerType == PetDigiMonPet = in-game "Support" + flat ×(1+NormalDamage) stacked on top
2attr has Counter flagCounter
3attr has Combo flagCombo
4attr has SkillAttack flagSkill + an extra per-skill coefficient if one was staged (consumed once, then cleared)
5— (default)Normal

This is a single if/elseif chain — a hit is exactly one of Normal/Skill/Combo/Counter for this stage, never two at once (a hit can't be "Combo" and "Skill" simultaneously here). The one exception is PetDigiMon attackers, who get two layers at once: their own Pet-type multiplier and the standard Normal-attack damage bonus, both applied to the same hit — a support unit's autoattack is mechanically a normal attack with an extra Pet-specific layer bolted on.

GetTypeDamage(type, D₁) = D₁ ×
( 1 + max(0, atk.Amplify def.AmplifyDecrease def.Reduction) )
× ( 1 + max(0, atk.TypeDamage def.TypeDamageReduction) )

Both brackets floor at 0 — a defender's resist can cancel an attacker's bonus down to a ×1.0 no-op, never negative. def.Reduction (stat 26) is hardcoded into every type's amplify term — the one defensive stat that blunts all hit types at once, where the paired …DamageReduction stats are single-type.

TypeAmplifyAmplify decreaseType damageType reduction
NormalNormalDamageAmplify…AmplifyDecreaseNormalDamageNormalDamageReduction
SkillSkillDamageAmplify…AmplifyDecreaseSkillDamageSkillDamageReduction
ComboComboDamageAmplify…AmplifyDecreaseComboDamageComboDamageReduction
CounterCounterDamageAmplify…AmplifyDecreaseCounterDamageCounterDamageReduction
PetPetDamageAmplify…AmplifyDecreasePetDamagePetDamageReduction

6.3 — Boss multiplier (a separate axis, not a sixth type)

BossDamage/BossDamageReduction are not part of the type dispatch above — they key off a completely different question, checked independently of whatever type the hit already resolved to:

  • Attacking a boss (IsBossCharacter(targetType) is true): damage ×= (1 + attacker.BossDamage). This stacks on top of the type multiplier from §6.2, whichever type that was — Normal, Skill, Combo, Counter, all of them.
  • Being attacked by a boss (attacker's E_CHARACTER_TYPE == Boss): incoming damage /= (1 + target.BossDamageReduction), applied right after the Defense-mitigation stage (§6.1), before the type multiplier.

Symmetric by design: BossDamage is your offense stat for hitting boss-flagged targets, BossDamageReduction is your defense stat for surviving boss-flagged attackers — they never both apply to the same hit (you're either fighting a boss or you're not).

6.4 — Critical multiplier (also a separate axis)

Rolled and applied in a distinct function from the type dispatch, gated only by whether the hit carries the SkillAttack flag — not by Combo/Counter/Pet:

Hit carries…Crit roll succeeds whenCrit multiplier
SkillAttack flagatk.SkillCriticalRate > roll1.5 + max(0, atk.SkillCriticalDamage − def.SkillCriticalDamageResist)
anything else (Normal, Combo, Counter, Pet)atk.CriticalRate > roll(1.5 + max(0, atk.CriticalDamage − def.CriticalDamageResist)) × (1 + max(0, atk.CriticalDamageAmplify − def.CriticalDamageAmplifyDecrease))

On success, the final chained damage value is multiplied by that crit multiplier and the Critical attribute flag is stamped onto the hit (that's the flag that drives the crit VFX/number-color in the UI). On failure, nothing changes.

Directly answering the questions above: Yes, Combo and Counter hits can critically hit — and Pet/Support hits too — all three roll against plain CriticalRate/CriticalDamage, the exact same pair Normal attacks use. Only hits flagged SkillAttack get diverted to the separate SkillCriticalRate/SkillCriticalDamage pair. Critical, Boss, and the five-way type multiplier are three independent axes that all chain multiplicatively onto the same hit — a Combo hit against a boss that also crits runs Defense-mitigation × Combo-type-multiplier × Boss-multiplier × Crit-multiplier, all four, in one number. The only thing that's mutually exclusive is which single type (Normal/Skill/Combo/Counter) gets picked in §6.2 — Pet is the one attacker type that gets two type-layers instead of one.

Full chain, as actually computed
let D = // raw hit value, pre-Defense (base Attack × skill coefficient — not yet traced) if attr.has(TrueDamage): return D // bypasses everything below D = D² / (D + target.Defense) // §6.1 Defense mitigation if attacker.type == Boss: D /= (1 + target.BossDamageReduction) // §6.3 incoming boss mitigation D = GetTypeDamage(resolvedType, D) // §6.2 — Normal / Skill / Combo / Counter (/ +Pet) if IsBossCharacter(target.type): D ×= (1 + attacker.BossDamage) // §6.3 outgoing boss bonus if crit roll succeeds: // §6.4 D ×= critMultiplier

07 Defense-side mechanics confirmed

§06 covers what happens to a hit once it's already landing. This is everything around that: whether it lands at all, and what it lands on — traced from SimulateDamageInfo.CheckDamageEvade() (RVA 0x1BDE880), SimulateDamageInfo.ApplyDamage() (RVA 0x1BDF290), and the generic proc-roll helper CCProcess() (RVA 0x1BDF6B4).

7.1 — Evade (rolled before Defense mitigation even runs)

Evade succeeds when: target.EvadeRate − attacker.EvadeRateDecrease > random(0,1)

A dodged hit deals 0 damage — the whole §06 chain never runs. Counter-flagged hits are hardcoded to skip the evade check entirely — a Counter attack cannot be evaded, full stop, no matter how much EvadeRate the original attacker has stacked. Every other hit type (Normal, Skill, Combo, Pet) can be evaded.

7.2 — Shield absorbs before HP

ApplyDamage() takes a shield value by reference alongside current HP, and always drains it first:

  • If shield > incoming damage: the shield fully absorbs the hit. shield −= damage, HP is untouched, and the hit gets tagged with the Shield attribute flag (that's what drives the "blocked" VFX).
  • If shield ≤ incoming damage: the shield is fully consumed (set to 0) and only the overflowdamage − shield — carries through to reduce HP.

Healing runs through the same function on the opposite sign, and is clamped so it can never push current HP past the target's HP stat (i.e. max HP) — no overheal beyond the stat sheet.

7.3 — Crowd control & proc rolls share one shape

CCProcess(damageInfo, rateStat, decreaseStat, key) is a generic, reusable roll: it reads an attacker rate stat and a defender decrease stat, rolls against a seeded PRNG, and on success applies whatever status effect key identifies. The comparison is structurally identical to Evade, just with the roles reversed (attacker's rate is what's trying to succeed, rather than the defender's):

Proc succeeds when: attacker.Rate − defender.RateDecrease > random(0,1)

This is confirmed as the shape used for Stun/Airborne procs, and — because the function is generic over which stat pair gets passed in — is very likely the same mechanism behind whether a hit becomes a Combo or Counter in the first place (i.e. ComboRate/ComboRateDecrease and CounterRate/CounterRateDecrease feeding this same roll), though the exact call site wiring those two in wasn't individually located.

Order of operations for one attack, start to finish: Evade roll (§7.1, skipped for Counter hits) → §06's four-stage damage chain (Defense → Type → Boss → Critical) → Shield absorption → HP reduction (§7.2). Rate-vs-decrease-vs-random is the one recurring shape across Evade, Stun, Airborne, and (very likely) Combo/Counter proc — the whole game's "does this special thing happen" question keeps coming back to the same formula with different stat pairs plugged in.

08 PVP correction data-only

The full ArenaCorrectionStat table — only 3 rows, no other PVP-only stat table exists:

StatCorrection
Attack+20%
Defense+0%
HP−10%

The consuming function wasn't traced, but the shape of the data is unambiguous — this is a flat percentage correction applied only inside Arena/PVP, and only to the three raw Decimal stats. Attack is pushed up, HP is pulled down, Defense is untouched. Treat as a strong directional signal (PVP favors offense over stacking HP relative to PVE) rather than exact-formula confirmed.

09 What this means for a tier list

  • Stat sources are fungible. Since aggregation is pure addition with no per-source scaling, you can build a single "effective stat budget" per character (Base+Item+Rune+Soul+Possession+Training+DimensionalBoxDeco) and compare characters on that budget directly — a flat +50 Attack rune and a +50 Attack training roll are worth identically as much.
  • The CombatPower table is your master weight sheet for a first-pass power score — it's a real, confirmed, per-stat linear formula, not a black box. Pull the full 52-row table to rank "how much is 1 point of stat X worth" — or just watch it update live in the Calculators tab.
  • CP will misrank buff-and-evolution-reliant kits. Anything whose power spikes mid-fight (self-buffs, a strong evolved form) is invisible to CP but very real in the §06 damage formula once All (not Growth) is what's actually fighting.
  • Diminishing returns are real but local, not global. Amplify/TypeDamage stats are only as good as what the opposing Reduction/AmplifyResist can't already cancel — against a low-Reduction PVE mob they're close to free damage; against a high-Reduction PVP defender or a tuned boss, the same points can be entirely absorbed. A tier list should weight raw Attack/base-damage output higher for boss/tank matchups and Amplify/TypeDamage stacking higher for squishier PVP/Tower targets.
  • Reduction (stat 26) is the best single defensive stat to itemize on a survival-focused build — it's the only stat that discounts all five hit types simultaneously, where the …DamageReduction pairs are single-type.
  • Defense follows a diminishing curve (D²/(D+Defense)), not a flat subtraction. A defender needs Defense roughly equal to the incoming hit just to halve it — against a Digimon with low raw Attack, modest Defense goes a long way; against a hard-hitting glass cannon it barely registers. Tanky-tier rankings should weigh Defense relative to the attack power of the content being ranked against, not as a flat number.
  • Critical is one universal system, not five. Combo, Counter, and Pet(Support) hits all crit off the exact same CriticalRate/CriticalDamage/CriticalDamageAmplify stats as Normal attacks — only Skill-flagged hits use a separate SkillCritical* pair. A kit built around triggering lots of Combos/Counters gets full value from generic Crit investment; you don't need "Combo crit" gear, it doesn't exist as a separate system.
  • Boss stats are a pure bonus axis, not a type. BossDamage stacks multiplicatively on top of whatever type multiplier (Normal/Skill/Combo/Counter) and crit result a hit already got — so for boss-heavy content (raids, Tower bosses) it's additive value on top of your existing kit, not a competing investment. BossDamageReduction is the mirror stat for surviving boss-type attackers specifically.
  • Pet/Support units double-dip. A PetDigiMon's hits get both the Pet-type multiplier and the flat Normal-damage bonus stacked on the same hit — meaning both PetDamage and NormalDamage investment benefit a support unit's own auto-attacks, not just PetDamage alone.
  • Counter builds don't need Evade investment to land — but they also can't be evaded when they're the ones attacking, which is a real, quantifiable edge over Combo/Normal follow-ups against high-EvadeRate PVP defenders.
  • MoveSpeed/MoveSpeedBonus have zero combat or CP value in everything traced so far — purely a clear-speed/QoL stat, safe to deprioritize entirely in a combat-effectiveness ranking.
  • PVP skews offense. The +20% Attack / −10% HP arena correction (§08) means a build optimized by raw CP (which is PVE-neutral) won't be the PVP-optimal build — arena tier rankings should discount HP-heavy budgets relative to PVE/Tower rankings.

10 Open questions

What would sharpen this further, roughly in order of payoff for a tier list:

  1. The raw hit value D that Defense mitigation (§6.1) starts from. Leading hypothesis: D = Attack × (1 + AttackBonus)AttackBonus is the only stat that never appears in the confirmed §06/§07 chain, so this is where it's most likely spent (see the callout in §6.1). For Skill hits there's almost certainly an additional per-skill coefficient on top (the Skill table, or the per-hit "extra float slot" seen consumed in the Skill branch of §6.2) that hasn't been traced yet. The Damage Calculator has both a manual D field and a one-click button for the AttackBonus hypothesis so you can sanity-check it against observed in-game numbers.
  2. Skill coefficients — the 598-row Skill table almost certainly carries per-skill multipliers/scaling-stat references; these decide how hard a given Digimon's kit actually hits independent of its stat sheet.
  3. Exactly which stat pair feeds Combo/Counter proc rolls — §7.3 confirms the generic CCProcess(rate, decrease, key) shape and its use for Stun/Airborne, but the specific call site wiring ComboRate/CounterRate into it wasn't individually pinned down.
  4. Buff condition triggers (BuffCondition, 34 rows) — what procs what, relevant for combo/counter-heavy kits.
  5. Rune/Soul/Item roll ranges — the *Stat tables define possible rolls; worth pulling min/max per grade for a proper gearing tier list.

Happy to keep going on any of these — the tool chain (patched Il2CppDumper + Capstone disassembly script) is already set up and reusable.

Extracted from com.bandainamcoent.dgup_ww v1.1.1 (WW build) · libil2cpp.so metadata version 39 · analysis for personal/educational build-strategy research.