nonebot-plugin-werewolf 1.1.9__py3-none-any.whl → 1.1.11__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.
@@ -10,7 +10,7 @@ from . import matchers as matchers
10
10
  from . import players as players
11
11
  from .config import Config
12
12
 
13
- __version__ = "1.1.9"
13
+ __version__ = "1.1.11"
14
14
  __plugin_meta__ = PluginMetadata(
15
15
  name="狼人杀",
16
16
  description="适用于 Nonebot2 的狼人杀插件",
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from pathlib import Path
3
- from typing import Any, ClassVar, Final
3
+ from typing import Any, ClassVar, Final, Literal
4
4
  from typing_extensions import Self
5
5
 
6
6
  import nonebot
@@ -83,10 +83,26 @@ class GameBehavior(ConfigFile):
83
83
  timeout: Final[_Timeout] = _Timeout()
84
84
 
85
85
 
86
+ class RequireAtConfig(BaseModel):
87
+ start: bool = True
88
+ terminate: bool = True
89
+
90
+
91
+ class MatcherPriorityConfig(BaseModel):
92
+ start: int = 1
93
+ terminate: int = 1
94
+ preset: int = 1
95
+ behavior: int = 1
96
+ in_game: int = 10
97
+ stop: int = 10
98
+
99
+
86
100
  class PluginConfig(BaseModel):
87
101
  enable_poke: bool = True
88
102
  enable_button: bool = False
89
103
  stop_command: str | set[str] = "stop"
104
+ require_at: bool | RequireAtConfig = True
105
+ matcher_priority: MatcherPriorityConfig = MatcherPriorityConfig()
90
106
 
91
107
  def get_stop_command(self) -> list[str]:
92
108
  return (
@@ -95,6 +111,11 @@ class PluginConfig(BaseModel):
95
111
  else sorted(self.stop_command, key=len)
96
112
  )
97
113
 
114
+ def get_require_at(self, cmd: Literal["start", "terminate"]) -> bool:
115
+ if isinstance(self.require_at, bool):
116
+ return self.require_at
117
+ return getattr(self.require_at, cmd)
118
+
98
119
 
99
120
  class Config(BaseModel):
100
121
  werewolf: PluginConfig = PluginConfig()
@@ -1,20 +1,18 @@
1
1
  import functools
2
2
  from typing import TYPE_CHECKING
3
3
 
4
- import nonebot
5
-
6
4
  from .models import GameStatus, KillReason, Role, RoleGroup
7
5
 
8
6
  STOP_COMMAND = "{{stop}}"
9
- COMMAND_START = next(
10
- iter(sorted(nonebot.get_driver().config.command_start, key=len)), ""
11
- )
12
7
 
13
8
 
14
9
  def stop_command_prompt() -> str:
10
+ import nonebot
11
+
15
12
  from .config import config # circular import
16
13
 
17
- return COMMAND_START + config.get_stop_command()[0]
14
+ cmd_starts = sorted(nonebot.get_driver().config.command_start, key=len)
15
+ return next(iter(cmd_starts), "") + config.get_stop_command()[0]
18
16
 
19
17
 
20
18
  if not TYPE_CHECKING:
@@ -1,7 +1,7 @@
1
1
  import contextlib
2
2
  import functools
3
3
  import secrets
4
- from collections import defaultdict
4
+ from collections import Counter
5
5
  from typing import NoReturn, final
6
6
  from typing_extensions import Self
7
7
 
@@ -10,8 +10,8 @@ import nonebot
10
10
  from nonebot.adapters import Bot
11
11
  from nonebot.utils import escape_tag
12
12
  from nonebot_plugin_alconna import At, Target, UniMessage
13
- from nonebot_plugin_alconna.uniseg.message import Receipt
14
- from nonebot_plugin_uninfo import Interface, SceneType
13
+ from nonebot_plugin_alconna.uniseg.receipt import Receipt
14
+ from nonebot_plugin_uninfo import Interface, Scene, SceneType
15
15
 
16
16
  from .config import GameBehavior, PresetData
17
17
  from .constant import GAME_STATUS_CONV, REPORT_TEXT, ROLE_EMOJI, ROLE_NAME_CONV
@@ -162,11 +162,10 @@ class Game:
162
162
  self.state = GameState(0)
163
163
  self.killed_players = []
164
164
  self._player_map: dict[str, Player] = {}
165
- self._scene = None
166
- self._finished = None
167
- self._task_group = None
168
- self._send_handler = _SendHandler()
169
- self._send_handler.update(group, bot)
165
+ self._shuffled: list[Player] = []
166
+ self._scene: Scene | None = None
167
+ self._finished = self._task_group = None
168
+ self._send_handler = _SendHandler(group, bot)
170
169
 
171
170
  @final
172
171
  @classmethod
@@ -185,6 +184,7 @@ class Game:
185
184
 
186
185
  self.players = await init_players(bot, self, players, interface)
187
186
  self._player_map |= {p.user_id: p for p in self.players}
187
+ self._shuffled = self.players.shuffled
188
188
 
189
189
  return self
190
190
 
@@ -258,12 +258,9 @@ class Game:
258
258
  )
259
259
 
260
260
  if self.behavior.show_roles_list_on_start:
261
- role_cnt: dict[Role, int] = defaultdict(lambda: 0)
262
- for role in sorted((p.role for p in self.players), key=lambda r: r.value):
263
- role_cnt[role] += 1
264
-
265
261
  msg.text("\n\n📚职业列表:\n")
266
- for role, cnt in role_cnt.items():
262
+ counter = Counter(p.role for p in self.players)
263
+ for role, cnt in sorted(counter.items(), key=lambda x: x[0].value):
267
264
  msg.text(f"- {ROLE_EMOJI[role]}{ROLE_NAME_CONV[role]}x{cnt}\n")
268
265
 
269
266
  async with anyio.create_task_group() as tg:
@@ -340,23 +337,24 @@ class Game:
340
337
  timeout = self.behavior.timeout
341
338
 
342
339
  if not self.behavior.speak_in_turn:
343
- speak_timeout = timeout.group_speak
344
340
  await self.send(
345
341
  f"💬接下来开始自由讨论\n{timeout.group_speak_timeout_prompt}",
346
342
  stop_btn_label="结束发言",
347
343
  )
348
- await self.wait_stop(*self.players.alive(), timeout_secs=speak_timeout)
344
+ await self.wait_stop(
345
+ *self.players.alive(),
346
+ timeout_secs=timeout.group_speak,
347
+ )
349
348
  else:
350
349
  await self.send("💬接下来开始轮流发言")
351
- speak_timeout = timeout.speak
352
- for player in self.players.alive().sorted:
350
+ for player in filter(lambda p: p.alive, self._shuffled):
353
351
  await self.send(
354
352
  UniMessage.text("💬")
355
353
  .at(player.user_id)
356
354
  .text(f"\n轮到你发言\n{timeout.speak_timeout_prompt}"),
357
355
  stop_btn_label="结束发言",
358
356
  )
359
- await self.wait_stop(player, timeout_secs=speak_timeout)
357
+ await self.wait_stop(player, timeout_secs=timeout.speak)
360
358
  await self.send("💬所有玩家发言结束")
361
359
 
362
360
  async def run_vote(self) -> None:
@@ -1,7 +1,7 @@
1
1
  import itertools
2
2
 
3
3
  from nonebot.adapters import Bot, Event
4
- from nonebot_plugin_alconna import MsgTarget, UniMessage
4
+ from nonebot_plugin_alconna import MsgTarget, get_target
5
5
 
6
6
  from ..game import Game, get_running_games
7
7
 
@@ -27,7 +27,7 @@ async def rule_in_game(bot: Bot, event: Event) -> bool:
27
27
  return False
28
28
 
29
29
  try:
30
- target = UniMessage.get_target(event, bot)
30
+ target = get_target(event, bot)
31
31
  except NotImplementedError:
32
32
  return False
33
33
 
@@ -15,7 +15,7 @@ from nonebot_plugin_alconna import (
15
15
  on_alconna,
16
16
  )
17
17
 
18
- from ..config import GameBehavior
18
+ from ..config import GameBehavior, config
19
19
 
20
20
  GAME_BEHAVIOR_CACHE_KEY = "GAME_BEHAVIOR_CACHE_KEY"
21
21
 
@@ -118,7 +118,7 @@ alc = Alconna(
118
118
  edit_behavior = on_alconna(
119
119
  alc,
120
120
  permission=SUPERUSER,
121
- use_cmd_start=True,
121
+ priority=config.matcher_priority.behavior,
122
122
  )
123
123
 
124
124
 
@@ -145,7 +145,10 @@ async def set_dead_chat(behavior: Behavior, limit: int) -> None:
145
145
  @edit_behavior.assign("werewolf_multi_select")
146
146
  async def set_werewolf_multi_select(behavior: Behavior, enabled: bool) -> None:
147
147
  behavior.werewolf_multi_select = enabled
148
- await finish(f"已{'启用' if enabled else '禁用'}狼人多选")
148
+ await finish(
149
+ f"已{'启用' if enabled else '禁用'}狼人多选\n"
150
+ "注: 狼人意见未统一时随机选择已选玩家"
151
+ )
149
152
 
150
153
 
151
154
  @edit_behavior.assign("timeout.prepare")
@@ -205,13 +208,14 @@ async def handle_default(behavior: Behavior) -> None:
205
208
  f"游戏开始发送职业列表: {'是' if behavior.show_roles_list_on_start else '否'}",
206
209
  f"白天讨论按顺序发言: {'是' if behavior.speak_in_turn else '否'}",
207
210
  f"死亡玩家发言转发限制: {behavior.dead_channel_rate_limit} 次/分钟",
211
+ f"狼人多选(意见未统一时随机选择已选玩家): {'是' if behavior.werewolf_multi_select else '否'}", # noqa: E501
208
212
  "",
209
213
  "超时时间设置:",
210
214
  f"准备阶段: {timeout.prepare} 秒",
211
215
  f"个人发言: {timeout.speak} 秒",
212
216
  f"集体发言: {timeout.group_speak} 秒",
213
- f"交互阶段: {timeout.interact} 秒",
214
217
  f"投票阶段: {timeout.vote} 秒",
218
+ f"交互阶段: {timeout.interact} 秒",
215
219
  f"狼人交互: {timeout.werewolf} 秒",
216
220
  ]
217
221
  await finish("\n".join(lines))
@@ -1,6 +1,6 @@
1
1
  from typing import Any, NoReturn
2
2
 
3
- import nonebot_plugin_waiter as waiter
3
+ import nonebot_plugin_waiter.unimsg as waiter
4
4
  from arclet.alconna import AllParam
5
5
  from nonebot.permission import SUPERUSER
6
6
  from nonebot.typing import T_State
@@ -14,7 +14,7 @@ from nonebot_plugin_alconna import (
14
14
  on_alconna,
15
15
  )
16
16
 
17
- from ..config import PresetData
17
+ from ..config import PresetData, config
18
18
  from ..constant import ROLE_NAME_CONV
19
19
  from ..models import Role
20
20
 
@@ -48,8 +48,8 @@ alc = Alconna(
48
48
  help_text="设置神职优先级",
49
49
  ),
50
50
  Subcommand(
51
- "joker",
52
- Args["probability?#概率", float],
51
+ "jester",
52
+ Args["probability?#概率(百分比)", float],
53
53
  alias={"小丑"},
54
54
  help_text="设置小丑概率",
55
55
  ),
@@ -73,7 +73,7 @@ alc = Alconna(
73
73
  edit_preset = on_alconna(
74
74
  alc,
75
75
  permission=SUPERUSER,
76
- use_cmd_start=True,
76
+ priority=config.matcher_priority.preset,
77
77
  )
78
78
 
79
79
 
@@ -82,8 +82,7 @@ async def finish(text: str) -> NoReturn:
82
82
 
83
83
 
84
84
  def display_roles(roles: list[Role]) -> str:
85
- role_name = ROLE_NAME_CONV.__getitem__
86
- return ", ".join(map(role_name, roles))
85
+ return ", ".join(map(ROLE_NAME_CONV.__getitem__, roles))
87
86
 
88
87
 
89
88
  @edit_preset.assign("role")
@@ -217,8 +216,8 @@ async def assign_priesthood(state: T_State) -> None:
217
216
  await finish("设置成功: " + display_roles(result))
218
217
 
219
218
 
220
- @edit_preset.assign("joker")
221
- async def assign_joker(probability: Match[float]) -> None:
219
+ @edit_preset.assign("jester")
220
+ async def assign_jester(probability: Match[float]) -> None:
222
221
  if not probability.available:
223
222
  result = await waiter.prompt_until(
224
223
  message="请发送小丑概率,范围 0-100\n发送 “取消” 取消操作",
@@ -7,7 +7,10 @@ from ..constant import STOP_COMMAND
7
7
  from ..utils import InputStore
8
8
  from .depends import rule_in_game
9
9
 
10
- message_in_game = on_message(rule=rule_in_game, priority=10)
10
+ message_in_game = on_message(
11
+ rule=rule_in_game,
12
+ priority=config.matcher_priority.in_game,
13
+ )
11
14
 
12
15
 
13
16
  @message_in_game.handle()
@@ -24,6 +27,7 @@ stopcmd = on_alconna(
24
27
  block=True,
25
28
  use_cmd_start=True,
26
29
  aliases=set(aliases) if (aliases := config.get_stop_command()[1:]) else None,
30
+ priority=config.matcher_priority.stop,
27
31
  )
28
32
 
29
33
 
@@ -1,3 +1,4 @@
1
+ from ...config import config
1
2
  from .chronocat_poke import chronocat_poke_enabled
2
3
  from .ob11_poke import ob11_poke_enabled
3
4
 
@@ -5,4 +6,4 @@ checks = [chronocat_poke_enabled, ob11_poke_enabled]
5
6
 
6
7
 
7
8
  def poke_enabled() -> bool:
8
- return any(check() for check in checks)
9
+ return config.enable_poke and any(check() for check in checks)
@@ -15,7 +15,10 @@ def chronocat_poke_enabled() -> bool:
15
15
  return False
16
16
 
17
17
 
18
- with contextlib.suppress(ImportError):
18
+ with contextlib.suppress(ImportError, RuntimeError):
19
+ if not config.enable_poke:
20
+ raise RuntimeError # skip matcher definition
21
+
19
22
  from nonebot.adapters.satori import Bot
20
23
  from nonebot.adapters.satori.event import (
21
24
  MessageCreatedEvent,
@@ -46,8 +49,6 @@ with contextlib.suppress(ImportError):
46
49
 
47
50
  # 游戏内戳一戳等效 "stop" 命令
48
51
  async def _rule_poke_stop(bot: Bot, event: MessageCreatedEvent) -> bool:
49
- if not config.enable_poke:
50
- return False
51
52
  return extract_poke_tome(event) is not None and (
52
53
  user_in_game(bot.self_id, *extract_user_group(event))
53
54
  )
@@ -66,9 +67,6 @@ with contextlib.suppress(ImportError):
66
67
  event: PublicMessageCreatedEvent,
67
68
  target: MsgTarget,
68
69
  ) -> bool:
69
- if not config.enable_poke:
70
- return False
71
-
72
70
  return (
73
71
  (user_id := extract_poke_tome(event)) is not None
74
72
  and not user_in_game(
@@ -110,9 +108,6 @@ with contextlib.suppress(ImportError):
110
108
  await UniMessage.at(user_id).text("\n✅成功加入游戏").send(target, bot)
111
109
 
112
110
  def chronocat_poke_enabled() -> bool:
113
- if not config.enable_poke:
114
- return False
115
-
116
111
  event = current_event.get()
117
112
  return (
118
113
  isinstance(event, MessageCreatedEvent)
@@ -15,15 +15,15 @@ def ob11_poke_enabled() -> bool:
15
15
  return False
16
16
 
17
17
 
18
- with contextlib.suppress(ImportError):
18
+ with contextlib.suppress(ImportError, RuntimeError):
19
+ if not config.enable_poke:
20
+ raise RuntimeError # skip matcher definition
21
+
19
22
  from nonebot.adapters.onebot.v11 import Bot
20
23
  from nonebot.adapters.onebot.v11.event import PokeNotifyEvent
21
24
 
22
25
  # 游戏内戳一戳等效 "stop" 命令
23
26
  async def _rule_poke_stop(bot: Bot, event: PokeNotifyEvent) -> bool:
24
- if not config.enable_poke:
25
- return False
26
-
27
27
  user_id = str(event.user_id)
28
28
  group_id = str(event.group_id) if event.group_id is not None else None
29
29
  return (event.target_id == event.self_id) and user_in_game(
@@ -42,7 +42,7 @@ with contextlib.suppress(ImportError):
42
42
  async def _rule_poke_join(
43
43
  bot: Bot, event: PokeNotifyEvent, target: MsgTarget
44
44
  ) -> bool:
45
- if not config.enable_poke or event.group_id is None:
45
+ if event.group_id is None:
46
46
  return False
47
47
 
48
48
  user_id = str(event.user_id)
@@ -74,7 +74,4 @@ with contextlib.suppress(ImportError):
74
74
  await UniMessage.at(user_id).text("\n✅成功加入游戏").send(target, bot)
75
75
 
76
76
  def ob11_poke_enabled() -> bool:
77
- if not config.enable_poke:
78
- return False
79
-
80
77
  return isinstance(current_bot.get(), Bot)
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  import anyio
7
7
  import nonebot
8
- import nonebot_plugin_waiter as waiter
8
+ import nonebot_plugin_waiter.unimsg as waiter
9
9
  from nonebot.adapters import Bot, Event
10
10
  from nonebot.internal.matcher import current_bot
11
11
  from nonebot.permission import SuperUser
@@ -21,12 +21,13 @@ from nonebot_plugin_alconna import (
21
21
  Target,
22
22
  UniMessage,
23
23
  UniMsg,
24
+ get_target,
24
25
  on_alconna,
25
26
  )
26
27
  from nonebot_plugin_localstore import get_plugin_data_file
27
28
  from nonebot_plugin_uninfo import QryItrface, Uninfo
28
29
 
29
- from ..config import GameBehavior, PresetData
30
+ from ..config import GameBehavior, PresetData, config
30
31
  from ..constant import stop_command_prompt
31
32
  from ..game import Game, get_running_games, get_starting_games
32
33
  from ..utils import ObjectStream, SendHandler, extract_session_member_nick
@@ -41,9 +42,11 @@ start_game = on_alconna(
41
42
  "werewolf",
42
43
  Option("restart|-r|--restart|重开", dest="restart"),
43
44
  ),
44
- rule=to_me() & rule_not_in_game,
45
+ rule=to_me() & rule_not_in_game
46
+ if config.get_require_at("start")
47
+ else rule_not_in_game,
45
48
  aliases={"狼人杀"},
46
- use_cmd_start=True,
49
+ priority=config.matcher_priority.start,
47
50
  )
48
51
  player_data_file = get_plugin_data_file("players.json")
49
52
  if not player_data_file.exists():
@@ -112,7 +115,7 @@ class PrepareGame:
112
115
  def __init__(self, event: Event, players: dict[str, str]) -> None:
113
116
  self.event = event
114
117
  self.admin_id = event.get_user_id()
115
- self.group = UniMessage.get_target(event)
118
+ self.group = get_target(event)
116
119
  self.stream = ObjectStream[tuple[Event, str, str]](16)
117
120
  self.players = players
118
121
  self.send_handler = self._SendHandler()
@@ -1,24 +1,32 @@
1
+ from typing import Annotated
2
+
3
+ from nonebot.params import Depends
1
4
  from nonebot.permission import SUPERUSER
2
5
  from nonebot.rule import to_me
3
6
  from nonebot_plugin_alconna import Alconna, MsgTarget, UniMessage, on_alconna
4
7
 
5
- from ..game import get_running_games
6
-
7
-
8
- def rule_game_running(target: MsgTarget) -> bool:
9
- return any(target.verify(g.group) for g in get_running_games())
10
-
8
+ from ..config import config
9
+ from ..game import Game, get_running_games
11
10
 
12
- force_stop = on_alconna(
11
+ terminate = on_alconna(
13
12
  Alconna("中止游戏"),
14
- rule=to_me() & rule_game_running,
13
+ rule=to_me() if config.get_require_at("terminate") else None,
15
14
  permission=SUPERUSER,
16
- use_cmd_start=True,
15
+ priority=config.matcher_priority.terminate,
17
16
  )
18
17
 
19
18
 
20
- @force_stop.handle()
21
- async def _(target: MsgTarget) -> None:
22
- game = next(g for g in get_running_games() if target.verify(g.group))
19
+ async def running_game(target: MsgTarget) -> Game:
20
+ for game in get_running_games():
21
+ if target.verify(game.group):
22
+ return game
23
+ return terminate.skip()
24
+
25
+
26
+ RunningGame = Annotated[Game, Depends(running_game)]
27
+
28
+
29
+ @terminate.handle()
30
+ async def _(game: RunningGame) -> None:
23
31
  game.terminate()
24
32
  await UniMessage.text("已中止当前群组的游戏进程").finish(reply_to=True)
@@ -129,8 +129,7 @@ class Player:
129
129
  self.bot = bot
130
130
  self.killed = anyio.Event()
131
131
  self._member = None
132
- self._send_handler = _SendHandler()
133
- self._send_handler.update(self.__user, bot)
132
+ self._send_handler = _SendHandler(self.__user, bot)
134
133
 
135
134
  @final
136
135
  @override
@@ -1,6 +1,7 @@
1
1
  import functools
2
2
  import random
3
3
  from collections.abc import Iterable
4
+ from collections.abc import Set as AbstractSet
4
5
  from typing_extensions import Self
5
6
 
6
7
  import anyio
@@ -100,3 +101,12 @@ class PlayerSet(set[Player]):
100
101
 
101
102
  def __getitem__(self, index: int, /) -> Player:
102
103
  return self.sorted[index]
104
+
105
+ def __and__(self, other: AbstractSet[Player], /) -> Self: # type: ignore[override]
106
+ return self.from_(super().__and__(other))
107
+
108
+ def __or__(self, other: AbstractSet[Player], /) -> Self: # type: ignore[override]
109
+ return self.from_(super().__or__(other))
110
+
111
+ def __sub__(self, other: AbstractSet[Player], /) -> Self: # type: ignore[override]
112
+ return self.from_(super().__sub__(other))
@@ -190,11 +190,19 @@ def add_players_button(msg: str | UniMessage, players: "PlayerSet") -> UniMessag
190
190
 
191
191
  class SendHandler(abc.ABC, Generic[P]):
192
192
  bot: Bot
193
- target: Event | Target
193
+ target: Event | Target | None
194
194
  reply_to: bool | None = None
195
195
  last_msg: UniMessage | None = None
196
196
  last_receipt: Receipt | None = None
197
197
 
198
+ def __init__(
199
+ self,
200
+ target: Event | Target | None = None,
201
+ bot: Bot | None = None,
202
+ ) -> None:
203
+ self.bot = bot or current_bot.get()
204
+ self.target = target
205
+
198
206
  def update(self, target: Event | Target, bot: Bot | None = None) -> None:
199
207
  self.bot = bot or current_bot.get()
200
208
  self.target = target
@@ -210,6 +218,9 @@ class SendHandler(abc.ABC, Generic[P]):
210
218
  await last.edit(self.last_msg.exclude(Keyboard))
211
219
 
212
220
  async def _send(self, message: UniMessage) -> None:
221
+ if self.target is None:
222
+ raise RuntimeError("Target cannot be None when sending a message.")
223
+
213
224
  if not config.enable_button:
214
225
  message = message.exclude(Keyboard)
215
226
  receipt = await message.send(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-werewolf
3
- Version: 1.1.9
3
+ Version: 1.1.11
4
4
  Summary: 适用于 Nonebot2 的狼人杀插件
5
5
  Author-email: wyf7685 <wyf7685@163.com>
6
6
  License: MIT
@@ -10,11 +10,11 @@ Project-URL: bug-tracker, https://github.com/wyf7685/nonebot-plugin-werewolf/iss
10
10
  Requires-Python: >=3.10
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: nonebot2>=2.3.3
14
- Requires-Dist: nonebot-plugin-alconna>=0.52.1
13
+ Requires-Dist: nonebot2>=2.4.0
14
+ Requires-Dist: nonebot-plugin-alconna>=0.57.0
15
15
  Requires-Dist: nonebot-plugin-localstore>=0.7.1
16
- Requires-Dist: nonebot-plugin-uninfo>=0.4.0
17
- Requires-Dist: nonebot-plugin-waiter>=0.7.1
16
+ Requires-Dist: nonebot-plugin-uninfo>=0.7.3
17
+ Requires-Dist: nonebot-plugin-waiter>=0.8.0
18
18
  Requires-Dist: anyio>=4.6.0
19
19
  Dynamic: license-file
20
20
 
@@ -39,7 +39,8 @@ _✨ 简单的狼人杀插件 ✨_
39
39
  [![pre-commit](https://results.pre-commit.ci/badge/github/wyf7685/nonebot-plugin-werewolf/master.svg)](https://results.pre-commit.ci/latest/github/wyf7685/nonebot-plugin-werewolf/master)
40
40
  [![lint](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/lint.yml/badge.svg?branch=master&event=push)](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/lint.yml)
41
41
 
42
- <!-- https://github.com/lgc2333/nonebot-registry-badge -->
42
+ <!-- ref: https://github.com/lgc2333/nonebot-registry-badge -->
43
+
43
44
  [![NoneBot Registry](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin%2Fnonebot-plugin-werewolf)](https://registry.nonebot.dev/plugin/nonebot-plugin-werewolf:nonebot_plugin_werewolf)
44
45
  [![Supported Adapters](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin-adapters%2Fnonebot-plugin-werewolf)](https://registry.nonebot.dev/plugin/nonebot-plugin-werewolf:nonebot_plugin_werewolf)
45
46
 
@@ -53,7 +54,7 @@ _✨ 简单的狼人杀插件 ✨_
53
54
 
54
55
  > [!note]
55
56
  >
56
- > 请确保 NoneBot2 使用的 Python 解释器版本 >=3.10
57
+ > 请确保 [NoneBot2](https://nonebot.dev/) 使用的 Python 解释器版本 >=3.10
57
58
 
58
59
  <details open>
59
60
  <summary>使用 nb-cli 安装</summary>
@@ -65,12 +66,14 @@ _✨ 简单的狼人杀插件 ✨_
65
66
 
66
67
  <details>
67
68
  <summary>使用包管理器安装</summary>
69
+ <!-- 会用包管理器的用户真的需要这节吗 -->
70
+
68
71
  在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
69
72
 
70
- <details>
71
- <summary>pip</summary>
73
+ <details open>
74
+ <summary>uv</summary>
72
75
 
73
- pip install nonebot-plugin-werewolf
76
+ uv add nonebot-plugin-werewolf
74
77
 
75
78
  </details>
76
79
  <details>
@@ -90,6 +93,12 @@ _✨ 简单的狼人杀插件 ✨_
90
93
 
91
94
  conda install nonebot-plugin-werewolf
92
95
 
96
+ </details>
97
+ <details>
98
+ <summary>pip</summary>
99
+
100
+ pip install nonebot-plugin-werewolf
101
+
93
102
  </details>
94
103
 
95
104
  打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
@@ -102,16 +111,39 @@ _✨ 简单的狼人杀插件 ✨_
102
111
 
103
112
  在 nonebot2 项目的 `.env` 文件中添加如下配置:
104
113
 
105
- | 配置项 | 必填 | 默认值 | 说明 |
106
- | :-----------------------: | :---: | :-----: | :--------------------------: |
107
- | `werewolf__enable_poke` | 否 | `True` | 是否使用戳一戳简化操作流程 |
108
- | `werewolf__enable_button` | 否 | `False` | 是否在交互中添加按钮 |
109
- | `werewolf__stop_command` | 否 | `stop` | 修改游戏进程中的 `stop` 命令 |
114
+ | 配置项 | 必填 | 默认值 | 类型 | 说明 |
115
+ | :--------------------------: | :--: | :-----: | :-----------------------: | :----------------------------: |
116
+ | `werewolf__enable_poke` | 否 | `True` | `bool` | 是否使用戳一戳简化操作流程 |
117
+ | `werewolf__enable_button` | 否 | `False` | `bool` | 是否在交互中添加按钮 |
118
+ | `werewolf__stop_command` | 否 | `stop` | `str \| set[str]` | 修改游戏进程中的 `stop` 命令 |
119
+ | `werewolf__require_at` | 否 | `True` | `bool \| RequireAtConfig` | 部分命令是否需要 at 机器人触发 |
120
+ | `werewolf__matcher_priority` | 否 | - | `MatcherPriorityConfig` | 配置插件 matcher 注册的优先级 |
110
121
 
111
122
  `werewolf__enable_poke` 仅在 `OneBot V11` 适配器 / `Satori/chronocat` 下生效
112
123
 
113
124
  `werewolf__enable_button` 仅在 `Telegram` 适配器下通过测试,不保证在其他适配器的可用性。如有疑问欢迎提出。
114
125
 
126
+ <details>
127
+ <summary> werewolf__require_at 示例 </summary>
128
+
129
+ ```ini
130
+ # 所有命令均需 at 触发
131
+ werewolf__require_at=true
132
+
133
+ # 所有命令均不需 at 触发
134
+ werewolf__require_at=false
135
+
136
+ # 狼人杀命令需要 at, 中止游戏命令不需要 at
137
+ werewolf__require_at='{"start": true, "terminate": false}'
138
+ ```
139
+ </details>
140
+ <br/>
141
+
142
+ `werewolf__matcher_priority` 的 matcher 优先级参考 [官方文档](https://nonebot.dev/docs/advanced/matcher#%E5%93%8D%E5%BA%94%E4%BC%98%E5%85%88%E7%BA%A7)
143
+ - 一般情况下不需要修改此配置, 插件的默认优先级可以参考 [这里](./nonebot_plugin_werewolf/config.py) 的 `MatcherPriorityConfig`
144
+ - 如果遇到与其他插件的命令冲突, 可考虑修改此处的优先级配置
145
+ - 配置应填入 JSON 对象, 可用键: `start` `terminate` `preset` `behavior` `in_game` `stop`
146
+
115
147
  ## 🎉 使用
116
148
 
117
149
  > [!note]
@@ -135,28 +167,29 @@ _✨ 简单的狼人杀插件 ✨_
135
167
 
136
168
  ### 指令表
137
169
 
138
- | 指令 | 权限 | 需要@ | 范围 | 说明 |
139
- | :-----------------: | :-----------------: | :---: | :---: | :---------------------------------------: |
140
- | `werewolf`/`狼人杀` | 群员 | 是 | 群聊 | 发起游戏 (进入准备阶段) |
141
- | `开始游戏` | 游戏发起者 | 否 | 群聊 | _[准备阶段]_ 游戏发起者开始游戏 |
142
- | `结束游戏` | 游戏发起者/超级用户 | 否 | 群聊 | _[准备阶段]_ 游戏发起者/超级用户 结束游戏 |
143
- | `当前玩家` | 群员 | 否 | 群聊 | _[准备阶段]_ 列出参与游戏的玩家列表 |
144
- | `加入游戏` | 群员 | 否 | 群聊 | _[准备阶段]_ 玩家加入游戏 |
145
- | `退出游戏` | 群员 | 否 | 群聊 | _[准备阶段]_ 玩家退出游戏 |
146
- | `中止游戏` | 超级用户 | 是 | 群聊 | _[游戏内]_ 超级用户强制中止游戏 |
147
- | `狼人杀预设` | 超级用户 | 否 | 任意 | _[游戏外]_ 超级用户编辑游戏预设 |
148
- | `狼人杀配置` | 超级用户 | 否 | 任意 | _[游戏外]_ 超级用户编辑游戏配置 |
170
+ | 指令 | 权限 | 需要@ | 范围 | 说明 |
171
+ | :-----------------: | :-----------------: | :---: | :--: | :---------------------------------------: |
172
+ | `werewolf`/`狼人杀` | 群员 | 是 | 群聊 | 发起游戏 (进入准备阶段) |
173
+ | `开始游戏` | 游戏发起者 | 否 | 群聊 | _[准备阶段]_ 游戏发起者开始游戏 |
174
+ | `结束游戏` | 游戏发起者/超级用户 | 否 | 群聊 | _[准备阶段]_ 游戏发起者/超级用户 结束游戏 |
175
+ | `当前玩家` | 群员 | 否 | 群聊 | _[准备阶段]_ 列出参与游戏的玩家列表 |
176
+ | `加入游戏` | 群员 | 否 | 群聊 | _[准备阶段]_ 玩家加入游戏 |
177
+ | `退出游戏` | 群员 | 否 | 群聊 | _[准备阶段]_ 玩家退出游戏 |
178
+ | `中止游戏` | 超级用户 | 是 | 群聊 | _[游戏内]_ 超级用户强制中止游戏 |
179
+ | `狼人杀预设` | 超级用户 | 否 | 任意 | _[游戏外]_ 超级用户编辑游戏预设 |
180
+ | `狼人杀配置` | 超级用户 | 否 | 任意 | _[游戏外]_ 超级用户编辑游戏配置 |
149
181
 
150
- - 发起游戏时添加 `restart`/`重开`, 可加载上一次游戏的玩家列表, 快速发起游戏。例: `werewolf restart`/`狼人杀 重开`
182
+ - `超级用户` nonebot2 配置项中的 `SUPERUSERS`, 配置说明参考 [官方文档](https://nonebot.dev/docs/appendices/config#superusers)
151
183
 
152
- - `狼人杀预设` 命令用法可通过 `狼人杀预设 --help` 获取,或参考 [游戏内容](#游戏内容) 部分的介绍
184
+ - 发起游戏时添加 `restart`/`重开`, 可加载上一次游戏的玩家列表, 快速发起游戏。例: `werewolf restart`/`狼人杀 重开`
153
185
 
154
- - `狼人杀配置` 命令用法可通过 `狼人杀预设 --help` 获取
186
+ - `狼人杀预设` 命令用法可通过 `狼人杀预设 --help` 获取,或参考 [游戏内容](#游戏内容) 部分的介绍
155
187
 
156
- - 对于 `OneBot V11` 适配器和 `Satori` 适配器的 `chronocat`, 启用配置项 `werewolf__enable_poke` 后, 可以使用戳一戳代替 _准备阶段_ 的 `加入游戏` 操作 和 游戏内的 `stop` 命令
188
+ - `狼人杀配置` 命令用法可通过 `狼人杀预设 --help` 获取
157
189
 
158
- - _其他交互参考游戏内提示_
190
+ - 对于 `OneBot V11` 适配器和 `Satori` 适配器的 `chronocat`, 启用配置项 `werewolf__enable_poke` 后, 可以使用戳一戳代替 _准备阶段_ 的 `加入游戏` 操作 和 游戏内的 `stop` 命令
159
191
 
192
+ - _其他交互参考游戏内提示_
160
193
 
161
194
  ### 游戏内容
162
195
 
@@ -183,9 +216,9 @@ _✨ 简单的狼人杀插件 ✨_
183
216
  <details>
184
217
  <summary>示例</summary>
185
218
 
186
- - 命令: `狼人杀预设 职业 6 1 3 2`
219
+ - 命令: `狼人杀预设 职业 6 1 3 2`
187
220
 
188
- - 上述命令指定当总人数为 6 时,狼人、神职、平民的数量分别为 1、3、2
221
+ - 上述命令指定当总人数为 6 时,狼人、神职、平民的数量分别为 1、3、2
189
222
 
190
223
  </details>
191
224
  <br/>
@@ -202,19 +235,19 @@ _✨ 简单的狼人杀插件 ✨_
202
235
 
203
236
  #### 命令 `狼人杀预设 狼人`
204
237
 
205
- - 命令: `狼人杀预设 狼人 狼 狼王 狼 狼`
238
+ - 命令: `狼人杀预设 狼人 狼 狼王 狼 狼`
206
239
 
207
- - 上述命令指定狼人的职业优先级为 `狼人`, `狼王`, `狼人`, `狼人`
240
+ - 上述命令指定狼人的职业优先级为 `狼人`, `狼王`, `狼人`, `狼人`
208
241
 
209
242
  #### 命令 `狼人杀预设 神职`
210
243
 
211
- - 命令: `狼人杀预设 神职 预言家 女巫 猎人 守卫 白痴`
244
+ - 命令: `狼人杀预设 神职 预言家 女巫 猎人 守卫 白痴`
212
245
 
213
- - 上述命令指定狼人的职业优先级为 `预言家`, `女巫`, `猎人`, `守卫`, `白痴`
246
+ - 上述命令指定神职的职业优先级为 `预言家`, `女巫`, `猎人`, `守卫`, `白痴`
214
247
 
215
248
  > [!note]
216
249
  >
217
- > 以上两条命令均支持交互式输入
250
+ > 以上两条命令均支持交互式输入 ~~waiter 真好用~~
218
251
  >
219
252
  > 例:向机器人发送命令 `狼人杀预设 狼人`,在接下来的一条消息中发送 `狼人 狼王 狼人 狼人`
220
253
  >
@@ -223,7 +256,7 @@ _✨ 简单的狼人杀插件 ✨_
223
256
  </details>
224
257
  <br/>
225
258
 
226
- 对于 `小丑` 职业,当预设中的平民数量大于或等于 2 时,将有 *一定概率* 将其中一个平民替换为小丑。
259
+ 对于 `小丑` 职业,当预设中的平民数量大于或等于 2 时,将有 _一定概率_ 将其中一个平民替换为小丑。
227
260
 
228
261
  小丑属于第三方阵营,胜利条件为在投票阶段被票出,在预言家查验及游戏进程判断时视作平民。
229
262
 
@@ -231,8 +264,13 @@ _✨ 简单的狼人杀插件 ✨_
231
264
 
232
265
  ### 已知问题
233
266
 
267
+ <details>
268
+ <summary>已知问题</summary>
269
+
234
270
  - 截止 chronocat v0.2.19, 调用 [`guild.member.get`](https://github.com/chrononeko/chronocat/blob/8558ad9ff4319395d86abbfda22136939bf66780/packages/engine-chronocat-api/src/api/guild/member/get.ts) / [`user.get`](https://github.com/chrononeko/chronocat/blob/8558ad9ff4319395d86abbfda22136939bf66780/packages/engine-chronocat-api/src/api/user/get.ts) 均无法获取用户名,这将导致在交互过程中的玩家名显示为用户 ID
235
271
 
272
+ </details>
273
+
236
274
  ## 📝 更新日志
237
275
 
238
276
  <details>
@@ -240,11 +278,21 @@ _✨ 简单的狼人杀插件 ✨_
240
278
 
241
279
  <!-- CHANGELOG -->
242
280
 
281
+ - 2025.04.20 v1.1.11
282
+
283
+ - 添加配置项 `werewolf__require_at`, 用于配置命令是否需要 at 机器人触发
284
+ - 添加配置项 `werewolf__matcher_priority`, 用于配置插件 matcher 注册优先级
285
+
286
+ - 2025.04.17 v1.1.10
287
+
288
+ - 添加狼人多选目标配置项显示
289
+ - 在游戏开始时打乱并固定轮流发言模式的发言顺序 (#20)
290
+
243
291
  - 2025.04.15 v1.1.9
244
292
 
245
293
  - 添加游戏行为配置 `werewolf_multi_select`
246
294
  - 重构玩家类
247
- - 添加轮流发言模式缺失的 at 消息段
295
+ - 添加轮流发言模式缺失的 at 消息段 (#19)
248
296
 
249
297
  - 2025.02.13 v1.1.8
250
298
 
@@ -254,7 +302,7 @@ _✨ 简单的狼人杀插件 ✨_
254
302
 
255
303
  - 2024.10.31 v1.1.7
256
304
 
257
- - *Bug fix*
305
+ - _Bug fix_
258
306
 
259
307
  - 2024.10.31 v1.1.6
260
308
 
@@ -0,0 +1,35 @@
1
+ nonebot_plugin_werewolf/__init__.py,sha256=9e9JlBvTP1rx6o5CSsFQo5w_cr8-0_xWg2YUsNEJ_WE,932
2
+ nonebot_plugin_werewolf/config.py,sha256=ncIqL9StQ_Q0osqt2iyGlxZxgdqo9QPDQDhFDZMnk-g,3739
3
+ nonebot_plugin_werewolf/constant.py,sha256=oBA6RWhJr7sDp-p3EbveMZfMP144TTGqYQGLUU7ionQ,2049
4
+ nonebot_plugin_werewolf/exception.py,sha256=SP9RdzsREB6PtpRfhZjxqybtvO0aw48hpN9QMU9jDZY,366
5
+ nonebot_plugin_werewolf/game.py,sha256=bq8w28jU7soBP7_UjsL3iCv4JfG-VOlbXfHheH3KLIQ,19378
6
+ nonebot_plugin_werewolf/models.py,sha256=PiQ-5_R-cUlHKWDa5G0bFnz7jv20200_kr449G9Jgjg,2300
7
+ nonebot_plugin_werewolf/player.py,sha256=1FPsvNkt9d5D2EH7vXCXmDabdcOOAGFcI4Ky9rUe99s,11223
8
+ nonebot_plugin_werewolf/player_set.py,sha256=S2To4-YW-Geh-Jrol6IsqIvJmf5a7lNGMl4rlngD3Gc,3375
9
+ nonebot_plugin_werewolf/utils.py,sha256=gV01cdGJXdbnxDcm6PWEbFYcgL1sF4rA-y5XzrYwzvU,7122
10
+ nonebot_plugin_werewolf/matchers/__init__.py,sha256=lQ9AZDEWgtbP-W8KWvjkEYc_UfTHSUwjaGdZ7PT3z0E,219
11
+ nonebot_plugin_werewolf/matchers/depends.py,sha256=FMlKxDyFjQUXmi6UekhmG1zDdO8xVOhPNoRKbBlg3Nw,1332
12
+ nonebot_plugin_werewolf/matchers/edit_behavior.py,sha256=8gTSnvJNqKGjmOts_5zYR4f5Qn-NxUlAvUsOCk6LYDw,7262
13
+ nonebot_plugin_werewolf/matchers/edit_preset.py,sha256=2PLo-7f2XdZxQ71hZBZ7r-wVj5fNlE13A2wnathhofw,8113
14
+ nonebot_plugin_werewolf/matchers/message_in_game.py,sha256=xpnUanxa-reVlaXnwBTwfoDWQc-MhsMq03tHFKjeEkQ,1052
15
+ nonebot_plugin_werewolf/matchers/start_game.py,sha256=yLYXxzK_NUz8FreAZMB894wFaMpTmR2lNxMrkwQRzIg,12060
16
+ nonebot_plugin_werewolf/matchers/superuser_ops.py,sha256=_Bt_UbEZzeaPMBzwICvWRWoGgV_YnKauBy8dw7uBiUA,889
17
+ nonebot_plugin_werewolf/matchers/poke/__init__.py,sha256=LhWYvAYZsmJbnYMFj7Q032pvq5_P6FYRCzvnwuBvsb0,272
18
+ nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py,sha256=i_9eJXR2FTHhSM_jveeza6A2jkVGl0lncqs6u_rJ4yk,3931
19
+ nonebot_plugin_werewolf/matchers/poke/ob11_poke.py,sha256=k-huQnnblojsQpDYVM_RnhWvmEWc--1usn_0sN-lzxo,2539
20
+ nonebot_plugin_werewolf/players/__init__.py,sha256=lDHCYkk6h_1Bl9DKIqF6vPAcLXNhCGlxBFQzPH4NvUQ,345
21
+ nonebot_plugin_werewolf/players/civilian.py,sha256=Y6A5yB74Ckn_U0vAOoRJhpwhm3MyG6m47TalQ2mjhtw,151
22
+ nonebot_plugin_werewolf/players/guard.py,sha256=2HE3MRG92Ujc4JUHEB86EwNB-l7PgdpNUFxCU8cDBKQ,1354
23
+ nonebot_plugin_werewolf/players/hunter.py,sha256=iYeM2srPaoncBrft2LRuyNVUeGyeBF-rs0BAHl7RP7s,228
24
+ nonebot_plugin_werewolf/players/idiot.py,sha256=OfbLuSLhXNJueB9IYheNT7OpenqaFQjKaAKBlOH3hE0,1659
25
+ nonebot_plugin_werewolf/players/jester.py,sha256=aErVfQS30hS0t2KiQSNFfTHmC2_hqtaHdQvQ4U1Ts_Y,1016
26
+ nonebot_plugin_werewolf/players/prophet.py,sha256=OlMYIdSlZppbHVpfpeO60nFwdh1YtxMVCWEuapFZSyA,1084
27
+ nonebot_plugin_werewolf/players/shooter.py,sha256=1bWkqcSFX6Crynh3IrlI-2RGrNiP6d4XJAc8_FAF2JU,1946
28
+ nonebot_plugin_werewolf/players/werewolf.py,sha256=7lAJT7FjEt42J04RNAXkfDDIN-1mQOej0NaIo0dEWMQ,5347
29
+ nonebot_plugin_werewolf/players/witch.py,sha256=flugzsDkpYiMW-BQGvvqwcXHX_UGcsryAnyYKmh07l4,3049
30
+ nonebot_plugin_werewolf/players/wolfking.py,sha256=CMZ5Tq74wupcRPjAzXHEF2Gts4z3thsD57q64uGp_-c,628
31
+ nonebot_plugin_werewolf-1.1.11.dist-info/licenses/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
32
+ nonebot_plugin_werewolf-1.1.11.dist-info/METADATA,sha256=mU_NX1jnmiEtiMkwJ_sRkmfDjwGKDrSr8sFS8OD_tBI,13897
33
+ nonebot_plugin_werewolf-1.1.11.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
34
+ nonebot_plugin_werewolf-1.1.11.dist-info/top_level.txt,sha256=wLTfg8sTKbH9lLT9LtU118C9cTspEBJareLsrYM52YA,24
35
+ nonebot_plugin_werewolf-1.1.11.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (78.1.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,35 +0,0 @@
1
- nonebot_plugin_werewolf/__init__.py,sha256=lDOYm3Z6UA_fFXiKT9cGweOiND3X-Y3RAiKB5iqpTVc,931
2
- nonebot_plugin_werewolf/config.py,sha256=Dlng9cRvTf8dEPFngOobeV3S-TnrVrjs9Eqje8dH1wQ,3160
3
- nonebot_plugin_werewolf/constant.py,sha256=NVKMx4CI64hgftJJySa6VnK2K8ZBmGtrAyMxel3HS2o,2053
4
- nonebot_plugin_werewolf/exception.py,sha256=SP9RdzsREB6PtpRfhZjxqybtvO0aw48hpN9QMU9jDZY,366
5
- nonebot_plugin_werewolf/game.py,sha256=UL68ftCEgV9h34Xgw1sZPAUbyjIhFhGAdc70w8huWuQ,19438
6
- nonebot_plugin_werewolf/models.py,sha256=PiQ-5_R-cUlHKWDa5G0bFnz7jv20200_kr449G9Jgjg,2300
7
- nonebot_plugin_werewolf/player.py,sha256=EzV_In8KmlZAx0GGV-Cj9qIJjIefIf7CXzlchCTJvFo,11259
8
- nonebot_plugin_werewolf/player_set.py,sha256=RF3aQXLZyUBPa0_G-Q48NUARictMRp6IV2WD-BKtNTQ,2913
9
- nonebot_plugin_werewolf/utils.py,sha256=bwbBLApPWis15_perT89Mmy33gAdaHR8fKJWVnDGh9E,6803
10
- nonebot_plugin_werewolf/matchers/__init__.py,sha256=lQ9AZDEWgtbP-W8KWvjkEYc_UfTHSUwjaGdZ7PT3z0E,219
11
- nonebot_plugin_werewolf/matchers/depends.py,sha256=TITA2brcyHSavFA3K_HgqkoQtkwxdM8miyEKafcfZz4,1343
12
- nonebot_plugin_werewolf/matchers/edit_behavior.py,sha256=DaxMS9wcSyYpdhnHHXb0GqRgRNm6LNr5W1vbk-B63n4,7014
13
- nonebot_plugin_werewolf/matchers/edit_preset.py,sha256=PXABbjhQM0DiKfEqjOMKtSrJs2fKoVh91iTJlVD3hKA,8089
14
- nonebot_plugin_werewolf/matchers/message_in_game.py,sha256=Lm9VqZcnAU023SJ6R8LH-3-tSp8KRtmOJ4x4dTZGb1o,969
15
- nonebot_plugin_werewolf/matchers/start_game.py,sha256=cFa9KzZ3zEri5Ras1ccFyZQWK8HPcs6KRNZr2ArsdsA,11956
16
- nonebot_plugin_werewolf/matchers/superuser_ops.py,sha256=oz-znCaraxCJS08Ox1xcbhC0X-Uy-WXeNYTH1LgT2zU,700
17
- nonebot_plugin_werewolf/matchers/poke/__init__.py,sha256=gYysvGjztN3iDQpX6v5nkPT195FXnk7fqP9kzByTES0,220
18
- nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py,sha256=kYJfhOGbZkYWmti0S7b82yYxcoEO9baMHORCXA19cpY,4013
19
- nonebot_plugin_werewolf/matchers/poke/ob11_poke.py,sha256=XYkEYoYqaViLp5pzRBZqyjBqanJp-sZL4595-fhfrys,2587
20
- nonebot_plugin_werewolf/players/__init__.py,sha256=lDHCYkk6h_1Bl9DKIqF6vPAcLXNhCGlxBFQzPH4NvUQ,345
21
- nonebot_plugin_werewolf/players/civilian.py,sha256=Y6A5yB74Ckn_U0vAOoRJhpwhm3MyG6m47TalQ2mjhtw,151
22
- nonebot_plugin_werewolf/players/guard.py,sha256=2HE3MRG92Ujc4JUHEB86EwNB-l7PgdpNUFxCU8cDBKQ,1354
23
- nonebot_plugin_werewolf/players/hunter.py,sha256=iYeM2srPaoncBrft2LRuyNVUeGyeBF-rs0BAHl7RP7s,228
24
- nonebot_plugin_werewolf/players/idiot.py,sha256=OfbLuSLhXNJueB9IYheNT7OpenqaFQjKaAKBlOH3hE0,1659
25
- nonebot_plugin_werewolf/players/jester.py,sha256=aErVfQS30hS0t2KiQSNFfTHmC2_hqtaHdQvQ4U1Ts_Y,1016
26
- nonebot_plugin_werewolf/players/prophet.py,sha256=OlMYIdSlZppbHVpfpeO60nFwdh1YtxMVCWEuapFZSyA,1084
27
- nonebot_plugin_werewolf/players/shooter.py,sha256=1bWkqcSFX6Crynh3IrlI-2RGrNiP6d4XJAc8_FAF2JU,1946
28
- nonebot_plugin_werewolf/players/werewolf.py,sha256=7lAJT7FjEt42J04RNAXkfDDIN-1mQOej0NaIo0dEWMQ,5347
29
- nonebot_plugin_werewolf/players/witch.py,sha256=flugzsDkpYiMW-BQGvvqwcXHX_UGcsryAnyYKmh07l4,3049
30
- nonebot_plugin_werewolf/players/wolfking.py,sha256=CMZ5Tq74wupcRPjAzXHEF2Gts4z3thsD57q64uGp_-c,628
31
- nonebot_plugin_werewolf-1.1.9.dist-info/licenses/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
32
- nonebot_plugin_werewolf-1.1.9.dist-info/METADATA,sha256=ZL27XQ01QhEddypOZDVFVr5cRfB9WO5MUE19o7GA-jQ,11912
33
- nonebot_plugin_werewolf-1.1.9.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
34
- nonebot_plugin_werewolf-1.1.9.dist-info/top_level.txt,sha256=wLTfg8sTKbH9lLT9LtU118C9cTspEBJareLsrYM52YA,24
35
- nonebot_plugin_werewolf-1.1.9.dist-info/RECORD,,