fix: add creature damage accumulation to combat engine

Previously _resolve_combat() used a binary power-vs-toughness kill check:
creatures only died if a single source had power >= their toughness in one
swing. This meant a 2/2 wouldn't die to two 1/1 tokens blocking it, and
repeated smaller hits across combats never accumulated.

Changes:
- models.py: add damage_marked field to Card (default 0)
- engine.py: accumulate damage via damage_marked += power instead of
  binary a_pow >= toughness checks in _resolve_combat()
- engine.py: clear damage_marked = 0 in untap phase (MTG rule 514.2)

This enables multi-blocker lethality, incremental chip damage within a
combat step, and proper creature death-by-accumulated-damage interactions.
This commit is contained in:
KoalaTrapLord committed 2026-03-22 04:52:28 +00:00
1 parent 473c453abf
commit cffd8d8109
2 files changed
+7 -2

No files matched your search

+6 -2
View File
@@ -127,6 +127,7 @@ class GameEngine:
# ── Untap (correct MTG order: untap is first) ──
for c in sim.get_battlefield(pi):
c.tapped = False
c.damage_marked = 0 # clear damage each turn (MTG rule 514.2)
# ── Draw ──
if p.library:
@@ -590,12 +591,15 @@ class GameEngine:
blocked = True
if events is not None:
combat_details.append(f"{atk.name} blocked by {blocker.name}")
if a_pow >= blocker.get_toughness() or atk.has_keyword("deathtouch"):
# Accumulate damage on creatures (not binary kill)
blocker.damage_marked += a_pow
if blocker.damage_marked >= blocker.get_toughness() or atk.has_keyword("deathtouch"):
sim.remove_from_battlefield(blocker.id)
self._send_to_graveyard(sim, blocker, opp_idx)
if events is not None:
combat_details.append(f" {blocker.name} dies")
if b_pow >= a_tou or blocker.has_keyword("deathtouch"):
atk.damage_marked += b_pow
if atk.damage_marked >= a_tou or blocker.has_keyword("deathtouch"):
sim.remove_from_battlefield(atk.id)
self._send_to_graveyard(sim, atk, pi)
if events is not None:
+1
View File
@@ -43,6 +43,7 @@ class Card:
owner_id: int = -1
tapped: bool = False
turn_played: int = -1
damage_marked: int = 0 # track damage marked on creature (cleared each cleanup step)
def get_power(self) -> int:
"""Extract numeric power from pt string."""