diff --git a/data/spells/divine_favor.json b/data/spells/divine_favor.json index ee6f363..365fc00 100644 --- a/data/spells/divine_favor.json +++ b/data/spells/divine_favor.json @@ -6,6 +6,16 @@ "save": "none", "base_dc": 10, "cast_time": "standard", - "effects": [], - "description": "You draw upon divine power for 1 round/level: a +1 luck bonus on attack rolls and weapon damage per 4 caster levels. Simplified: the engine has no luck-bonus self-buff that preserves the pinned default-policy casting order, so no mechanical effect is applied." + "effects": [ + { + "type": "buff", + "modifiers": [ + { "target": "attack", "value": 1, "bonus_type": "luck" }, + { "target": "damage", "value": 1, "bonus_type": "luck" } + ], + "duration_rounds": 10, + "scaling_flat": { "amount": 1, "per_levels": 3, "max": 2 } + } + ], + "description": "SRD spells/divine-favor.md: evocation, level 1 (cleric/inquisitor/oracle/paladin/warpriest), range personal, duration 1 minute. You gain a +1 luck bonus on attack and weapon damage rolls, +1 for every three caster levels (at least +1, maximum +3). The bonus does not apply to spell damage - the engine's 'damage' modifier target only rides weapon damage rolls, so that clause holds by construction. Duration 1 minute = 10 rounds." } diff --git a/tests/test_pc_combat_golden.py b/tests/test_pc_combat_golden.py index b4b4983..5743c9c 100644 --- a/tests/test_pc_combat_golden.py +++ b/tests/test_pc_combat_golden.py @@ -63,81 +63,69 @@ class TestGoldenCombats: "Pistol" now matches her pistol names ("... (pistolet ?)"), so every pistol attack gains the +1 feat bonus. - Updated again by the SRD shield-of-faith fix (data/spells/ - shield_of_faith.json now carries its real +2 deflection AC buff): - _find_buff_spell returns the FIRST buff spell in her known-spell - order, and Shield of Faith (list index 30) precedes Bull's Strength - (index 46) — so the policy's buff pick is now Shield of Faith. + Updated again by the SRD spell-effect fixes (shield of faith and + divine favor now carry their real buffs): _find_buff_spell returns the + FIRST buff spell in her known-spell order, and Divine Favor (list + index 20) precedes Shield of Faith (30) and Bull's Strength (46) — so + the policy's buff pick is now Divine Favor. Line-by-line: - - rounds 1-4 tammara: "cast Shield of Faith ... DC14 SAVED -> buff 1 - mods (10r)" — DC 14 = 10 + spell level 1 + her +3 Wis; the deflection - buff does not stack with itself, so the re-casts just refresh it. She - has four level-1 slots, so the buff phase now runs rounds 1-4 (the - old Bull's Strength phase ran rounds 1-3 on three level-2 slots). - - rounds 1-10 goblin: "AC 22" (was 20) — the +2 deflection raises her - AC; the goblin's d20=15+4-2=17 shot still misses. - - rounds 5-10 tammara: "d20=10+9-6=14 AC 16 -> MISS" — out of level-1 - slots she shoots; without Bull's Strength's +2 enhancement attack - bonus the scripted d20=10 shot totals 14, below the goblin's AC 16. - - "battle over: draw after 10 rounds": the goblin is never dropped - within the round cap. This is a default_policy first-match heuristic - artifact (Shield of Faith is a legitimate SRD buff, just a - defensively-picked one), not an SRD regression. + - rounds 1-4 tammara: "cast Divine Favor vs tammara DC14 NO SAVE -> + buff 2 mods (10r)" — save "none" (SRD: personal, no save), so no d20 + is consumed by the cast; the +1 luck attack / +1 luck weapon-damage + buff scales +1 per three caster levels (level 4 -> +2/+2), luck not + stacking with itself so the re-casts just refresh it. Four level-1 + slots cover rounds 1-4 (the old Bull's Strength phase ran rounds 1-3 + on three level-2 slots). + - rounds 1-5 goblin: the un-consumed save rolls shift the scripted + dice queue — the goblin's shots alternate d20=10/15 (+4-2 range), + 12/17 vs her unchanged AC 20: all MISS. + - round 5 tammara: out of level-1 slots she shoots; the Divine Favor + +2 luck on attack and weapon damage reproduces the old Bull's + Strength totals: d20=10+9-6=16 meets AC 16 -> HIT 17 damage, goblin + 6 -> -11 (below its -CON death threshold). + - "goblin down" + "players win in 5 rounds": the goblin dies one round + later than before (four level-1 buff casts instead of three + level-2 casts). """ result, _ = run_golden("tammara") - assert result.winner is None - assert result.rounds == 10 + assert result.winner == "players" + assert result.rounds == 5 assert result.transcript == ( "initiative: tammara d20=15+7=22", "initiative: goblin d20=10+6=16", - ("round 1 tammara: cast Shield of Faith vs tammara DC14 SAVED " - "-> buff 1 mods (10r) (36->36)"), - "round 1 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 2 tammara: cast Shield of Faith vs tammara DC14 SAVED " - "-> buff 1 mods (10r) (36->36)"), - "round 2 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 3 tammara: cast Shield of Faith vs tammara DC14 SAVED " - "-> buff 1 mods (10r) (36->36)"), - "round 3 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 4 tammara: cast Shield of Faith vs tammara DC14 SAVED " - "-> buff 1 mods (10r) (36->36)"), - "round 4 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", + ("round 1 tammara: cast Divine Favor vs tammara DC14 NO SAVE " + "-> buff 2 mods (10r) (36->36)"), + "round 1 goblin: short bow vs tammara d20=10+4-2=12 AC 20 -> MISS", + ("round 2 tammara: cast Divine Favor vs tammara DC14 NO SAVE " + "-> buff 2 mods (10r) (36->36)"), + "round 2 goblin: short bow vs tammara d20=15+4-2=17 AC 20 -> MISS", + ("round 3 tammara: cast Divine Favor vs tammara DC14 NO SAVE " + "-> buff 2 mods (10r) (36->36)"), + "round 3 goblin: short bow vs tammara d20=10+4-2=12 AC 20 -> MISS", + ("round 4 tammara: cast Divine Favor vs tammara DC14 NO SAVE " + "-> buff 2 mods (10r) (36->36)"), + "round 4 goblin: short bow vs tammara d20=15+4-2=17 AC 20 -> MISS", ("round 5 tammara: Braises d'Automne (pistolet ?) vs goblin " - "d20=10+9-6=14 AC 16 -> MISS"), - "round 5 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 6 tammara: Braises d'Automne (pistolet ?) vs goblin " - "d20=10+9-6=14 AC 16 -> MISS"), - "round 6 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 7 tammara: Braises d'Automne (pistolet ?) vs goblin " - "d20=10+9-6=14 AC 16 -> MISS"), - "round 7 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 8 tammara: Braises d'Automne (pistolet ?) vs goblin " - "d20=10+9-6=14 AC 16 -> MISS"), - "round 8 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 9 tammara: Braises d'Automne (pistolet ?) vs goblin " - "d20=10+9-6=14 AC 16 -> MISS"), - "round 9 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - ("round 10 tammara: Braises d'Automne (pistolet ?) vs goblin " - "d20=10+9-6=14 AC 16 -> MISS"), - "round 10 goblin: short bow vs tammara d20=15+4-2=17 AC 22 -> MISS", - "battle over: draw after 10 rounds", + "d20=10+9-6=16 AC 16 -> HIT 17 damage (6->-11)"), + "round 5 tammara: goblin down", + "battle over: players win in 5 rounds", ) def test_tammara_vs_lich(self): """Tammara vs Lich (boss fight) — full pinned transcript. Updated (S2b): the lich is caster level 11, so Magic Missile now fires - its SRD full five missiles (1d4+1 each) instead of a single one. Three - missiles (16 + 11 + 16 = 43) drop Tammara below 0 hp on round 1; the - remaining two are lost (the engine's target-drops-mid-sequence - convention), so the lich wins in 1 round. + its SRD full five missiles (1d4+1 each). - Updated by the SRD shield-of-faith fix: her round-1 buff pick is now - Shield of Faith (first buff spell in her known-spell order, index 30 - before Bull's Strength's 46) — "cast Shield of Faith ... DC14 SAVED -> - buff 1 mods (10r)" (DC 14 = 10 + level 1 + her +3 Wis). Magic Missile - auto-hits and ignores the +2 deflection it would otherwise grant, so - the lich's line and the outcome are unchanged. + Updated by the SRD spell-effect fixes: her round-1 buff pick is now + Divine Favor (first buff spell in her known-spell order, index 20) — + "cast Divine Favor vs tammara DC14 NO SAVE -> buff 2 mods (10r)" + (DC 14 = 10 + level 1 + her +3 Wis; save "none" consumes no d20, so + the scripted queue feeding the lich's five missile damage rolls + shifts: 38 total instead of 43). Three missiles still drop Tammara + below 0 hp on round 1 (36 -> -2) and the remaining two are lost (the + engine's target-drops-mid-sequence convention), so the lich wins in 1 + round — outcome unchanged. """ result, _ = run_golden("tammara", "lich") assert result.winner == "monsters" @@ -145,9 +133,9 @@ class TestGoldenCombats: assert result.transcript == ( "initiative: tammara d20=15+7=22", "initiative: lich d20=10+6=16", - ("round 1 tammara: cast Shield of Faith vs tammara DC14 SAVED " - "-> buff 1 mods (10r) (36->36)"), - "round 1 lich: cast Magic Missile vs tammara DC16 NO SAVE -> 43 damage (36->-7)", + ("round 1 tammara: cast Divine Favor vs tammara DC14 NO SAVE " + "-> buff 2 mods (10r) (36->36)"), + "round 1 lich: cast Magic Missile vs tammara DC16 NO SAVE -> 38 damage (36->-2)", "battle over: monsters win in 1 rounds", )