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§
Constants§
- AOE_
COEF - ATTACKS_
PER_ SEC - ATTR_
DEVIATION - 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 - BRAVERY_
BUFF_ DURATION - BRAVERY_
BUFF_ QUANTITY - BUFF_
EFF - CASTS_
PER_ SEC - CHAPTER_
POWER_ STEP - CLASS_
COUNTER_ SWING - 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 (current). Was 1.6 (2026-06-23, “too easy early, full HP”) but playtest (2026-06-29) found the bump created the opposite problem: stages 1-3..1-5 felt hard and punishing (“cleared by luck”, “barely scraped through”), while 1-7+ felt fine. The sim confirmed ch2 (=stage 1-3) already hits P/E=1.24 with min-HP 13% from the hand-made→formula transition alone, and the ch3=1.6x bump pushed ch3 (=stage 1-4) from the clean 1.30x step to a 2.09x step — creating an anomalous hump. Disabled (1.0) so the geometric 1.30x step runs cleanly through early chapters. Tune viaOVERLORD_BAL_ENEMY_EARLY_BUMP. - ENEMY_
MID_ BUMP - Mid-game enemy bump — applied only to CampaignBossFight (ch7–15).
Applied via
OVERLORD_BAL_ENEMY_MID_BUMP. At 8.0 the boss at ch7 has effective power687 × STEP^0.5 × 8 ≈ 6265vs a frozen player’s ~2121 (P/E ≈ 0.34 → ~7% first-try win rate), while an engaged player (power ~3274) has P/E ≈ 0.52 — withstop_on_lose=trueand boss-stop-on-loss retries, even a 50% single-shot rate means the free bot quickly clears it via quest-funded chest opens between attempts, while the lazy bot has no path to more power. Combined withstop_on_lose=trueon campaign boss fights and the lazy-bot strategy not retrying boss fights, this creates the hard engagement gate: freeze at 1-6, wall at the ch7 boss. Wave fights are unaffected (the bump is applied inenemy_power_scalar, not inenemy_power_for_chapter), so the global power curve stays monotone. - ENEMY_
STEP_ LATE - ENEMY_
STEP_ TAPER_ START - FIGHT_
DURATION - 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.
- K_ARMOR
- K_DODGE
- MAIN_
ATTRS_ QUANTITY - MIN_
RECEIVED_ DAMAGE_ K - Minimum
received_damagemultiplier (in /10000 units) so heavy mitigation (e.g. stackedprotection) can’t reach ≤0 → unkillable. 100 ⇒ ≤99% reduction. - MIN_
STAT_ MOD_ MULT - Floor on a stat’s
.modmultiplier inget_entity_stat, so a stacking.moddebuff (e.g.weaknesson attack,protectionon 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
- POWER_
NORM - Power-scalar normalisation. Anchors a reference character
(attack=
BASE_ATTACK, hp=BASE_HP, neutral elsewhere) atBASE_POWER, so the displayed Combat-Power integer stays on the established scale while the formula underneath isP = DPS × EHP. = 600·3000/1000 = 1800. - REGEN_
TICK_ MAX_ PCT - Default cap on per-tick combat regen, as a fraction of max HP (seed; final
from the bot-sim). The
Regeneration_rateeffect fires ~1×/s over an ~8.3sFIGHT_DURATION(~8 ticks), so this bounds a fight’s combat regen to ≈0.16×HP ⇒ ≈×1.16 EHP. The power scalar’s regen-as-EHP is derived from this same value (power_from_attrs, SC-1 fix) so display/matchmaking can’t over- rate what combat delivers — there is no separate scalar regen cap any more. - SELL_
PRICE_ COEF - SELL_
PRICE_ EXP - SPELL_
QUANTITY
Functions§
- ability_
damage_ from_ id - ability_
damage_ from_ rarity - ability_
eff - armor_k
- attr_
spread_ for_ item - attr_
spread_ random - aux_
attr_ eff - aux_
attr_ eff_ for_ item - bravery_
p_ from_ eff - buff_
uptime_ mult - Multiplicative buff/debuff factor from a proc chance
p(0..1): a buff of strengthBUFF_EFFheld for a mean uptime, stackedquantitytimes. Shared by bravery (offensive) and deceit (defensive); preserves the legacy(1 + (BUFF_EFF−1)·uptime)^quantityshape exactly. - cap_
per_ tick - Per-tick heal/damage cap:
amountbounded above bypct × 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;pctcomes from the matchingtuning()knob (regen|hot|dot_tick_max_pct). - character_
attrs_ power - The
attrs_powerterm ofcharacter_power: char-level attributes, inventory items and pet stats composed into anAttrMapand run throughpower_from_attrs— WITHOUT the trailing* ability_eff_summultiplier. - character_
power - references. The previous version accepted either real essences structs (the into these typed inputs and then calls this exact function — so results are byte-identical on both paths.
- character_
power_ from_ attrs - Combat-power scalar from an already-composed
AttrMapplus equipped abilities —floor(power_from_attrs(attrs) × Σ ability_eff). - class_
counter_ multiplier - Soft 3-cycle damage multiplier for an
attackerclass hitting adefenderclass (bothOption, resolved vialookups.class_counter_role). Returns1 + CLASS_COUNTER_SWINGwhen the attacker’s role beats the defender’s,1 - CLASS_COUNTER_SWINGwhen it is beaten, and1.0otherwise (same role, either neutral, or a classless PvE mob). - class_
counter_ role_ from_ code - 3-cycle combat role from a class’s
main_attributecode. 0 = Warrior, 1 = Rogue, 2 = Mage, -1 = neutral. - day_
by_ level - deceit_
p_ from_ eff - eff_
by_ level - eff_
item_ with_ config - eff_
spell_ by_ level - effect_
cost - effect_
duration - enemy_
power_ for_ chapter - Absolute enemy power at
chapter:ANCHOR · ∏ step(c), where the per-chapter step is the constantchapter_power_stepuntilenemy_step_taper_start, then decays smoothly towardenemy_step_lateso 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 formANCHOR · 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_wavefeeds into the HP/attack curve, and the apples-to-apples counterpart of the player’scharacter.power(both normalized toBASE_POWER). For campaign fights: at/below the anchor chapter it is the hand-authoredFightTemplate.power(base_power); 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-difficultybase_power(see below). Shared so the battle-end analytics report exactly the value the fight spawned. - 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).
- item_
q_ by_ day - level_
by_ day - mean_
fight_ duration - power_
from_ attrs - Compute character power from a composed
AttrMapas P = DPS × EHP (balance v2).DPSis the offensive product (attack · rate · crit · multicast · bravery · counterattack);EHPthe survivability product (hp ÷ the damage that gets through), where armor and dodge use the diminishing-returns curvesarmor_kandev/(ev+K_DODGE). Normalised byPOWER_NORMso a reference character (attack=BASE_ATTACK, hp=BASE_HP, neutral elsewhere) anchors atBASE_POWER. Replaces the legacy opaqueS²-style formula; every factor maps 1:1 to the old one except armor and evasion, which move from a linear cap to a DR curve. - rand_
round_ f64 - Pure: stochastic round of a non-integer value.
- 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 (Phase 2). Pure + sim-tunable viatuning(); the call site isbehaviors::items::item_price. - tuning
- The process-wide balance tuning (defaults until
init_tuningis called). Hot-path safe — an atomic load of a&'static.
Type Aliases§
- AttrMap
- Ordered attribute accumulator used by
power_from_attrs/character_power.