Add mode stack to Player and mode check in dispatch
This commit is contained in:
parent
dcc8b961bb
commit
d220835f7d
3 changed files with 66 additions and 1 deletions
|
|
@ -60,5 +60,11 @@ async def dispatch(player: Player, raw_input: str) -> None:
|
|||
await player.writer.drain()
|
||||
return
|
||||
|
||||
# Check mode restriction
|
||||
if defn.mode != "*" and defn.mode != player.mode:
|
||||
player.writer.write("You can't do that right now.\r\n")
|
||||
await player.writer.drain()
|
||||
return
|
||||
|
||||
# Execute the handler
|
||||
await defn.handler(player, args)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""Player state and registry."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
|
||||
|
|
@ -14,6 +14,12 @@ class Player:
|
|||
writer: Any # telnetlib3 TelnetWriter for sending output
|
||||
reader: Any # telnetlib3 TelnetReader for reading input
|
||||
flying: bool = False
|
||||
mode_stack: list[str] = field(default_factory=lambda: ["normal"])
|
||||
|
||||
@property
|
||||
def mode(self) -> str:
|
||||
"""Current mode is the top of the stack."""
|
||||
return self.mode_stack[-1]
|
||||
|
||||
|
||||
# Global registry of connected players
|
||||
|
|
|
|||
|
|
@ -318,3 +318,56 @@ async def test_effects_dont_override_player_marker(player, mock_world):
|
|||
assert "@" in output
|
||||
|
||||
active_effects.clear()
|
||||
|
||||
|
||||
# Test mode stack
|
||||
def test_mode_stack_default(player):
|
||||
"""Player starts in normal mode."""
|
||||
assert player.mode == "normal"
|
||||
assert player.mode_stack == ["normal"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_blocks_wrong_mode(player, mock_writer):
|
||||
"""Commands with wrong mode get rejected."""
|
||||
|
||||
async def combat_handler(p, args):
|
||||
pass
|
||||
|
||||
commands.register(CommandDefinition("strike", combat_handler, mode="combat"))
|
||||
await commands.dispatch(player, "strike")
|
||||
|
||||
assert mock_writer.write.called
|
||||
written = mock_writer.write.call_args[0][0]
|
||||
assert "can't" in written.lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_allows_wildcard_mode(player):
|
||||
"""Commands with mode='*' work from any mode."""
|
||||
called = False
|
||||
|
||||
async def any_handler(p, args):
|
||||
nonlocal called
|
||||
called = True
|
||||
|
||||
commands.register(CommandDefinition("universal", any_handler, mode="*"))
|
||||
await commands.dispatch(player, "universal")
|
||||
|
||||
assert called
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_allows_matching_mode(player):
|
||||
"""Commands work when player mode matches command mode."""
|
||||
called = False
|
||||
|
||||
async def combat_handler(p, args):
|
||||
nonlocal called
|
||||
called = True
|
||||
|
||||
commands.register(CommandDefinition("strike", combat_handler, mode="combat"))
|
||||
player.mode_stack.append("combat")
|
||||
await commands.dispatch(player, "strike")
|
||||
|
||||
assert called
|
||||
|
|
|
|||
Loading…
Reference in a new issue