Lines 96.55% 28 / 29
Functions and Methods 66.66% 2 / 3
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
ItemDroppedEvent 96.55% 28 / 29 66.66% 2 / 3 8 0.00% 0 / 1
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 from 95.65% 22 / 23 0.00% 0 / 1 6
 summary 100.00% 5 / 5 100.00% 1 / 1 1
1<?php
2
3declare(strict_types=1);
4
5namespace Lorekeeper\Server\Event\Inventory;
6
7use Lorekeeper\Core\Item\ItemId;
8use Lorekeeper\Core\Item\ItemName;
9use Lorekeeper\Core\Item\ItemTag;
10use Lorekeeper\Core\Player\PlayerItem;
11use Lorekeeper\Core\Support\Quantity;
12use Lorekeeper\Server\Event\Event;
13use Lorekeeper\Server\Event\Item\Helper\ItemKinds;
14use Lorekeeper\Server\Event\NamedAfterClass;
15use Lorekeeper\Server\Exception\MalformedEventException;
16use Lorekeeper\Server\Message\JsonMessage;
17use Lorekeeper\Server\Message\Message;
18use Override;
19use Psl\Option;
20use Psl\Type;
21use Psl\Type\Exception\CoercionException;
22
23final readonly class ItemDroppedEvent implements Event
24{
25    use NamedAfterClass;
26
27    /** @param non-empty-list<PlayerItem> $items */
28    public function __construct(
29        public array $items,
30    ) {}
31
32    /** @return Option\Option<static> */
33    #[Override]
34    public static function from(Message $message): Option\Option
35    {
36        if (!$message instanceof JsonMessage || ($message->data['cmd'] ?? null) !== 'dropItem') {
37            return Option\none();
38        }
39
40        try {
41            $items = Type\non_empty_dict(Type\string(), Type\shape([
42                'ItemID' => Type\positive_int(),
43                'sName' => Type\non_empty_string(),
44                'sType' => Type\string(),
45                'iQty' => Type\positive_int(),
46                'bUpg' => Type\optional(Type\bool()),
47            ], allowUnknownFields: true))->coerce($message->data['items'] ?? null);
48        } catch (CoercionException $exception) {
49            throw new MalformedEventException(static::class, 'dropped items are missing or invalid', $exception);
50        }
51
52        $dropped = [];
53        foreach ($items as $entry) {
54            $item = ItemKinds::read(
55                new ItemId($entry['ItemID']),
56                new ItemName($entry['sName']),
57                $entry['sType'],
58                static::class,
59            );
60            if ($entry['bUpg'] ?? false) {
61                $item->tags->add(ItemTag::MemberOnly);
62            }
63
64            $dropped[] = new PlayerItem($item, new Quantity($entry['iQty']));
65        }
66
67        return Option\some(new static($dropped));
68    }
69
70    #[Override]
71    public function summary(): string
72    {
73        return 'Dropped '
74        . implode(', ', array_map(
75            static fn(PlayerItem $held): string => "{$held->quantity->value} {$held->item->name->value}",
76            $this->items,
77        ));
78    }
79}