Module balance

Source
Expand description

Functions and constants here mirror the original balance.yaml script, which contained the project’s fundamental combat and economic balance formulas. Content-dependent lookups (item rarity quality, ability rarity effectiveness, fixed-power items) are sourced from ContentLookups, which is populated at engine init time by reading the content_raw module’s data maps.

Structs§

AbilityCombatProfile
Combat-honest contribution of one slotted ability to the power scalar.
BalanceTuning

Enums§

EnemyCurveMode
Which formula enemy_power_for_chapter uses.

Constants§

ABILITY_MILESTONES
Ability upgrade milestones: on top of the linear +5%/level, levels 5 and 10 grant a multiplicative jump — a proximate milestone that makes the dup-shard chase eventful instead of a flat drip. UNIVERSAL for every ability (gacha, class kits, pet ults) — no per-content flags; tooltips (ability_info(level)) and the honest power scalar recompute automatically because everything routes through ability_eff. Sizing: ×1.10 at L5 ≈ two extra linear levels, ×1.20 at L10 ≈ four — noticeable, but small enough that the shard economy absorbs it.
AOE_COEF
ATTACKS_PER_SEC
INCOMING enemy hits/s on the player — prices counterattack (the scalar term and the item roll are FD-invariant: FD cancels, only this rate matters). Deliberately independent of CASTS_PER_SEC — the player’s cast rate says nothing about enemy attack rate. Derivation: combat schedules each mob’s next cast at current_tick + scaled_cooldown (logic/fighting.rs), so a mob attacks every cd — mob basic attacks run cd 1.0-1.7s (typ. 1.4 ⇒ ~0.7 atk/s). Campaign waves hold a median 5 mobs, declining as they die (time-avg attackers ≈ 2.5, further shaved by approach/spawn delays): ≈ 2.5 × 0.7 ≈ 1.8 hits/s. Boss fights run lower (single attacker) — this is the campaign-mix weight.
ATTR_DEVIATION
ATTR_DEVIATION_LEVEL_ONE
Level-1 rolls use a wider deviation than the 2..=25 band: level-1 stat values are tiny integers, so ±10% would be flattened by flooring and every roll of the single early template per (rarity, slot) cell came out a clone of the scripted starters.
AUX_ATTR_IMPACT
BALANCE_TUNING_DEFAULT
Tuning with every knob at its constant default.
BASE_ATTACK
BASE_CRIT_CHANCE
BASE_CRIT_MOD
BASE_HP
BASE_POWER
BASE_SPEED
BASE_SPELL_EFF
BOSS_ENCOUNTER_COEF_SQ
One total normalized encounter coefficient for every boss on every chapter, FTUE included: sqrt(1.30). It covers the WHOLE encounter budget including a potential summon wave — adds never get a second sqrt(1.30) on top. Hand-authored per-chapter boss ratios and the legacy ch12/13/14 bumps are removed: no chapter through ch21 may read as a wall.
BOSS_OUTGOING_EQUIVALENCE_KNOTS
A2-BAL-001 frozen outgoing-equivalence correction after removal of the automatic boss stun. These are measured D_old / D_unstunned ratios from the signed reference matrix, not a reconstructed duty-cycle formula: boss kits contain both Attack-derived and flat payloads, so only the complete deterministic trace can preserve the previously shipped outgoing budget.
BRAVERY_BUFF_DURATION
BRAVERY_BUFF_QUANTITY
BUFF_EFF
CASTS_PER_SEC
PLAYER cast rate (casts/s) — prices the bravery/deceit on-cast proc uptime (buff_uptime_mult*). Near-honest for a filled loadout: ~6 slotted abilities at cd 2-6s + class basic at cd 1s ⇒ Σ1/cd ≈ 1.5-2.5 casts/s.
CHAPTER_POWER_STEP
CLASS_MAX_RANK
CLASS_RANK_PAYLOAD_STEP
Payload multiplier of a CLASS ability at rank: ×[1.0, 1.1, … 1.6] over ranks 1..=7 (BAL-034).
COUNTERATTACK_POWER
DECEIT_DEBUFF_DURATION
DECEIT_DEBUFF_QUANTITY
DMG_K
DOT_TICK_MAX_PCT
EFF_A1
EFF_A2
EFF_B1
EFF_B2
EFF_C1
EFF_C2
EFF_MIDGAME_LEVEL
ENEMY_CURVE_ANCHOR_CHAPTER
ENEMY_CURVE_ANCHOR_POWER
ENEMY_EARLY_BUMP
Early-game stat-check bump strength. 1.0 = OFF, deliberately: the hand-made→formula transition already lands the early chapters taut on its own, and playtesting showed a bump here makes stages 1-3..1-5 feel punishing (“cleared by luck”) — so the geometric step runs cleanly through the early game instead. Tune via OVERLORD_BAL_ENEMY_EARLY_BUMP.
ENEMY_MID_BUMP
Mid-game enemy bump — applied only to CampaignBossFight, over the ch12–14 window (see [enemy_mid_chapter_mult]). Applied via OVERLORD_BAL_ENEMY_MID_BUMP. stage2-bridge (2026-07-16) lowered it 8.0 → 2.5 and moved the window off the stage-2 boundary: at 8.0 the gate slammed ×5.67/×4.89 onto the ch10/ch11 bosses — the first stage-2 fights — an instant wall for a fresh-ladder player exiting the new easy stage 1. The legacy ch7 rationale is moot (ch0-9 is hand-authored now, the gate never fired there). At 2.5 the gear-check is a boss EMPHASIS (bot boss-win ~0.9 at ch12-14, vs wave ~1.0) landing mid-bridge where the wave curve is comfortable, not a wall; a frozen (non-gearing) player is already walled by the wave curve. Wave fights are unaffected (the bump is applied in enemy_power_scalar, not in enemy_power_for_chapter), so the global power curve stays monotone. stage2-bridge CYCLE 2 (2026-07-16): lowered 2.5 → 1.3 for the casual re-pacing test — a gentle ch12-14 boss emphasis (at-cadence boss ~80% win) rather than a gear-check, so no chapter reads as a wall. The smooth cadence-ramped wave curve now carries all the difficulty shaping.
ENEMY_STEP_LATE
ENEMY_STEP_TAPER_START
E_BASE_KNOTS
Smooth early E_base calibration through chapter 45. The knots only bridge FTUE and the first-hour feature/power ramp; after chapter 45 one universal geometric multiplier owns the entire campaign tail (see e_base).
FIGHT_DURATION
Ability-budget window (seconds) — the measured length of a typical campaign fight (weighted median from battle-end telemetry; win-only fights run longer). It is a WEIGHT in the ability-damage budget (eff·FD/(FD+cd)·cd, combat AND scalar — the two share the primitive, so they cannot desync) and in the regen/HoT-as-EHP conversion. The counterattack term and the item counterattack roll are FD-invariant (FD cancels in their ratios — only ATTACKS_PER_SEC prices them). Changing this constant re-scales ability damage and the honest scalar together, so it requires the full coderive recalibration cycle (η + growth knots), same as any scalar-changing edit.
HAND_AUTHORED_CHAPTER_MAX
Highest 0-based current_chapter_level at which enemy_power_scalar resolves campaign enemy power from the hand-authored FightTemplate.power (base_power) instead of the derived chapter curve. Set to 9 so the ENTIRE first stage (levels 0..=9 = stages 1-1..1-10) is hand-authored onboarding difficulty: the coderived curve AND the ch7-15 mid-boss gear gate do NOT apply inside stage 1 (the gate still starts at ch10 = stage 2-1).
HEAL_COEF
HOT_TICK_MAX_PCT
Per-tick caps for HoT/DoT effects, as a fraction of max HP — safety so a mis-tuned ability effect can’t out-heal all damage (HoT) or one-shot (DoT). Generous (these are ability-derived, already bounded by ability balance); the cap only catches pathological values. Seed; sim-calibrated.
ITEM_XP_BREAK_LEVEL
ITEM_XP_COEF
ITEM_XP_EXP
ITEM_XP_LATE_EXP
K_ARMOR
K_DODGE
K_HP_KNOTS
Multiplier on encounter HP, checked against the player’s DPS.
K_OUT_KNOTS
Multiplier on enemy outgoing damage, checked against the player’s EHP. See K_HP_KNOTS — same shape, same default, the other axis.
LEVEL_ONE_ATTR_MEAN
Mean of the level-1 attribute spread — level-1 items are deliberately weak (the scripted starters and the first chest drops share it).
MAIN_ATTRS_QUANTITY
MIN_RECEIVED_DAMAGE_K
Minimum received_damage multiplier (in /10000 units) so heavy mitigation (e.g. stacked protection) can’t reach ≤0 → unkillable. 100 ⇒ ≤99% reduction.
MIN_STAT_MOD_MULT
Floor on a stat’s .mod multiplier in get_entity_stat, so a stacking .mod debuff (e.g. weakness on attack, protection on received_damage) can’t drive a stat to ≤0 (zero-damage / unkillable). 0.05 ⇒ ≤95% debuff. Only bites at mod ≤ −9500; no-mod / buff stats are unaffected.
OT_COEF
PET_ULT_EFFECTIVE_CD
Expected seconds between pet-ult casts for the honest scalar. The pet ult is charge-gated, not cooldown-gated (charge_rate_on_skill_use / _on_damage_dealt / _on_damage_taken fill max_charge), so its template cooldown says nothing about throughput. With the shipped charge profiles (max_charge 1000, rates 5-40 per trigger) a fight fills the bar roughly once per ~12s of combat — a deliberate round number until a sim remeasure; the pet’s per-cast budget divided by this is the honest DPS/heal rate.
PLAYER_GROWTH_KNOTS
Reference player (free archetype) honest power per chapter — sparse calibration knots (chapter, power).
POWER_NORM
Power-scalar normalisation. Anchors a reference character (attack=BASE_ATTACK, hp=BASE_HP, neutral elsewhere) at BASE_POWER, so the displayed Combat-Power integer stays on the established scale while the formula underneath is P = DPS × EHP. = 600·3000/1000 = 1800.
REGEN_PERCENT_CODE
Share of MAX HP an entity regenerates per second, in permyriad (100 = 1%/s). BAL-034 gives the regen class a specialization that keeps meaning something as HP pools grow: a flat rate authored for early gear is noise by the time a player has ten times the HP.
REGEN_TICK_MAX_PCT
Cap on per-tick combat regen, as a fraction of max HP. The Regeneration_rate effect fires ~1×/s, so over a FIGHT_DURATION fight this bounds combat regen to ≈0.5×HP ⇒ ≈×1.5 EHP at the cap. The power scalar’s regen-as-EHP is derived from this same value (power_from_attrs) so display/matchmaking can never over-rate what combat delivers — there is deliberately no separate scalar regen cap.
RHO_TARGET_KNOTS
Designed pressure profile — sparse knots, geometric interpolation. THE designer-editable difficulty curve: raise a knot to make that zone easier (player further ahead), lower it for pressure.
SELL_PRICE_COEF
SELL_PRICE_EXP
SPELL_QUANTITY
S_REF_KNOTS
Early analytic S_ref seed for FTUE and first-hour diagnostics. Runtime difficulty after FTUE is authored by E_base; no second hand-written reference ladder exists beyond the universal-tail anchor.
WAVE_DAMAGE_SKEW
WAVE_HP_SKEW
ZONE_DIFFICULTY_KNOTS
Zone difficulty correction z(ch): how much harder (>1) or easier (<1) a chapter’s content plays than the honest per-fight scalar P/E predicts. The corrected ratio ρ̂ = P/(z·E) is a sufficient statistic for winrate: its 50%-crossing is ≈0.55 in EVERY zone (the stat-check contract “come with power” needs the ratio to mean the same thing everywhere).

