Removed identical local copies from 45 test files. These fixtures are already defined in conftest.py.
223 lines
4.7 KiB
Python
223 lines
4.7 KiB
Python
"""Tests for safe zone combat prevention."""
|
|
|
|
import pathlib
|
|
import tempfile
|
|
|
|
import pytest
|
|
|
|
from mudlib.combat.engine import active_encounters, get_encounter
|
|
from mudlib.entity import Mob
|
|
from mudlib.player import Player, players
|
|
from mudlib.zone import Zone
|
|
from mudlib.zones import load_zone
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def clear_state():
|
|
"""Clear global state between tests."""
|
|
players.clear()
|
|
active_encounters.clear()
|
|
yield
|
|
players.clear()
|
|
active_encounters.clear()
|
|
|
|
|
|
@pytest.fixture
|
|
def safe_zone():
|
|
terrain = [["." for _ in range(10)] for _ in range(10)]
|
|
return Zone(
|
|
name="sanctuary",
|
|
width=10,
|
|
height=10,
|
|
terrain=terrain,
|
|
safe=True,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def unsafe_zone():
|
|
terrain = [["." for _ in range(10)] for _ in range(10)]
|
|
return Zone(
|
|
name="wilderness",
|
|
width=10,
|
|
height=10,
|
|
terrain=terrain,
|
|
safe=False,
|
|
)
|
|
|
|
|
|
# --- Zone property tests ---
|
|
|
|
|
|
def test_zone_safe_default_false():
|
|
"""Zones are unsafe by default."""
|
|
zone = Zone(name="test")
|
|
assert zone.safe is False
|
|
|
|
|
|
def test_zone_safe_true():
|
|
"""Zone can be created as safe."""
|
|
zone = Zone(name="test", safe=True)
|
|
assert zone.safe is True
|
|
|
|
|
|
# --- TOML loading ---
|
|
|
|
|
|
def test_load_zone_safe_flag():
|
|
"""Load a zone with safe = true from TOML."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write(
|
|
"""
|
|
name = "sanctuary"
|
|
description = "a peaceful place"
|
|
width = 3
|
|
height = 3
|
|
safe = true
|
|
|
|
[terrain]
|
|
rows = [
|
|
"...",
|
|
"...",
|
|
"...",
|
|
]
|
|
"""
|
|
)
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
assert zone.safe is True
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_load_zone_safe_default():
|
|
"""Zone without safe field defaults to False."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write(
|
|
"""
|
|
name = "wilderness"
|
|
description = "dangerous lands"
|
|
width = 3
|
|
height = 3
|
|
|
|
[terrain]
|
|
rows = [
|
|
"...",
|
|
"...",
|
|
"...",
|
|
]
|
|
"""
|
|
)
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
assert zone.safe is False
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_tavern_is_safe():
|
|
"""The tavern zone file has safe = true."""
|
|
project_root = pathlib.Path(__file__).resolve().parents[1]
|
|
tavern_path = project_root / "content" / "zones" / "tavern.toml"
|
|
zone = load_zone(tavern_path)
|
|
assert zone.safe is True
|
|
|
|
|
|
# --- Combat prevention ---
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_attack_blocked_in_safe_zone(safe_zone, mock_writer, mock_reader):
|
|
"""Attacking in a safe zone sends error message."""
|
|
from mudlib.combat.commands import do_attack
|
|
from mudlib.combat.moves import CombatMove
|
|
|
|
player = Player(
|
|
name="attacker",
|
|
x=5,
|
|
y=5,
|
|
writer=mock_writer,
|
|
reader=mock_reader,
|
|
location=safe_zone,
|
|
)
|
|
safe_zone._contents.append(player)
|
|
players["attacker"] = player
|
|
|
|
target = Mob(
|
|
name="goblin",
|
|
x=5,
|
|
y=5,
|
|
location=safe_zone,
|
|
pl=50,
|
|
stamina=40,
|
|
max_stamina=40,
|
|
)
|
|
safe_zone._contents.append(target)
|
|
|
|
move = CombatMove(
|
|
name="punch left",
|
|
command="punch",
|
|
variant="left",
|
|
move_type="attack",
|
|
stamina_cost=5,
|
|
hit_time_ms=850,
|
|
damage_pct=0.15,
|
|
)
|
|
|
|
await do_attack(player, "goblin", move)
|
|
|
|
# Should have sent the safe zone message
|
|
mock_writer.write.assert_called()
|
|
written = mock_writer.write.call_args_list[0][0][0]
|
|
assert "can't fight here" in written.lower()
|
|
|
|
# Should NOT have started combat
|
|
assert get_encounter(player) is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_attack_allowed_in_unsafe_zone(unsafe_zone, mock_writer, mock_reader):
|
|
"""Attacking in an unsafe zone works normally."""
|
|
from mudlib.combat.commands import do_attack
|
|
from mudlib.combat.moves import CombatMove
|
|
|
|
player = Player(
|
|
name="fighter",
|
|
x=5,
|
|
y=5,
|
|
writer=mock_writer,
|
|
reader=mock_reader,
|
|
location=unsafe_zone,
|
|
)
|
|
unsafe_zone._contents.append(player)
|
|
players["fighter"] = player
|
|
|
|
target = Mob(
|
|
name="goblin",
|
|
x=5,
|
|
y=5,
|
|
location=unsafe_zone,
|
|
pl=50,
|
|
stamina=40,
|
|
max_stamina=40,
|
|
)
|
|
unsafe_zone._contents.append(target)
|
|
|
|
move = CombatMove(
|
|
name="punch left",
|
|
command="punch",
|
|
variant="left",
|
|
move_type="attack",
|
|
stamina_cost=5,
|
|
hit_time_ms=850,
|
|
damage_pct=0.15,
|
|
)
|
|
|
|
await do_attack(player, "goblin", move)
|
|
|
|
# Combat SHOULD have started
|
|
assert get_encounter(player) is not None
|