1<?php ...
 2 
 3namespace Thunk\Verbs\Examples\Monopoly\Events\Gameplay;
 4 
 5use Thunk\Verbs\Attributes\Autodiscovery\AppliesToState;
 6use Thunk\Verbs\Event;
 7use Thunk\Verbs\Examples\Monopoly\Game\Phase;
 8use Thunk\Verbs\Examples\Monopoly\Game\Spaces\Property;
 9use Thunk\Verbs\Examples\Monopoly\States\GameState;
10use Thunk\Verbs\Examples\Monopoly\States\PlayerState; 
11 
12#[AppliesToState(GameState::class)]
13#[AppliesToState(PlayerState::class)]
14class PaidRent extends Event
15{
16    use PlayerAction;
17 
18    public function __construct(
19        public int $game_id,
20        public int $player_id,
21        public Property $property,
22    ) {}
23 
24    public function validatePlayer(PlayerState $player)
25    {
26        $this->assert($player->location === $this->property, 'You must land on a property to pay rent on it.');
27        $this->assert($player->money->isGreaterThanOrEqualTo($this->property->rent()), "You do not have enough money to pay rent at {$this->property->name()}.");
28        $this->assert($player !== $this->property->owner(), 'You cannot pay rent on a property that you do own.');
29    }
30 
31    public function validateGame(GameState $game)
32    {
33        $this->assert(! $game->bank->hasDeed($this->property), "{$this->property->name()} is still for sale—you cannot pay rent on it.");
34        $this->assert($game->phase_complete, 'You must finish what you’re doing before purchasing a property.');
35        $this->assert($game->phase->canTransitionTo(Phase::PayRent), 'You are not allowed to pay rent right now.');
36    }
37 
38    public function applyToGame(GameState $game)
39    {
40        $game->phase = Phase::PayRent;
41        $game->phase_complete = true;
42    }
43 
44    public function applyToPlayer(PlayerState $player)
45    {
46        $owner = $this->property->owner();
47 
48        $owner->money = $owner->money->plus($this->property->rent());
49        $player->money = $player->money->minus($this->property->rent());
50    }
51}