Skip to content

Spine split increment 4: extract item-loop + character-base + self-buff phases#12

Merged
ackness merged 1 commit into
masterfrom
refactor/spine-split-4
Jun 28, 2026
Merged

Spine split increment 4: extract item-loop + character-base + self-buff phases#12
ackness merged 1 commit into
masterfrom
refactor/spine-split-4

Conversation

@ackness

@ackness ackness commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Fourth spine-split increment. Extracts 3 more injection phases from the calculate_with_data spine into inject_* free functions (explicit params, behavior-preserving):

  • inject_character_base (phase 1: class-derived base + resistance penalty)
  • inject_items (phase 2: the ~118-line equipment attribution loop — filter / Kalandra reflect / local-mod stripping / slot-bonus scaled copies; takes off_weapon_active: bool)
  • inject_self_buff_exposure_spirit (phase 4c/4c'/4d)

The item loop was the largest remaining single block. 11 injection phases now extracted across PR #8/#9/#10 + this. Remaining inline: the derivation block (303-585) + phases needing main_skill/weapon/dmg_mult locals (1b skill-mods, 1c weapon-crit), which would benefit from a CalcCtx struct — deferred.

Verification

  • cargo nextest run --workspace2092 passed / 0 failed
  • cargo fmt --check + cargo clippy -p pobr-build --all-targets -- -D warnings — clean
  • parity — zero drift: def25 84.2% / defcore 91.7% / off 77.5% / dot 59.5% @5%

…f-buff phases from spine

Fourth spine-split increment: extract 3 more injection phases into inject_* free functions
with explicit params:
- inject_character_base (phase 1: class-derived base + resistance penalty)
- inject_items (phase 2: the ~118-line equipment attribution loop — filter / Kalandra
  reflect / local-mod stripping / slot-bonus scaled copies; takes off_weapon_active: bool)
- inject_self_buff_exposure_spirit (phase 4c/4c'/4d)

Same operations, same order — pure grouping, zero behavior change. 11 injection phases now
extracted across PR #8/#9/#10 + this; the item loop was the largest remaining single block.

Verified: cargo nextest run --workspace = 2092 passed/0 failed; fmt + clippy clean; parity
zero-drift (def25 84.2 / defcore 91.7 / off 77.5 / dot 59.5 @5%).
@ackness
ackness merged commit 27171d2 into master Jun 28, 2026
@ackness
ackness deleted the refactor/spine-split-4 branch June 28, 2026 11:30
ackness added a commit that referenced this pull request Jul 17, 2026
…-list

Two narrow statmap channels for the companion defence layer (#12):

- map_minion_life_stat: translate 'MinionModifier LIST { mod = Life ... }'
  statmap payloads (e.g. Loyalty's
  support_trusty_companion_minion_life_+%_final -> Life MORE -30) into
  minion-side inner modifiers, normalising vendor 'Life' to the engine
  life-pool name 'MaximumLife'. First batch admits inner Life only
  (BASE/INC/MORE); anything else is skipped, never mis-applied.
- admit TakenFromCompanionBeforeYou through the player-buff allow-list
  (Loyalty / Wild Protector carry
  companion_takes_%_damage_before_you_from_support with
  GlobalEffect/Buff/unscalable, SkillStatMap.lua:2559-2561).
ackness added a commit that referenced this pull request Jul 17, 2026
Implements the vendor companion allies layer
(CalcDefence.lua:2961-2965 mitigation, :493-495/:525-531 EHP drain,
:3656-3663 max-hit poolProtected fold; CalcPerform.lua:3323-3370 life
pool):

- Actor::is_companion marks damageable-companion minions at spawn
  (granting skill has SkillType.Companion and not MinionsAreUndamagable);
  add_minion_from_def/session wrapper take the flag.
- spawn_minions now feeds summons the effective gem level (+N to Level
  of ... bonuses + support-granted levels, vendor
  minionLevelTable[activeEffect.level]) and appends group-scoped support
  minion payloads via map_minion_life_stat (Loyalty -30% more life).
- perform runs perform_minions before fill_mechanics (vendor computes
  minion life pools before player defence) and inject_companion_life
  writes TotalCompanionLife BASE into the player ModDb (Override-aware,
  vendor CalcPerform.lua:3364-3370).
- build_pool_state emits the 'companion' AllyLayer consumed by the
  existing shared EHP/max-hit allies machinery. The deflected-hits term
  (TakenFromCompanionBeforeYouFromDeflected x DeflectChance) is not
  modelled: no source in the 18-build corpus and the wolf-pack oracle
  pins mitigation at exactly 10 (pure hits term).

Design note: no companion actor abstraction - the existing minion actor
plus the generic AllyLayer machinery express the whole mechanic; the
only new state is one bool on Actor and one BASE mod on the player db.

Oracle pins (mercenary-tactician-wolf-pack): TotalCompanionLife 2262 =
floor(ally[44] 2938 x 1.1) x 0.7; CompanionAllyDamageMitigation 10;
<Type>TotalHitPool 3826.67 (PoBR now 3817.0 = 0.9975, remainder is the
pre-existing Mana 761.2-vs-770 gap).

Parity: huntress-spirit-walker-twister closes exactly (5x MaxHit +
TotalEHP 0.89-0.90x -> 1.00x); wolf-pack MaxHit 0.82->0.90x, ChaosMaxHit
0.72->0.80x, TotalEHP 0.74->0.83x (residual is a uniform per-type
taken-multiplier gap, not the companion layer). Baselines ratcheted:
def 425->431 @5%, 434->439 @10%; only these two builds moved in the
18-build per-cell diff.
ackness added a commit that referenced this pull request Jul 18, 2026
The #12 companion work switched summon life to monsterAllyLifeTable with
vendor floor semantics (CalcPerform.lua:1046); two minion tests still
pinned the enemy monsterLifeTable expectation and slipped through the
merge gate (the pobr-core run output was truncated by the tee log).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant