nonebot-plugin-werewolf 1.0.6__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nonebot_plugin_werewolf/__init__.py +1 -1
- nonebot_plugin_werewolf/config.py +76 -4
- nonebot_plugin_werewolf/constant.py +35 -26
- nonebot_plugin_werewolf/exception.py +19 -0
- nonebot_plugin_werewolf/game.py +117 -68
- nonebot_plugin_werewolf/matchers.py +6 -8
- nonebot_plugin_werewolf/ob11_ext.py +1 -1
- nonebot_plugin_werewolf/player.py +97 -71
- nonebot_plugin_werewolf/player_set.py +17 -9
- nonebot_plugin_werewolf/utils.py +34 -24
- {nonebot_plugin_werewolf-1.0.6.dist-info → nonebot_plugin_werewolf-1.1.0.dist-info}/METADATA +83 -20
- nonebot_plugin_werewolf-1.1.0.dist-info/RECORD +15 -0
- {nonebot_plugin_werewolf-1.0.6.dist-info → nonebot_plugin_werewolf-1.1.0.dist-info}/WHEEL +2 -1
- nonebot_plugin_werewolf-1.1.0.dist-info/top_level.txt +1 -0
- nonebot_plugin_werewolf-1.0.6.dist-info/RECORD +0 -13
- {nonebot_plugin_werewolf-1.0.6.dist-info/licenses → nonebot_plugin_werewolf-1.1.0.dist-info}/LICENSE +0 -0
@@ -4,15 +4,20 @@ import asyncio
|
|
4
4
|
import asyncio.timeouts
|
5
5
|
from dataclasses import dataclass
|
6
6
|
from typing import TYPE_CHECKING, ClassVar, TypeVar, final
|
7
|
-
from typing_extensions import override
|
8
7
|
|
9
|
-
from nonebot.
|
8
|
+
from nonebot.log import logger
|
10
9
|
from nonebot_plugin_alconna.uniseg import Receipt, Target, UniMessage
|
10
|
+
from typing_extensions import override
|
11
11
|
|
12
|
-
from .constant import KillReason, Role, RoleGroup, role_name_conv
|
12
|
+
from .constant import GameStatus, KillReason, Role, RoleGroup, role_name_conv
|
13
|
+
from .exception import GameFinishedError
|
13
14
|
from .utils import InputStore, check_index
|
14
15
|
|
15
16
|
if TYPE_CHECKING:
|
17
|
+
from collections.abc import Callable
|
18
|
+
|
19
|
+
from nonebot.adapters import Bot
|
20
|
+
|
16
21
|
from .game import Game
|
17
22
|
from .player_set import PlayerSet
|
18
23
|
|
@@ -21,9 +26,14 @@ P = TypeVar("P", bound=type["Player"])
|
|
21
26
|
PLAYER_CLASS: dict[Role, type[Player]] = {}
|
22
27
|
|
23
28
|
|
24
|
-
def register_role(
|
25
|
-
|
26
|
-
|
29
|
+
def register_role(role: Role, role_group: RoleGroup, /) -> Callable[[P], P]:
|
30
|
+
def decorator(cls: P, /) -> P:
|
31
|
+
cls.role = role
|
32
|
+
cls.role_group = role_group
|
33
|
+
PLAYER_CLASS[role] = cls
|
34
|
+
return cls
|
35
|
+
|
36
|
+
return decorator
|
27
37
|
|
28
38
|
|
29
39
|
@dataclass
|
@@ -41,7 +51,7 @@ class Player:
|
|
41
51
|
user: Target
|
42
52
|
name: str
|
43
53
|
alive: bool = True
|
44
|
-
killed:
|
54
|
+
killed: asyncio.Event
|
45
55
|
kill_info: KillInfo | None = None
|
46
56
|
selected: Player | None = None
|
47
57
|
|
@@ -51,6 +61,7 @@ class Player:
|
|
51
61
|
self.game = game
|
52
62
|
self.user = user
|
53
63
|
self.name = name
|
64
|
+
self.killed = asyncio.Event()
|
54
65
|
|
55
66
|
@final
|
56
67
|
@classmethod
|
@@ -68,7 +79,7 @@ class Player:
|
|
68
79
|
return PLAYER_CLASS[role](bot, game, user, name)
|
69
80
|
|
70
81
|
def __repr__(self) -> str:
|
71
|
-
return f"<{self.role_name}: user={self.
|
82
|
+
return f"<{self.role_name}: user={self.name!r} alive={self.alive}>"
|
72
83
|
|
73
84
|
@property
|
74
85
|
def user_id(self) -> str:
|
@@ -78,18 +89,32 @@ class Player:
|
|
78
89
|
def role_name(self) -> str:
|
79
90
|
return role_name_conv[self.role]
|
80
91
|
|
92
|
+
@final
|
93
|
+
def _log(self, text: str) -> None:
|
94
|
+
text = text.replace("\n", "\\n")
|
95
|
+
logger.opt(colors=True).info(
|
96
|
+
f"<b><e>{self.game.group.id}</e></b> | "
|
97
|
+
f"[<b><m>{self.role_name}</m></b>] "
|
98
|
+
f"<y>{self.name}</y>(<e>{self.user_id}</e>) | "
|
99
|
+
f"{text}",
|
100
|
+
)
|
101
|
+
|
81
102
|
@final
|
82
103
|
async def send(self, message: str | UniMessage) -> Receipt:
|
83
104
|
if isinstance(message, str):
|
84
105
|
message = UniMessage.text(message)
|
85
106
|
|
107
|
+
self._log(f"<g>Send</g> | {message}")
|
86
108
|
return await message.send(target=self.user, bot=self.bot)
|
87
109
|
|
88
110
|
@final
|
89
111
|
async def receive(self, prompt: str | UniMessage | None = None) -> UniMessage:
|
90
112
|
if prompt:
|
91
113
|
await self.send(prompt)
|
92
|
-
|
114
|
+
|
115
|
+
result = await InputStore.fetch(self.user.id)
|
116
|
+
self._log(f"<y>Recv</y> | {result}")
|
117
|
+
return result
|
93
118
|
|
94
119
|
@final
|
95
120
|
async def receive_text(self) -> str:
|
@@ -101,11 +126,7 @@ class Player:
|
|
101
126
|
async def notify_role(self) -> None:
|
102
127
|
await self.send(f"你的身份: {self.role_name}")
|
103
128
|
|
104
|
-
async def kill(
|
105
|
-
self,
|
106
|
-
reason: KillReason,
|
107
|
-
*killers: Player,
|
108
|
-
) -> bool:
|
129
|
+
async def kill(self, reason: KillReason, *killers: Player) -> bool:
|
109
130
|
from .player_set import PlayerSet
|
110
131
|
|
111
132
|
self.alive = False
|
@@ -113,7 +134,7 @@ class Player:
|
|
113
134
|
return True
|
114
135
|
|
115
136
|
async def post_kill(self) -> None:
|
116
|
-
self.killed
|
137
|
+
self.killed.set()
|
117
138
|
|
118
139
|
async def vote(self, players: PlayerSet) -> tuple[Player, Player] | None:
|
119
140
|
await self.send(
|
@@ -179,7 +200,7 @@ class CanShoot(Player):
|
|
179
200
|
text = await self.receive_text()
|
180
201
|
if text == "/stop":
|
181
202
|
await self.send("已取消技能")
|
182
|
-
return
|
203
|
+
return None
|
183
204
|
index = check_index(text, len(players))
|
184
205
|
if index is not None:
|
185
206
|
selected = index - 1
|
@@ -190,11 +211,8 @@ class CanShoot(Player):
|
|
190
211
|
return players[selected]
|
191
212
|
|
192
213
|
|
193
|
-
@register_role
|
194
|
-
class
|
195
|
-
role: ClassVar[Role] = Role.Werewolf
|
196
|
-
role_group: ClassVar[RoleGroup] = RoleGroup.Werewolf
|
197
|
-
|
214
|
+
@register_role(Role.Werewolf, RoleGroup.Werewolf)
|
215
|
+
class Werewolf(Player):
|
198
216
|
@override
|
199
217
|
async def notify_role(self) -> None:
|
200
218
|
await super().notify_role()
|
@@ -211,7 +229,7 @@ class 狼人(Player):
|
|
211
229
|
partners = players.select(RoleGroup.Werewolf).exclude(self)
|
212
230
|
|
213
231
|
# 避免阻塞
|
214
|
-
def broadcast(msg: str | UniMessage):
|
232
|
+
def broadcast(msg: str | UniMessage) -> asyncio.Task[None]:
|
215
233
|
return asyncio.create_task(partners.broadcast(msg))
|
216
234
|
|
217
235
|
msg = UniMessage()
|
@@ -232,8 +250,8 @@ class 狼人(Player):
|
|
232
250
|
selected = None
|
233
251
|
finished = False
|
234
252
|
while selected is None or not finished:
|
235
|
-
|
236
|
-
text =
|
253
|
+
input_msg = await self.receive()
|
254
|
+
text = input_msg.extract_plain_text()
|
237
255
|
index = check_index(text, len(players))
|
238
256
|
if index is not None:
|
239
257
|
selected = index - 1
|
@@ -247,22 +265,21 @@ class 狼人(Player):
|
|
247
265
|
broadcast(f"队友 {self.name} 结束当前回合")
|
248
266
|
else:
|
249
267
|
await self.send("当前未选择玩家,无法结束回合")
|
250
|
-
broadcast(UniMessage.text(f"队友 {self.name}:\n") +
|
268
|
+
broadcast(UniMessage.text(f"队友 {self.name}:\n") + input_msg)
|
251
269
|
|
252
270
|
self.selected = players[selected]
|
253
271
|
|
254
272
|
|
255
|
-
@register_role
|
256
|
-
class
|
257
|
-
|
258
|
-
|
259
|
-
|
273
|
+
@register_role(Role.WolfKing, RoleGroup.Werewolf)
|
274
|
+
class WolfKing(CanShoot, Werewolf):
|
275
|
+
@override
|
276
|
+
async def notify_role(self) -> None:
|
277
|
+
await super().notify_role()
|
278
|
+
await self.send("作为狼王,你可以在死后射杀一名玩家")
|
260
279
|
|
261
|
-
@register_role
|
262
|
-
class 预言家(Player):
|
263
|
-
role: ClassVar[Role] = Role.Prophet
|
264
|
-
role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
|
265
280
|
|
281
|
+
@register_role(Role.Prophet, RoleGroup.GoodGuy)
|
282
|
+
class Prophet(Player):
|
266
283
|
@override
|
267
284
|
async def interact(self) -> None:
|
268
285
|
players = self.game.players.alive().exclude(self)
|
@@ -281,14 +298,12 @@ class 预言家(Player):
|
|
281
298
|
await self.send("输入错误,请发送编号选择玩家")
|
282
299
|
|
283
300
|
player = players[selected]
|
284
|
-
result =
|
301
|
+
result = "狼人" if player.role_group == RoleGroup.Werewolf else "好人"
|
285
302
|
await self.send(f"玩家 {player.name} 的阵营是『{result}』")
|
286
303
|
|
287
304
|
|
288
|
-
@register_role
|
289
|
-
class
|
290
|
-
role: ClassVar[Role] = Role.Witch
|
291
|
-
role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
|
305
|
+
@register_role(Role.Witch, RoleGroup.GoodGuy)
|
306
|
+
class Witch(Player):
|
292
307
|
antidote: int = 1
|
293
308
|
poison: int = 1
|
294
309
|
|
@@ -297,7 +312,7 @@ class 女巫(Player):
|
|
297
312
|
*,
|
298
313
|
antidote: Player | None = None,
|
299
314
|
posion: Player | None = None,
|
300
|
-
):
|
315
|
+
) -> None:
|
301
316
|
if antidote is not None:
|
302
317
|
self.antidote = 0
|
303
318
|
self.selected = antidote
|
@@ -331,10 +346,9 @@ class 女巫(Player):
|
|
331
346
|
self.set_state(antidote=killed)
|
332
347
|
await self.send(f"你对 {killed.name} 使用了解药,回合结束")
|
333
348
|
return True
|
334
|
-
|
349
|
+
if text == "/stop":
|
335
350
|
return False
|
336
|
-
|
337
|
-
await self.send("输入错误: 请输入 “1” 或 “/stop”")
|
351
|
+
await self.send("输入错误: 请输入 “1” 或 “/stop”")
|
338
352
|
|
339
353
|
@override
|
340
354
|
async def interact(self) -> None:
|
@@ -361,12 +375,11 @@ class 女巫(Player):
|
|
361
375
|
if index is not None:
|
362
376
|
selected = index - 1
|
363
377
|
break
|
364
|
-
|
378
|
+
if text == "/stop":
|
365
379
|
await self.send("你选择不使用毒药,回合结束")
|
366
380
|
self.set_state()
|
367
381
|
return
|
368
|
-
|
369
|
-
await self.send("输入错误: 请发送玩家编号或 “/stop”")
|
382
|
+
await self.send("输入错误: 请发送玩家编号或 “/stop”")
|
370
383
|
|
371
384
|
self.poison = 0
|
372
385
|
self.selected = player = players[selected]
|
@@ -374,22 +387,19 @@ class 女巫(Player):
|
|
374
387
|
await self.send(f"当前回合选择对玩家 {player.name} 使用毒药\n回合结束")
|
375
388
|
|
376
389
|
|
377
|
-
@register_role
|
378
|
-
class
|
379
|
-
|
380
|
-
role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
|
390
|
+
@register_role(Role.Hunter, RoleGroup.GoodGuy)
|
391
|
+
class Hunter(CanShoot, Player):
|
392
|
+
pass
|
381
393
|
|
382
394
|
|
383
|
-
@register_role
|
384
|
-
class
|
385
|
-
role: ClassVar[Role] = Role.Guard
|
386
|
-
role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
|
387
|
-
|
395
|
+
@register_role(Role.Guard, RoleGroup.GoodGuy)
|
396
|
+
class Guard(Player):
|
388
397
|
@override
|
389
398
|
async def interact(self) -> None:
|
390
|
-
players = self.game.players.alive()
|
399
|
+
players = self.game.players.alive()
|
391
400
|
await self.send(
|
392
|
-
UniMessage.text(
|
401
|
+
UniMessage.text("请选择需要保护的玩家:\n")
|
402
|
+
.text(players.show())
|
393
403
|
.text("\n\n发送编号选择玩家")
|
394
404
|
.text("\n发送 “/stop” 结束回合")
|
395
405
|
)
|
@@ -412,24 +422,25 @@ class 守卫(Player):
|
|
412
422
|
await self.send(f"本回合保护的玩家: {self.selected.name}")
|
413
423
|
|
414
424
|
|
415
|
-
@register_role
|
416
|
-
class
|
417
|
-
role: ClassVar[Role] = Role.Idiot
|
418
|
-
role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
|
425
|
+
@register_role(Role.Idiot, RoleGroup.GoodGuy)
|
426
|
+
class Idiot(Player):
|
419
427
|
voted: bool = False
|
420
428
|
|
421
429
|
@override
|
422
|
-
async def
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
430
|
+
async def notify_role(self) -> None:
|
431
|
+
await super().notify_role()
|
432
|
+
await self.send(
|
433
|
+
"作为白痴,你可以在首次被投票放逐时免疫放逐,但在之后的投票中无法继续投票"
|
434
|
+
)
|
435
|
+
|
436
|
+
@override
|
437
|
+
async def kill(self, reason: KillReason, *killers: Player) -> bool:
|
427
438
|
if reason == KillReason.Vote and not self.voted:
|
428
439
|
self.voted = True
|
429
440
|
await self.game.send(
|
430
441
|
UniMessage.at(self.user_id)
|
431
442
|
.text(" 的身份是白痴\n")
|
432
|
-
.text("免疫本次投票放逐,且接下来无法参与投票")
|
443
|
+
.text("免疫本次投票放逐,且接下来无法参与投票"),
|
433
444
|
)
|
434
445
|
return False
|
435
446
|
return await super().kill(reason, *killers)
|
@@ -442,7 +453,22 @@ class 白痴(Player):
|
|
442
453
|
return await super().vote(players)
|
443
454
|
|
444
455
|
|
445
|
-
@register_role
|
446
|
-
class
|
447
|
-
|
448
|
-
|
456
|
+
@register_role(Role.Joker, RoleGroup.Others)
|
457
|
+
class Joker(Player):
|
458
|
+
@override
|
459
|
+
async def notify_role(self) -> None:
|
460
|
+
await super().notify_role()
|
461
|
+
await self.send("你的胜利条件: 被投票放逐")
|
462
|
+
|
463
|
+
@override
|
464
|
+
async def kill(self, reason: KillReason, *killers: Player) -> bool:
|
465
|
+
result = await super().kill(reason, *killers)
|
466
|
+
if reason == KillReason.Vote:
|
467
|
+
self.game.killed_players.append(self)
|
468
|
+
raise GameFinishedError(GameStatus.Joker)
|
469
|
+
return result
|
470
|
+
|
471
|
+
|
472
|
+
@register_role(Role.Civilian, RoleGroup.GoodGuy)
|
473
|
+
class Civilian(Player):
|
474
|
+
pass
|
@@ -1,34 +1,42 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import asyncio
|
2
4
|
import asyncio.timeouts
|
5
|
+
from typing import TYPE_CHECKING
|
3
6
|
|
4
|
-
from nonebot_plugin_alconna.uniseg import UniMessage
|
5
|
-
|
6
|
-
from .constant import Role, RoleGroup
|
7
7
|
from .player import Player
|
8
8
|
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from nonebot_plugin_alconna.uniseg import UniMessage
|
11
|
+
|
12
|
+
from .constant import Role, RoleGroup
|
13
|
+
|
9
14
|
|
10
15
|
class PlayerSet(set[Player]):
|
11
16
|
@property
|
12
17
|
def size(self) -> int:
|
13
18
|
return len(self)
|
14
19
|
|
15
|
-
def alive(self) ->
|
20
|
+
def alive(self) -> PlayerSet:
|
16
21
|
return PlayerSet(p for p in self if p.alive)
|
17
22
|
|
18
|
-
def dead(self) ->
|
23
|
+
def dead(self) -> PlayerSet:
|
19
24
|
return PlayerSet(p for p in self if not p.alive)
|
20
25
|
|
21
|
-
def
|
26
|
+
def killed(self) -> PlayerSet:
|
27
|
+
return PlayerSet(p for p in self if p.killed.is_set())
|
28
|
+
|
29
|
+
def include(self, *types: Player | Role | RoleGroup) -> PlayerSet:
|
22
30
|
return PlayerSet(
|
23
31
|
player
|
24
32
|
for player in self
|
25
33
|
if (player in types or player.role in types or player.role_group in types)
|
26
34
|
)
|
27
35
|
|
28
|
-
def select(self, *types: Player | Role | RoleGroup) ->
|
36
|
+
def select(self, *types: Player | Role | RoleGroup) -> PlayerSet:
|
29
37
|
return self.include(*types)
|
30
38
|
|
31
|
-
def exclude(self, *types: Player | Role | RoleGroup) ->
|
39
|
+
def exclude(self, *types: Player | Role | RoleGroup) -> PlayerSet:
|
32
40
|
return PlayerSet(
|
33
41
|
player
|
34
42
|
for player in self
|
@@ -39,7 +47,7 @@ class PlayerSet(set[Player]):
|
|
39
47
|
)
|
40
48
|
)
|
41
49
|
|
42
|
-
def player_selected(self) ->
|
50
|
+
def player_selected(self) -> PlayerSet:
|
43
51
|
return PlayerSet(p.selected for p in self.alive() if p.selected is not None)
|
44
52
|
|
45
53
|
def sorted(self) -> list[Player]:
|
nonebot_plugin_werewolf/utils.py
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
import asyncio
|
2
2
|
import asyncio.timeouts
|
3
|
+
import re
|
3
4
|
from collections import defaultdict
|
4
5
|
from typing import Annotated, Any, ClassVar
|
5
6
|
|
6
7
|
import nonebot_plugin_waiter as waiter
|
7
8
|
from nonebot.adapters import Event
|
9
|
+
from nonebot.log import logger
|
8
10
|
from nonebot.rule import to_me
|
9
11
|
from nonebot_plugin_alconna import MsgTarget, UniMessage, UniMsg
|
10
12
|
from nonebot_plugin_userinfo import EventUserInfo, UserInfo
|
11
13
|
|
12
|
-
from .
|
14
|
+
from .config import config
|
13
15
|
|
14
16
|
|
15
17
|
def check_index(text: str, arrlen: int) -> int | None:
|
@@ -47,7 +49,7 @@ def user_in_game(user_id: str, group_id: str | None) -> bool:
|
|
47
49
|
if group_id is not None and group_id not in running_games:
|
48
50
|
return False
|
49
51
|
games = running_games.values() if group_id is None else [running_games[group_id]]
|
50
|
-
for game
|
52
|
+
for game in games:
|
51
53
|
return any(user_id == player.user_id for player in game.players)
|
52
54
|
return False
|
53
55
|
|
@@ -59,7 +61,7 @@ async def rule_in_game(event: Event, target: MsgTarget) -> bool:
|
|
59
61
|
return False
|
60
62
|
if target.private:
|
61
63
|
return user_in_game(target.id, None)
|
62
|
-
|
64
|
+
if target.id in running_games:
|
63
65
|
return user_in_game(event.get_user_id(), target.id)
|
64
66
|
return False
|
65
67
|
|
@@ -92,14 +94,18 @@ async def _prepare_game_receive(
|
|
92
94
|
) -> tuple[str, str, str]:
|
93
95
|
return (
|
94
96
|
event.get_user_id(),
|
95
|
-
|
97
|
+
(
|
98
|
+
(info.user_displayname or info.user_name)
|
99
|
+
if info is not None
|
100
|
+
else event.get_user_id()
|
101
|
+
),
|
96
102
|
msg.extract_plain_text().strip(),
|
97
103
|
)
|
98
104
|
|
99
105
|
async for user, name, text in wait(default=(None, "", "")):
|
100
106
|
if user is None:
|
101
107
|
continue
|
102
|
-
await queue.put((user, name, text))
|
108
|
+
await queue.put((user, re.sub(r"[\u2066-\u2069]", "", name), text))
|
103
109
|
|
104
110
|
|
105
111
|
async def _prepare_game_handle(
|
@@ -107,26 +113,30 @@ async def _prepare_game_handle(
|
|
107
113
|
players: dict[str, str],
|
108
114
|
admin_id: str,
|
109
115
|
) -> None:
|
116
|
+
log = logger.opt(colors=True)
|
117
|
+
|
110
118
|
while True:
|
111
119
|
user, name, text = await queue.get()
|
112
120
|
msg = UniMessage.at(user)
|
121
|
+
colored = f"<y>{name}</y>(<c>{user}</c>)"
|
113
122
|
|
114
123
|
match (text, user == admin_id):
|
115
124
|
case ("开始游戏", True):
|
116
125
|
player_num = len(players)
|
117
|
-
|
126
|
+
role_preset = config.get_role_preset()
|
127
|
+
if player_num < min(role_preset):
|
118
128
|
await (
|
119
|
-
msg.text(f"游戏至少需要 {min(
|
129
|
+
msg.text(f"游戏至少需要 {min(role_preset)} 人, ")
|
120
130
|
.text(f"当前已有 {player_num} 人")
|
121
131
|
.send()
|
122
132
|
)
|
123
|
-
elif player_num > max(
|
133
|
+
elif player_num > max(role_preset):
|
124
134
|
await (
|
125
|
-
msg.text(f"游戏最多需要 {max(
|
135
|
+
msg.text(f"游戏最多需要 {max(role_preset)} 人, ")
|
126
136
|
.text(f"当前已有 {player_num} 人")
|
127
137
|
.send()
|
128
138
|
)
|
129
|
-
elif player_num not in
|
139
|
+
elif player_num not in role_preset:
|
130
140
|
await (
|
131
141
|
msg.text(f"不存在总人数为 {player_num} 的预设, ")
|
132
142
|
.text("无法开始游戏")
|
@@ -134,12 +144,14 @@ async def _prepare_game_handle(
|
|
134
144
|
)
|
135
145
|
else:
|
136
146
|
await msg.text("游戏即将开始...").send()
|
147
|
+
log.info(f"游戏发起者 {colored} 开始游戏")
|
137
148
|
return
|
138
149
|
|
139
150
|
case ("开始游戏", False):
|
140
151
|
await msg.text("只有游戏发起者可以开始游戏").send()
|
141
152
|
|
142
153
|
case ("结束游戏", True):
|
154
|
+
log.info(f"游戏发起者 {colored} 结束游戏")
|
143
155
|
await msg.text("已结束当前游戏").finish()
|
144
156
|
|
145
157
|
case ("结束游戏", False):
|
@@ -151,6 +163,7 @@ async def _prepare_game_handle(
|
|
151
163
|
case ("加入游戏", False):
|
152
164
|
if user not in players:
|
153
165
|
players[user] = name
|
166
|
+
log.info(f"玩家 {colored} 加入游戏")
|
154
167
|
await msg.text("成功加入游戏").send()
|
155
168
|
else:
|
156
169
|
await msg.text("你已经加入游戏了").send()
|
@@ -161,32 +174,29 @@ async def _prepare_game_handle(
|
|
161
174
|
case ("退出游戏", False):
|
162
175
|
if user in players:
|
163
176
|
del players[user]
|
177
|
+
log.info(f"玩家 {colored} 退出游戏")
|
164
178
|
await msg.text("成功退出游戏").send()
|
165
179
|
else:
|
166
180
|
await msg.text("你还没有加入游戏").send()
|
167
181
|
|
168
182
|
case ("当前玩家", _):
|
169
183
|
msg.text("\n当前玩家:\n")
|
170
|
-
for name in players.values():
|
171
|
-
msg.text(f"\n{name}")
|
184
|
+
for idx, name in enumerate(players.values(), 1):
|
185
|
+
msg.text(f"\n{idx}. {name}")
|
172
186
|
await msg.send()
|
173
187
|
|
174
188
|
|
175
189
|
async def prepare_game(event: Event, players: dict[str, str]) -> None:
|
190
|
+
from .game import starting_games
|
191
|
+
|
192
|
+
group_id = UniMessage.get_target(event).id
|
193
|
+
starting_games[group_id] = players
|
194
|
+
|
176
195
|
queue: asyncio.Queue[tuple[str, str, str]] = asyncio.Queue()
|
177
|
-
task_receive = asyncio.create_task(
|
178
|
-
_prepare_game_receive(
|
179
|
-
queue,
|
180
|
-
event,
|
181
|
-
UniMessage.get_target(event).id,
|
182
|
-
)
|
183
|
-
)
|
196
|
+
task_receive = asyncio.create_task(_prepare_game_receive(queue, event, group_id))
|
184
197
|
|
185
198
|
try:
|
186
|
-
await _prepare_game_handle(
|
187
|
-
queue,
|
188
|
-
players,
|
189
|
-
event.get_user_id(),
|
190
|
-
)
|
199
|
+
await _prepare_game_handle(queue, players, event.get_user_id())
|
191
200
|
finally:
|
192
201
|
task_receive.cancel()
|
202
|
+
del starting_games[group_id]
|