mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 08:52:42 +00:00
N4/E1: second pet slot for the Tier-4 Estate
An Established (Tier-4) home can draw a second companion. Both pets show up on the sheet and the town showcase, level via babysitting, and wear their own barding (!thom pet2buy <tier>). Combat: both pets contribute their attack/deflect/whiff procs at half weight — DerivePlayerStats now averages over the active pets, so a pair reads as roughly one full pet (flavor-forward, not a stat spike; difficulty-neutral). The average reduces to identity over a single pet (x/1==x, 0.0+x==x, 3+(2L+1)/2==3+L), and the engines still roll one proc per channel per round, so the single-pet path and TestCombatCharacterization golden stay byte-identical. Pinned by TestDerivePlayerStats_OnePetIsByteIdentical + the golden. Scope kept deliberately flavor-forward: pet 2 carries identity/level/barding and the three combat procs only. The morning-defense buff, death/ditch-recovery save, and the level-10 supply-shop unlock stay pet-1 mechanics — no second defensive multiplier stacks, and the one-pet path is untouched by construction. Storage: parallel pet2_* columns on player_meta + Pet2* mirror on AdventureCharacter (absent == no second pet, DEFAULT '' correct for every pre-existing row, no backfill — the N2-temper / P4-party precedent). Pet-1 code paths are untouched. Arrival reuses the chase/feed/type/name DM flow, slot-aware, gated HouseTier>=4 with an established first pet. Review fixes folded in (high-effort /code-review, 3 angles): pet-2 barding block no longer hidden when pet-1 is chased away; showcase tie-break restored (level desc, then name); petGrantXP collapsed onto the shared level-up helper; dead-param armor-buy wrappers inlined; pet-2 barding tagged with its own euro ledger reason. Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
This commit is contained in:
@@ -157,12 +157,33 @@ func DerivePlayerStats(
|
||||
}
|
||||
}
|
||||
|
||||
// Pet modifiers
|
||||
// Pet modifiers. Two pets each contribute at half weight — the combat mods
|
||||
// are an average over the active pets, so a pair reads as roughly one full
|
||||
// pet (flavor-forward, not a stat spike). A lone pet averages over one
|
||||
// element, so x/1==x and 0.0+x==x reproduce the former values exactly,
|
||||
// keeping the single-pet combat golden byte-identical. The engines roll one
|
||||
// attack/deflect/whiff off these mods per round regardless of pet count, so
|
||||
// the RNG draw order is unchanged too.
|
||||
pets := make([]struct{ level, armor int }, 0, 2)
|
||||
if char.HasPet() {
|
||||
mods.PetAttackProc = petAttackChance(char.PetLevel)
|
||||
mods.PetAttackDmg = 3 + char.PetLevel // per-attack variance added in engine
|
||||
mods.PetDeflectProc = petDeflectChance(char.PetLevel, char.PetArmorTier)
|
||||
mods.PetWhiffProc = 0.01 + float64(char.PetLevel)*0.005
|
||||
pets = append(pets, struct{ level, armor int }{char.PetLevel, char.PetArmorTier})
|
||||
}
|
||||
if char.HasPet2() {
|
||||
pets = append(pets, struct{ level, armor int }{char.Pet2Level, char.Pet2ArmorTier})
|
||||
}
|
||||
if n := len(pets); n > 0 {
|
||||
var atk, defl, whiff float64
|
||||
levelSum := 0
|
||||
for _, pt := range pets {
|
||||
atk += petAttackChance(pt.level)
|
||||
defl += petDeflectChance(pt.level, pt.armor)
|
||||
whiff += 0.01 + float64(pt.level)*0.005
|
||||
levelSum += pt.level
|
||||
}
|
||||
mods.PetAttackProc = atk / float64(n)
|
||||
mods.PetDeflectProc = defl / float64(n)
|
||||
mods.PetWhiffProc = whiff / float64(n)
|
||||
mods.PetAttackDmg = 3 + (levelSum*2+n)/(2*n) // 3 + rounded average level
|
||||
}
|
||||
if char.PetMorningDefense {
|
||||
mods.DamageReduct *= 0.95 // 5% less damage
|
||||
|
||||
Reference in New Issue
Block a user