Functions§

ability_combat_profile
Combat-honest profile of one ability instance. Uses the per-ability content::ability_info split where one exists; abilities without a bespoke closure (some class/buff abilities) fall back to a pure-damage assumption at their eff × FD/(FD+cd) throughput — the closest honest default.
ability_damage_from_id
ability_damage_from_rarity
ability_eff
ability_power_mults
Aggregate the equipped abilities into the two power-axis multipliers: (dps_mult, ehp_mult).
ability_profile_from_info
Pure split of an crate::mechanics::content::AbilityInfo budget into the (dps_add, heal_add) axes. Separated from the config lookup so the arithmetic is unit-testable without prod ability UUIDs.
armor_k
attr_spread_for_item
attr_spread_random
aux_attr_eff
aux_attr_eff_for_item
axis_multiplier
Shared reader for both axes: log-space interpolation between sparse knots, held flat outside them, identity when unauthored.
boss_outgoing_equivalence
bravery_p_from_eff
buff_uptime_mult
Multiplicative buff/debuff factor from a proc chance p (0..1): a buff of strength BUFF_EFF held for a mean uptime, stacked quantity times. Preserves the legacy (1 + (BUFF_EFF−1)·uptime)^quantity shape exactly.
buff_uptime_mult_branches
Honest two-branch pricing for bravery/deceit: a proc picks RANDOMLY between an offensive branch (empower/vulnerability = ×1.5 in power terms) and a defensive one (protection/weakness = ×0.5 damage/attack ⇒ ×2.0 in power terms) — each branch runs at HALF the proc uptime. A single-EFF shape would under-value the defensive branch ~25% at high uptime. Power is DPS×EHP, so the combined factor applies wherever the caller multiplies it in.
cap_per_tick
Per-tick heal/damage cap: amount bounded above by pct × max_hp. Used by the regen / HoT / DoT combat ticks so a mis-tuned effect can’t out-heal all incoming damage (regen/HoT) or one-shot (DoT). Pure + testable; pct comes from the matching tuning() knob (regen|hot|dot_tick_max_pct).
character_attrs_power
The attrs_power term of character_power: char-level attributes, inventory items and pet stats composed into an AttrMap and run through power_from_attrs — WITHOUT the trailing * ability_eff_sum multiplier.
character_attrs_power_raw
character_attrs_power before the floor, for callers that RANK loadouts rather than display a number. See power_from_attrs_raw for why the integer is unusable as a sort key.
character_power
Character power over the items+pets subset (marginal gear-compare path and arena-bot power): composed attrs → power_from_attrs → honest ability multipliers (ability_power_mults, DPS/EHP-split).
character_power_from_attrs
Combat-power scalar from an already-composed AttrMap plus equipped abilities — floor(power_from_attrs(attrs) × dps_mult × ehp_mult) with the honest ability multipliers (ability_power_mults).
character_power_from_attrs_raw
character_power_from_attrs before the floor — the P_static term of P_ui = floor(P_static × Πq) (BAL-030).
class_rank_payload_mult
compose_character_attrs
Compose the char-level + items + pets attribute map (the input to power_from_attrs) plus the summed per-item power_bonus jitter. Extracted from character_attrs_power so character_power can reuse the composed attrs for the honest ability EHP cap (it needs hp/attack).
day_by_level
deceit_p_from_eff
e_base
Unrounded E_base(ch) across the whole ladder.
eff_by_level
eff_item_with_config
eff_spell_by_level
effect_cost
effect_duration
enemy_boss_power
Boss encounter power at chapter, floored once at the end.
enemy_power_derived
The derived-mode curve G(ch)/(ρ̂(ch)·z(ch)), or None when the calibration tables are not baked — callers fall back to legacy. ρ̂ is the zone-corrected pressure target and z the zone difficulty correction; their product is the raw-scalar pressure the curve implements.
enemy_power_for_chapter
Absolute enemy power at chapter: ANCHOR · ∏ step(c), where the per-chapter step is the constant chapter_power_step until enemy_step_taper_start, then decays smoothly toward enemy_step_late so late-game difficulty tracks the player’s decelerating power (no multi-day stalls). With the taper OFF (enemy_step_late >= chapter_power_step) this is the original closed form ANCHOR · STEP^(chapter − ANCHOR_CH). A tapering early-chapter bump (see [enemy_early_chapter_mult]) multiplies the result.
enemy_power_scalar
Enemy “power” scalar for a fight — the value spawn_wave feeds into the HP/attack curve, and the apples-to-apples counterpart of the player’s character.power (both normalized to BASE_POWER). For campaign fights: at/below HAND_AUTHORED_CHAPTER_MAX (the whole first stage) it is the hand-authored FightTemplate.power (base_power) with NO mid-boss gate; above it the rebalanced geometric curve (enemy_power_for_chapter, which carries the sweepable anchor/step + the early-chapter bump), with a boss bump. For DUNGEON fights it is always the authored per-difficulty base_power (see below). Shared so the battle-end analytics report exactly the value the fight spawned.
enemy_wave_power
Ordinary wave power at chapter, floored once at the end. There is no chapter-specific wall layer: the smooth base curve is the whole scalar.
get_attr_from_attrs
attrs.get_attr(name): read the composed attribute value from an attribute map. Returns (base + bonus) * (1 + bonus / 10000.0).
hp_k_for_chapter
hp_k_for_level
init_tuning
Set the process-wide balance tuning once at startup (first call wins).
interp_geometric
Geometric (log-linear) interpolation over sparse (chapter, value) knots: exact at knots, constant before the first, final-segment ratio extrapolation past the last (the measured late slope continues — the treadmill contract’s “progress never fully stops” shape).
item_experience
Character XP paid by selling one item, from the item’s snapshot character level and its quality multiplier quality (the rarity axis M).
item_q_by_day
k_hp
K_HP(ch). 1.0 while the table is unauthored.
k_out
K_OUT(ch). 1.0 while the table is unauthored.
level_by_day
optional_attributes_for_chest_level
A2-BAL-003 §3.3: how many optional stats a chest of this level rolls.
pet_ult_combat_profile
Combat-honest profile of a pet ult: the pet’s ability carries the donor gacha ability’s per-cast budget (combat behaviors hardcode the donor uuid), but fires at the charge-fill rate, not at the template cooldown — so the throughput divides the per-cast budget by PET_ULT_EFFECTIVE_CD.
player_armor_rating_deflator
Player armor-rating deflator for character level (see BalanceTuning::armor_k_per_chapter; level ≈ chapter for players and is available for arena OPPONENT snapshots too, keeping PvP symmetric): multiply the aggregated player armor rating by this before it meets the constant-K DR curve.
power_from_attrs
Compute character power from a composed AttrMap as P = DPS × EHP (balance v2). DPS is the offensive product (attack · rate · crit · multicast · bravery · counterattack); EHP the survivability product (hp ÷ the damage that gets through), where armor and dodge use the diminishing-returns curves armor_k and ev/(ev+K_DODGE). Normalised by POWER_NORM so a reference character (attack=BASE_ATTACK, hp=BASE_HP, neutral elsewhere) anchors at BASE_POWER.
power_from_attrs_raw
power_from_attrs before the floor.
rand_round_f64
Pure: stochastic round of a non-integer value.
sell_gold
BAL-008 sale price: round(G0 × eff_level(snapshot)^α × M_quality).
sell_price
Item sale price (sell-currency units) from an item’s effectiveness eff: floor(eff^sell_price_exp · sell_price_coef). Sub-linear (exp < 1) so gold income grows ~linearly with item level and the geometric chest sink can bind. Pure + sim-tunable via tuning(); the call site is behaviors::items::item_price.
sell_price_with_config
Item sale price with the exponent/coefficient sourced from GameConfig (game_settings.sell_price_{exp,coef}). Per-knob precedence: OVERLORD_BAL_SELL_EXP / OVERLORD_BAL_SELL_COEF env override (sim sweep) > GameConfig value (Some) > the compiled SELL_PRICE_EXP / SELL_PRICE_COEF constants. With env unset and both config knobs None this is bit-identical to sell_price (the pre-config behavior), so deploying the config with the current constant values leaves every price unchanged. Call site: behaviors::items::item_price.
tuning
The process-wide balance tuning (defaults until init_tuning is called). Hot-path safe — an atomic load of a &'static.
zone_difficulty
Zone difficulty correction z at chapter (see ZONE_DIFFICULTY_KNOTS).

Type Aliases§

AttrMap
Ordered attribute accumulator used by power_from_attrs / character_power.