nonebot-plugin-werewolf 1.0.5__py3-none-any.whl → 1.0.6__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.
@@ -8,7 +8,7 @@ require("nonebot_plugin_waiter")
8
8
  from . import matchers as matchers
9
9
  from .config import Config
10
10
 
11
- __version__ = "1.0.5"
11
+ __version__ = "1.0.6"
12
12
  __plugin_meta__ = PluginMetadata(
13
13
  name="狼人杀",
14
14
  description="适用于 Nonebot2 的狼人杀插件",
@@ -4,31 +4,33 @@ from dataclasses import dataclass
4
4
  from enum import Enum, auto
5
5
  from typing import TYPE_CHECKING
6
6
 
7
+ from strenum import StrEnum
8
+
7
9
  from .config import config
8
10
 
9
11
  if TYPE_CHECKING:
10
12
  from .player import Player
11
13
 
12
14
 
13
- class Role(Enum):
15
+ class Role(StrEnum):
14
16
  # 狼人
15
- 狼人 = auto()
16
- 狼王 = auto()
17
+ Werewolf = auto()
18
+ WolfKing = auto()
17
19
 
18
20
  # 神职
19
- 预言家 = auto()
20
- 女巫 = auto()
21
- 猎人 = auto()
22
- 守卫 = auto()
23
- 白痴 = auto()
21
+ Prophet = auto()
22
+ Witch = auto()
23
+ Hunter = auto()
24
+ Guard = auto()
25
+ Idiot = auto()
24
26
 
25
27
  # 平民
26
- 平民 = auto()
28
+ Civilian = auto()
27
29
 
28
30
 
29
- class RoleGroup(Enum):
30
- 狼人 = auto()
31
- 好人 = auto()
31
+ class RoleGroup(StrEnum):
32
+ Werewolf = auto()
33
+ GoodGuy = auto()
32
34
 
33
35
 
34
36
  class KillReason(Enum):
@@ -53,6 +55,23 @@ class GameState:
53
55
  potion: tuple[Player | None, tuple[bool, bool]] = (None, (False, False))
54
56
 
55
57
 
58
+ role_name_conv: dict[Role, str] = {
59
+ Role.Werewolf: "狼人",
60
+ Role.WolfKing: "狼王",
61
+ Role.Prophet: "预言家",
62
+ Role.Witch: "女巫",
63
+ Role.Hunter: "猎人",
64
+ Role.Guard: "守卫",
65
+ Role.Idiot: "白痴",
66
+ Role.Civilian: "平民",
67
+ }
68
+
69
+
70
+ role_group_name_conv: dict[RoleGroup, str] = {
71
+ RoleGroup.Werewolf: "狼人",
72
+ RoleGroup.GoodGuy: "好人",
73
+ }
74
+
56
75
  player_preset: dict[int, tuple[int, int, int]] = {
57
76
  # 总人数: (狼, 神, 民)
58
77
  6: (1, 2, 3),
@@ -66,3 +85,4 @@ player_preset: dict[int, tuple[int, int, int]] = {
66
85
 
67
86
  if config.override_preset is not None:
68
87
  player_preset |= {i[0]: i[1:] for i in config.override_preset}
88
+ player_preset |= {i[0]: i[1:] for i in config.override_preset}
@@ -26,9 +26,13 @@ def init_players(bot: Bot, game: "Game", players: dict[str, str]) -> PlayerSet:
26
26
  )
27
27
 
28
28
  roles: list[Role] = []
29
- roles.extend([Role.狼人, Role.狼人, Role.狼王, Role.狼人][: preset[0]])
30
- roles.extend([Role.预言家, Role.女巫, Role.猎人, Role.守卫, Role.白痴][: preset[1]])
31
- roles.extend([Role.平民] * preset[2])
29
+ roles.extend(
30
+ [Role.Werewolf, Role.Werewolf, Role.WolfKing, Role.Werewolf][: preset[0]]
31
+ )
32
+ roles.extend(
33
+ [Role.Prophet, Role.Witch, Role.Hunter, Role.Guard, Role.Idiot][: preset[1]]
34
+ )
35
+ roles.extend([Role.Civilian] * preset[2])
32
36
 
33
37
  r = random.Random(time.time())
34
38
  shuffled: list[Role] = []
@@ -82,20 +86,20 @@ class Game:
82
86
 
83
87
  def at_all(self) -> UniMessage:
84
88
  msg = UniMessage()
85
- for p in sorted(self.players, key=lambda p: (p.role.name, p.user_id)):
89
+ for p in sorted(self.players, key=lambda p: (p.role_name, p.user_id)):
86
90
  msg.at(p.user_id)
87
91
  return msg
88
92
 
89
93
  def check_game_status(self) -> GameStatus:
90
94
  players = self.players.alive()
91
- w = players.select(RoleGroup.狼人)
92
- p = players.exclude(RoleGroup.狼人)
95
+ w = players.select(RoleGroup.Werewolf)
96
+ p = players.exclude(RoleGroup.Werewolf)
93
97
 
94
98
  if w.size >= p.size:
95
99
  return GameStatus.Bad
96
- if not p.select(Role.平民):
100
+ if not p.select(Role.Civilian):
97
101
  return GameStatus.Bad
98
- if not p.exclude(Role.平民):
102
+ if not p.exclude(Role.Civilian):
99
103
  return GameStatus.Bad
100
104
  if not w.size:
101
105
  return GameStatus.Good
@@ -162,7 +166,7 @@ class Game:
162
166
  ) -> None:
163
167
  players = self.players.alive().select(type_)
164
168
  text = (
165
- type_.role.name # Player
169
+ type_.role_name # Player
166
170
  if isinstance(type_, Player)
167
171
  else (
168
172
  type_.name # Role
@@ -181,8 +185,8 @@ class Game:
181
185
  players = self.players.alive()
182
186
  self.state.killed = None
183
187
 
184
- w = players.select(RoleGroup.狼人)
185
- await self.interact(RoleGroup.狼人, 120)
188
+ w = players.select(RoleGroup.Werewolf)
189
+ await self.interact(RoleGroup.Werewolf, 120)
186
190
  if (s := w.player_selected()).size == 1:
187
191
  self.state.killed = s.pop()
188
192
  await w.broadcast(f"今晚选择的目标为: {self.state.killed.name}")
@@ -190,8 +194,8 @@ class Game:
190
194
  await w.broadcast("狼人阵营意见未统一,此晚空刀")
191
195
 
192
196
  # 如果女巫存活,正常交互,限时1分钟
193
- if players.include(Role.女巫):
194
- await self.interact(Role.女巫, 60)
197
+ if players.include(Role.Witch):
198
+ await self.interact(Role.Witch, 60)
195
199
  # 否则等待 5-20s
196
200
  else:
197
201
  await asyncio.sleep(random.uniform(5, 20))
@@ -228,7 +232,7 @@ class Game:
228
232
  await self.send(
229
233
  UniMessage.text("玩家 ")
230
234
  .at(shoot.user_id)
231
- .text(f" 被{shooter.role.name}射杀, 请发表遗言\n")
235
+ .text(f" 被{shooter.role_name}射杀, 请发表遗言\n")
232
236
  .text("限时1分钟, 发送 “/stop” 结束发言")
233
237
  )
234
238
  await self.wait_stop(shoot, 60)
@@ -337,10 +341,10 @@ class Game:
337
341
  # 狼人、预言家、守卫 同时交互,女巫在狼人后交互
338
342
  await asyncio.gather(
339
343
  self.select_killed(),
340
- players.select(Role.女巫).broadcast("请等待狼人决定目标..."),
341
- players.select(Role.平民).broadcast("请等待其他玩家结束交互..."),
342
- self.interact(Role.预言家, 60),
343
- self.interact(Role.守卫, 60),
344
+ players.select(Role.Witch).broadcast("请等待狼人决定目标..."),
345
+ players.select(Role.Civilian).broadcast("请等待其他玩家结束交互..."),
346
+ self.interact(Role.Prophet, 60),
347
+ self.interact(Role.Guard, 60),
344
348
  )
345
349
 
346
350
  # 狼人击杀目标
@@ -354,10 +358,12 @@ class Game:
354
358
  if killed is not None:
355
359
  # 除非守卫保护或女巫使用解药,否则狼人正常击杀玩家
356
360
  if not ((killed is protected) or (antidote and potioned is killed)):
357
- await killed.kill(KillReason.Kill, *players.select(RoleGroup.狼人))
361
+ await killed.kill(
362
+ KillReason.Kill, *players.select(RoleGroup.Werewolf)
363
+ )
358
364
  # 如果女巫使用毒药且守卫未保护,杀死该玩家
359
365
  if poison and (potioned is not None) and (potioned is not protected):
360
- await potioned.kill(KillReason.Poison, *players.select(Role.女巫))
366
+ await potioned.kill(KillReason.Poison, *players.select(Role.Witch))
361
367
 
362
368
  day_count += 1
363
369
  msg = UniMessage.text(f"『第{day_count}天』天亮了...\n")
@@ -401,7 +407,7 @@ class Game:
401
407
  winner = "好人" if self.check_game_status() == GameStatus.Good else "狼人"
402
408
  msg = UniMessage.text(f"🎉游戏结束,{winner}获胜\n\n")
403
409
  for p in sorted(self.players, key=lambda p: (p.role.value, p.user_id)):
404
- msg.at(p.user_id).text(f": {p.role.name}\n")
410
+ msg.at(p.user_id).text(f": {p.role_name}\n")
405
411
  await self.send(msg)
406
412
  await self.send(f"玩家死亡报告:\n\n{self.show_killed_players()}")
407
413
 
@@ -3,13 +3,13 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import asyncio.timeouts
5
5
  from dataclasses import dataclass
6
- from typing import TYPE_CHECKING, ClassVar, TypeVar
6
+ from typing import TYPE_CHECKING, ClassVar, TypeVar, final
7
7
  from typing_extensions import override
8
8
 
9
9
  from nonebot.adapters import Bot
10
10
  from nonebot_plugin_alconna.uniseg import Receipt, Target, UniMessage
11
11
 
12
- from .constant import KillReason, Role, RoleGroup
12
+ from .constant import KillReason, Role, RoleGroup, role_name_conv,role_group_name_conv
13
13
  from .utils import InputStore, check_index
14
14
 
15
15
  if TYPE_CHECKING:
@@ -45,12 +45,14 @@ class Player:
45
45
  kill_info: KillInfo | None = None
46
46
  selected: Player | None = None
47
47
 
48
+ @final
48
49
  def __init__(self, bot: Bot, game: Game, user: Target, name: str) -> None:
49
50
  self.bot = bot
50
51
  self.game = game
51
52
  self.user = user
52
53
  self.name = name
53
54
 
55
+ @final
54
56
  @classmethod
55
57
  def new(
56
58
  cls,
@@ -66,23 +68,30 @@ class Player:
66
68
  return PLAYER_CLASS[role](bot, game, user, name)
67
69
 
68
70
  def __repr__(self) -> str:
69
- return f"<{self.role.name}: user={self.user} alive={self.alive}>"
71
+ return f"<{self.role_name}: user={self.user} alive={self.alive}>"
70
72
 
71
73
  @property
72
74
  def user_id(self) -> str:
73
75
  return self.user.id
74
76
 
77
+ @property
78
+ def role_name(self) -> str:
79
+ return role_name_conv[self.role]
80
+
81
+ @final
75
82
  async def send(self, message: str | UniMessage) -> Receipt:
76
83
  if isinstance(message, str):
77
84
  message = UniMessage.text(message)
78
85
 
79
86
  return await message.send(target=self.user, bot=self.bot)
80
87
 
88
+ @final
81
89
  async def receive(self, prompt: str | UniMessage | None = None) -> UniMessage:
82
90
  if prompt:
83
91
  await self.send(prompt)
84
92
  return await InputStore.fetch(self.user.id)
85
93
 
94
+ @final
86
95
  async def receive_text(self) -> str:
87
96
  return (await self.receive()).extract_plain_text()
88
97
 
@@ -90,7 +99,7 @@ class Player:
90
99
  return
91
100
 
92
101
  async def notify_role(self) -> None:
93
- await self.send(f"你的身份: {self.role.name}")
102
+ await self.send(f"你的身份: {self.role_name}")
94
103
 
95
104
  async def kill(
96
105
  self,
@@ -136,9 +145,9 @@ class CanShoot(Player):
136
145
  return await super().post_kill()
137
146
 
138
147
  await self.game.send(
139
- UniMessage.text(f"{self.role.name} ")
148
+ UniMessage.text(f"{self.role_name} ")
140
149
  .at(self.user_id)
141
- .text(f" 死了\n请{self.role.name}决定击杀目标...")
150
+ .text(f" 死了\n请{self.role_name}决定击杀目标...")
142
151
  )
143
152
 
144
153
  self.game.state.shoot = (None, None)
@@ -147,14 +156,14 @@ class CanShoot(Player):
147
156
  if shoot is not None:
148
157
  self.game.state.shoot = (self, shoot)
149
158
  await self.send(
150
- UniMessage.text(f"{self.role.name} ")
159
+ UniMessage.text(f"{self.role_name} ")
151
160
  .at(self.user_id)
152
161
  .text(" 射杀了玩家 ")
153
162
  .at(shoot.user_id)
154
163
  )
155
164
  await shoot.kill(KillReason.Shoot, self)
156
165
  else:
157
- await self.send(f"{self.role.name}选择了取消技能")
166
+ await self.send(f"{self.role_name}选择了取消技能")
158
167
  return await super().post_kill()
159
168
 
160
169
  async def shoot(self) -> Player | None:
@@ -183,23 +192,23 @@ class CanShoot(Player):
183
192
 
184
193
  @register_role
185
194
  class 狼人(Player):
186
- role: ClassVar[Role] = Role.狼人
187
- role_group: ClassVar[RoleGroup] = RoleGroup.狼人
195
+ role: ClassVar[Role] = Role.Werewolf
196
+ role_group: ClassVar[RoleGroup] = RoleGroup.Werewolf
188
197
 
189
198
  @override
190
199
  async def notify_role(self) -> None:
191
200
  await super().notify_role()
192
- partners = self.game.players.alive().select(RoleGroup.狼人).exclude(self)
201
+ partners = self.game.players.alive().select(RoleGroup.Werewolf).exclude(self)
193
202
  if partners:
194
203
  await self.send(
195
204
  "你的队友:\n"
196
- + "\n".join(f" {p.role.name}: {p.name}" for p in partners)
205
+ + "\n".join(f" {p.role_name}: {p.name}" for p in partners)
197
206
  )
198
207
 
199
208
  @override
200
209
  async def interact(self) -> None:
201
210
  players = self.game.players.alive()
202
- partners = players.select(RoleGroup.狼人).exclude(self)
211
+ partners = players.select(RoleGroup.Werewolf).exclude(self)
203
212
 
204
213
  # 避免阻塞
205
214
  def broadcast(msg: str | UniMessage):
@@ -209,7 +218,7 @@ class 狼人(Player):
209
218
  if partners:
210
219
  msg = (
211
220
  msg.text("你的队友:\n")
212
- .text("\n".join(f" {p.role.name}: {p.name}" for p in partners))
221
+ .text("\n".join(f" {p.role_name}: {p.name}" for p in partners))
213
222
  .text("\n所有私聊消息将被转发至队友\n\n")
214
223
  )
215
224
  await self.send(
@@ -245,14 +254,14 @@ class 狼人(Player):
245
254
 
246
255
  @register_role
247
256
  class 狼王(CanShoot, 狼人):
248
- role: ClassVar[Role] = Role.狼王
249
- role_group: ClassVar[RoleGroup] = RoleGroup.狼人
257
+ role: ClassVar[Role] = Role.WolfKing
258
+ role_group: ClassVar[RoleGroup] = RoleGroup.Werewolf
250
259
 
251
260
 
252
261
  @register_role
253
262
  class 预言家(Player):
254
- role: ClassVar[Role] = Role.预言家
255
- role_group: ClassVar[RoleGroup] = RoleGroup.好人
263
+ role: ClassVar[Role] = Role.Prophet
264
+ role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
256
265
 
257
266
  @override
258
267
  async def interact(self) -> None:
@@ -272,14 +281,14 @@ class 预言家(Player):
272
281
  await self.send("输入错误,请发送编号选择玩家")
273
282
 
274
283
  player = players[selected]
275
- result = "狼人" if player.role == Role.狼人 else "好人"
284
+ result = role_group_name_conv[player.role_group]
276
285
  await self.send(f"玩家 {player.name} 的阵营是『{result}』")
277
286
 
278
287
 
279
288
  @register_role
280
289
  class 女巫(Player):
281
- role: ClassVar[Role] = Role.女巫
282
- role_group: ClassVar[RoleGroup] = RoleGroup.好人
290
+ role: ClassVar[Role] = Role.Witch
291
+ role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
283
292
  antidote: int = 1
284
293
  poison: int = 1
285
294
 
@@ -367,14 +376,14 @@ class 女巫(Player):
367
376
 
368
377
  @register_role
369
378
  class 猎人(CanShoot, Player):
370
- role: ClassVar[Role] = Role.猎人
371
- role_group: ClassVar[RoleGroup] = RoleGroup.好人
379
+ role: ClassVar[Role] = Role.Hunter
380
+ role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
372
381
 
373
382
 
374
383
  @register_role
375
384
  class 守卫(Player):
376
- role: ClassVar[Role] = Role.守卫
377
- role_group: ClassVar[RoleGroup] = RoleGroup.好人
385
+ role: ClassVar[Role] = Role.Guard
386
+ role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
378
387
 
379
388
  @override
380
389
  async def interact(self) -> None:
@@ -405,8 +414,8 @@ class 守卫(Player):
405
414
 
406
415
  @register_role
407
416
  class 白痴(Player):
408
- role: ClassVar[Role] = Role.白痴
409
- role_group: ClassVar[RoleGroup] = RoleGroup.好人
417
+ role: ClassVar[Role] = Role.Idiot
418
+ role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
410
419
  voted: bool = False
411
420
 
412
421
  @override
@@ -435,5 +444,5 @@ class 白痴(Player):
435
444
 
436
445
  @register_role
437
446
  class 平民(Player):
438
- role: ClassVar[Role] = Role.平民
439
- role_group: ClassVar[RoleGroup] = RoleGroup.好人
447
+ role: ClassVar[Role] = Role.Civilian
448
+ role_group: ClassVar[RoleGroup] = RoleGroup.GoodGuy
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nonebot-plugin-werewolf
3
- Version: 1.0.5
3
+ Version: 1.0.6
4
4
  Summary: Default template for PDM package
5
5
  Author-Email: wyf7685 <wyf7685@163.com>
6
6
  License: MIT
@@ -9,6 +9,7 @@ Requires-Dist: nonebot2>=2.3.3
9
9
  Requires-Dist: nonebot-plugin-alconna>=0.52.1
10
10
  Requires-Dist: nonebot-plugin-userinfo>=0.2.6
11
11
  Requires-Dist: nonebot-plugin-waiter>=0.7.1
12
+ Requires-Dist: StrEnum>=0.4.15
12
13
  Description-Content-Type: text/markdown
13
14
 
14
15
  <div align="center">
@@ -180,6 +181,10 @@ werewolf__override_preset='
180
181
  <details>
181
182
  <summary>更新日志</summary>
182
183
 
184
+ - 2024.09.03 v1.0.6
185
+
186
+ - 修复预言家查验狼王返回好人的 bug
187
+
183
188
  - 2024.09.03 v1.0.5
184
189
 
185
190
  - 优化玩家交互体验
@@ -0,0 +1,13 @@
1
+ nonebot_plugin_werewolf-1.0.6.dist-info/METADATA,sha256=VEQ_yjPRs3bB28Khz98EJA5XTlJ6fMrP_YNZBBp9PQc,6839
2
+ nonebot_plugin_werewolf-1.0.6.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
3
+ nonebot_plugin_werewolf-1.0.6.dist-info/licenses/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
4
+ nonebot_plugin_werewolf/__init__.py,sha256=WEwQN8NtEtOfTrH23_MysaaS4OnCjxtGb-_brG9bGTQ,734
5
+ nonebot_plugin_werewolf/config.py,sha256=3O63P1pjvJEwgOwxApAHbKQzvCR1zoG5UjTClZ_OJts,315
6
+ nonebot_plugin_werewolf/constant.py,sha256=k4r0vKYtePDzAqNOdpAlSXnP37YvJSgmJvmGVoJDdeI,1746
7
+ nonebot_plugin_werewolf/game.py,sha256=oGuqV4zmuX95CH7zjtx7wMFzQjzObWXbnnO8PHSnzYk,15525
8
+ nonebot_plugin_werewolf/matchers.py,sha256=D8F2FsV03YhBfXCUeUJmpSFvMk9Z7F0lKeFx-lRN9To,2281
9
+ nonebot_plugin_werewolf/ob11_ext.py,sha256=I6bPCv5SgAStTJuvBl5F7wqgiksWeFkb4R7n06jXprA,2399
10
+ nonebot_plugin_werewolf/player.py,sha256=KjGtfMT7mZG-ACfn5z2z0UJDlLH6t1-6mls_H4UxtWU,14175
11
+ nonebot_plugin_werewolf/player_set.py,sha256=pEXyjmA7INog23i5-TmuJA559y5eKUehrPxHcnzWCTU,2571
12
+ nonebot_plugin_werewolf/utils.py,sha256=8ddVr_PyObxZ8PfWry_-IXnH2dys2bTowKmHfqVbhPE,6233
13
+ nonebot_plugin_werewolf-1.0.6.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- nonebot_plugin_werewolf-1.0.5.dist-info/METADATA,sha256=YAMSQ9RZA-0jUe8o1iXg5zLy-vNh7AEcpoo9ek_ar-E,6735
2
- nonebot_plugin_werewolf-1.0.5.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
3
- nonebot_plugin_werewolf-1.0.5.dist-info/licenses/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
4
- nonebot_plugin_werewolf/__init__.py,sha256=7Kp0xiD5XhE803lRegOex0oEe3ZfCEnPOxSd1FqdhWM,734
5
- nonebot_plugin_werewolf/config.py,sha256=3O63P1pjvJEwgOwxApAHbKQzvCR1zoG5UjTClZ_OJts,315
6
- nonebot_plugin_werewolf/constant.py,sha256=MUqLz4jXfXPWc8wJdUXb0yaU0BcXZ_xbGM0Sn3IhAr4,1260
7
- nonebot_plugin_werewolf/game.py,sha256=3W_oghotlxbUgp7RaFmzla-CW-MVzNdYRb7JD7Xp_UU,15437
8
- nonebot_plugin_werewolf/matchers.py,sha256=D8F2FsV03YhBfXCUeUJmpSFvMk9Z7F0lKeFx-lRN9To,2281
9
- nonebot_plugin_werewolf/ob11_ext.py,sha256=I6bPCv5SgAStTJuvBl5F7wqgiksWeFkb4R7n06jXprA,2399
10
- nonebot_plugin_werewolf/player.py,sha256=AqeYhILjFEuPO0rXbp9dnCmUZO_dk0MODg_jXjwduyI,13986
11
- nonebot_plugin_werewolf/player_set.py,sha256=pEXyjmA7INog23i5-TmuJA559y5eKUehrPxHcnzWCTU,2571
12
- nonebot_plugin_werewolf/utils.py,sha256=8ddVr_PyObxZ8PfWry_-IXnH2dys2bTowKmHfqVbhPE,6233
13
- nonebot_plugin_werewolf-1.0.5.dist-info/RECORD,,