nonebot-plugin-werewolf 1.1.6__py3-none-any.whl → 1.1.8__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.
Files changed (35) hide show
  1. nonebot_plugin_werewolf/__init__.py +1 -1
  2. nonebot_plugin_werewolf/config.py +76 -18
  3. nonebot_plugin_werewolf/constant.py +54 -46
  4. nonebot_plugin_werewolf/exception.py +2 -4
  5. nonebot_plugin_werewolf/game.py +193 -166
  6. nonebot_plugin_werewolf/matchers/__init__.py +1 -0
  7. nonebot_plugin_werewolf/matchers/depends.py +4 -4
  8. nonebot_plugin_werewolf/matchers/edit_behavior.py +205 -0
  9. nonebot_plugin_werewolf/matchers/edit_preset.py +11 -11
  10. nonebot_plugin_werewolf/matchers/message_in_game.py +3 -1
  11. nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py +8 -5
  12. nonebot_plugin_werewolf/matchers/poke/ob11_poke.py +3 -3
  13. nonebot_plugin_werewolf/matchers/start_game.py +213 -175
  14. nonebot_plugin_werewolf/matchers/superuser_ops.py +3 -3
  15. nonebot_plugin_werewolf/models.py +31 -19
  16. nonebot_plugin_werewolf/player_set.py +10 -8
  17. nonebot_plugin_werewolf/players/__init__.py +1 -1
  18. nonebot_plugin_werewolf/players/can_shoot.py +15 -15
  19. nonebot_plugin_werewolf/players/civilian.py +1 -1
  20. nonebot_plugin_werewolf/players/guard.py +16 -14
  21. nonebot_plugin_werewolf/players/hunter.py +1 -1
  22. nonebot_plugin_werewolf/players/idiot.py +3 -3
  23. nonebot_plugin_werewolf/players/{joker.py → jester.py} +4 -5
  24. nonebot_plugin_werewolf/players/player.py +93 -29
  25. nonebot_plugin_werewolf/players/prophet.py +11 -10
  26. nonebot_plugin_werewolf/players/werewolf.py +63 -31
  27. nonebot_plugin_werewolf/players/witch.py +29 -12
  28. nonebot_plugin_werewolf/players/wolfking.py +1 -1
  29. nonebot_plugin_werewolf/utils.py +106 -7
  30. {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/METADATA +27 -20
  31. nonebot_plugin_werewolf-1.1.8.dist-info/RECORD +35 -0
  32. {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/WHEEL +1 -1
  33. nonebot_plugin_werewolf-1.1.6.dist-info/RECORD +0 -34
  34. {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/LICENSE +0 -0
  35. {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,205 @@
1
+ # ruff: noqa: FBT001
2
+
3
+ from typing import Annotated, NoReturn
4
+
5
+ from nonebot.internal.matcher import current_matcher
6
+ from nonebot.params import Depends
7
+ from nonebot.permission import SUPERUSER
8
+ from nonebot.typing import T_State
9
+ from nonebot_plugin_alconna import (
10
+ Alconna,
11
+ Args,
12
+ CommandMeta,
13
+ Subcommand,
14
+ UniMessage,
15
+ on_alconna,
16
+ )
17
+
18
+ from ..config import GameBehavior
19
+
20
+ GAME_BEHAVIOR_CACHE_KEY = "GAME_BEHAVIOR_CACHE_KEY"
21
+
22
+
23
+ def _behavior(state: T_State) -> GameBehavior:
24
+ if GAME_BEHAVIOR_CACHE_KEY not in state:
25
+ state[GAME_BEHAVIOR_CACHE_KEY] = GameBehavior.get()
26
+ return state[GAME_BEHAVIOR_CACHE_KEY]
27
+
28
+
29
+ Behavior = Annotated[GameBehavior, Depends(_behavior)]
30
+
31
+
32
+ async def finish(text: str) -> NoReturn:
33
+ behavior: GameBehavior = current_matcher.get().state[GAME_BEHAVIOR_CACHE_KEY]
34
+ behavior.save()
35
+ await UniMessage.text(text).finish(reply_to=True)
36
+
37
+
38
+ alc = Alconna(
39
+ "狼人杀配置",
40
+ Subcommand(
41
+ "show_roles",
42
+ Args["enabled#是否启用", bool],
43
+ alias={"显示职业"},
44
+ help_text="设置游戏开始时是否显示职业列表",
45
+ ),
46
+ Subcommand(
47
+ "speak_order",
48
+ Args["enabled#是否启用", bool],
49
+ alias={"发言顺序"},
50
+ help_text="设置是否按顺序发言",
51
+ ),
52
+ Subcommand(
53
+ "dead_chat",
54
+ Args["limit#每分钟限制次数", int],
55
+ alias={"死亡聊天"},
56
+ help_text="设置死亡玩家发言频率限制",
57
+ ),
58
+ Subcommand(
59
+ "timeout",
60
+ Subcommand(
61
+ "prepare",
62
+ Args["time#时间", int],
63
+ alias={"准备阶段"},
64
+ help_text="准备阶段超时时间(秒)",
65
+ ),
66
+ Subcommand(
67
+ "speak",
68
+ Args["time#时间", int],
69
+ alias={"个人发言"},
70
+ help_text="个人发言超时时间(秒)",
71
+ ),
72
+ Subcommand(
73
+ "group_speak",
74
+ Args["time#时间", int],
75
+ alias={"集体发言"},
76
+ help_text="集体发言超时时间(秒)",
77
+ ),
78
+ Subcommand(
79
+ "interact",
80
+ Args["time#时间", int],
81
+ alias={"交互阶段"},
82
+ help_text="交互阶段超时时间(秒)",
83
+ ),
84
+ Subcommand(
85
+ "vote",
86
+ Args["time#时间", int],
87
+ alias={"投票阶段"},
88
+ help_text="投票阶段超时时间(秒)",
89
+ ),
90
+ Subcommand(
91
+ "werewolf",
92
+ Args["time#时间", int],
93
+ alias={"狼人交互"},
94
+ help_text="狼人交互超时时间(秒)",
95
+ ),
96
+ alias={"超时"},
97
+ help_text="设置各阶段超时时间",
98
+ ),
99
+ meta=CommandMeta(
100
+ description="修改狼人杀游戏配置",
101
+ usage="狼人杀配置 --help",
102
+ example=(
103
+ "狼人杀配置\n"
104
+ "狼人杀配置 显示职业 true\n"
105
+ "狼人杀配置 发言顺序 false\n"
106
+ "狼人杀配置 死亡聊天 30\n"
107
+ "狼人杀配置 超时 准备 300"
108
+ ),
109
+ ),
110
+ )
111
+
112
+ edit_behavior = on_alconna(
113
+ alc,
114
+ permission=SUPERUSER,
115
+ use_cmd_start=True,
116
+ )
117
+
118
+
119
+ @edit_behavior.assign("show_roles")
120
+ async def set_show_roles(behavior: Behavior, enabled: bool) -> None:
121
+ behavior.show_roles_list_on_start = enabled
122
+ await finish(f"已{'启用' if enabled else '禁用'}游戏开始时显示职业列表")
123
+
124
+
125
+ @edit_behavior.assign("speak_order")
126
+ async def set_speak_order(behavior: Behavior, enabled: bool) -> None:
127
+ behavior.speak_in_turn = enabled
128
+ await finish(f"已{'启用' if enabled else '禁用'}按顺序发言")
129
+
130
+
131
+ @edit_behavior.assign("dead_chat")
132
+ async def set_dead_chat(behavior: Behavior, limit: int) -> None:
133
+ if limit < 0:
134
+ await finish("限制次数必须大于零")
135
+ behavior.dead_channel_rate_limit = limit
136
+ await finish(f"已设置死亡玩家发言限制为 {limit} 次/分钟")
137
+
138
+
139
+ @edit_behavior.assign("timeout.prepare")
140
+ async def set_prepare_timeout(behavior: Behavior, time: int) -> None:
141
+ if time < 300:
142
+ await finish("准备时间必须大于 300 秒")
143
+ behavior.timeout.prepare = time
144
+ await finish(f"已设置准备阶段超时时间为 {time} 秒")
145
+
146
+
147
+ @edit_behavior.assign("timeout.speak")
148
+ async def set_speak_timeout(behavior: Behavior, time: int) -> None:
149
+ if time < 60:
150
+ await finish("发言时间必须大于 60 秒")
151
+ behavior.timeout.speak = time
152
+ await finish(f"已设置发言阶段超时时间为 {time} 秒")
153
+
154
+
155
+ @edit_behavior.assign("timeout.group_speak")
156
+ async def set_group_speak_timeout(behavior: Behavior, time: int) -> None:
157
+ if time < 120:
158
+ await finish("集体发言时间必须大于 120 秒")
159
+ behavior.timeout.group_speak = time
160
+ await finish(f"已设置集体发言超时时间为 {time} 秒")
161
+
162
+
163
+ @edit_behavior.assign("timeout.interact")
164
+ async def set_interact_timeout(behavior: Behavior, time: int) -> None:
165
+ if time < 60:
166
+ await finish("交互时间必须大于 60 秒")
167
+ behavior.timeout.interact = time
168
+ await finish(f"已设置交互阶段超时时间为 {time} 秒")
169
+
170
+
171
+ @edit_behavior.assign("timeout.vote")
172
+ async def set_vote_timeout(behavior: Behavior, time: int) -> None:
173
+ if time < 60:
174
+ await finish("投票时间必须大于 60 秒")
175
+ behavior.timeout.vote = time
176
+ await finish(f"已设置投票阶段超时时间为 {time} 秒")
177
+
178
+
179
+ @edit_behavior.assign("timeout.werewolf")
180
+ async def set_werewolf_timeout(behavior: Behavior, time: int) -> None:
181
+ if time < 120:
182
+ await finish("狼人交互时间必须大于 120 秒")
183
+ behavior.timeout.werewolf = time
184
+ await finish(f"已设置狼人交互阶段超时时间为 {time} 秒")
185
+
186
+
187
+ @edit_behavior.handle()
188
+ async def handle_default(behavior: Behavior) -> None:
189
+ timeout = behavior.timeout
190
+ lines = [
191
+ "当前游戏配置:",
192
+ "",
193
+ f"游戏开始发送职业列表: {'是' if behavior.show_roles_list_on_start else '否'}",
194
+ f"白天讨论按顺序发言: {'是' if behavior.speak_in_turn else '否'}",
195
+ f"死亡玩家发言转发限制: {behavior.dead_channel_rate_limit} 次/分钟",
196
+ "",
197
+ "超时时间设置:",
198
+ f"准备阶段: {timeout.prepare} 秒",
199
+ f"个人发言: {timeout.speak} 秒",
200
+ f"集体发言: {timeout.group_speak} 秒",
201
+ f"交互阶段: {timeout.interact} 秒",
202
+ f"投票阶段: {timeout.vote} 秒",
203
+ f"狼人交互: {timeout.werewolf} 秒",
204
+ ]
205
+ await finish("\n".join(lines))
@@ -15,7 +15,7 @@ from nonebot_plugin_alconna import (
15
15
  )
16
16
 
17
17
  from ..config import PresetData
18
- from ..constant import role_name_conv
18
+ from ..constant import ROLE_NAME_CONV
19
19
  from ..models import Role
20
20
 
21
21
  alc = Alconna(
@@ -82,7 +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__
85
+ role_name = ROLE_NAME_CONV.__getitem__
86
86
  return ", ".join(map(role_name, roles))
87
87
 
88
88
 
@@ -152,9 +152,9 @@ async def assign_werewolf(state: T_State) -> None:
152
152
  for role in roles:
153
153
  match role:
154
154
  case "狼人" | "狼":
155
- result.append(Role.Werewolf)
155
+ result.append(Role.WEREWOLF)
156
156
  case "狼王":
157
- result.append(Role.WolfKing)
157
+ result.append(Role.WOLFKING)
158
158
  case x:
159
159
  await finish(f"未知职业: {x}")
160
160
 
@@ -195,15 +195,15 @@ async def assign_priesthood(state: T_State) -> None:
195
195
  for role in roles:
196
196
  match role:
197
197
  case "预言家" | "预言" | "预":
198
- result.append(Role.Prophet)
198
+ result.append(Role.PROPHET)
199
199
  case "女巫" | "巫":
200
- result.append(Role.Witch)
200
+ result.append(Role.WITCH)
201
201
  case "猎人" | "猎":
202
- result.append(Role.Hunter)
202
+ result.append(Role.HUNTER)
203
203
  case "守卫":
204
- result.append(Role.Guard)
204
+ result.append(Role.GUARD)
205
205
  case "白痴":
206
- result.append(Role.Idiot)
206
+ result.append(Role.IDIOT)
207
207
  case x:
208
208
  await finish(f"未知职业: {x}")
209
209
 
@@ -236,7 +236,7 @@ async def assign_joker(probability: Match[float]) -> None:
236
236
  await finish("输入错误,概率应在 0 到 100 之间")
237
237
 
238
238
  data = PresetData.load()
239
- data.joker_probability = probability.result / 100
239
+ data.jester_probability = probability.result / 100
240
240
  data.save()
241
241
  await finish(f"设置成功: 小丑概率 {probability.result:.1f}%")
242
242
 
@@ -258,6 +258,6 @@ async def handle_default() -> None:
258
258
 
259
259
  lines.append("狼人优先级: " + display_roles(data.werewolf_priority))
260
260
  lines.append("神职优先级: " + display_roles(data.priesthood_proirity))
261
- lines.append(f"小丑概率: {data.joker_probability:.0%}")
261
+ lines.append(f"小丑概率: {data.jester_probability:.0%}")
262
262
 
263
263
  await finish("\n".join(lines))
@@ -2,6 +2,7 @@ from nonebot import on_message
2
2
  from nonebot.adapters import Event
3
3
  from nonebot_plugin_alconna import Alconna, MsgTarget, UniMessage, UniMsg, on_alconna
4
4
 
5
+ from ..config import config
5
6
  from ..constant import STOP_COMMAND
6
7
  from ..utils import InputStore
7
8
  from .depends import rule_in_game
@@ -18,10 +19,11 @@ async def handle_input(event: Event, target: MsgTarget, msg: UniMsg) -> None:
18
19
 
19
20
 
20
21
  stopcmd = on_alconna(
21
- Alconna("stop"),
22
+ Alconna(config.get_stop_command()[0]),
22
23
  rule=rule_in_game,
23
24
  block=True,
24
25
  use_cmd_start=True,
26
+ aliases=set(aliases) if (aliases := config.get_stop_command()[1:]) else None,
25
27
  )
26
28
 
27
29
 
@@ -6,7 +6,7 @@ from nonebot_plugin_alconna import MsgTarget, UniMessage
6
6
 
7
7
  from ...config import config
8
8
  from ...constant import STOP_COMMAND
9
- from ...game import Game
9
+ from ...game import get_starting_games
10
10
  from ...utils import InputStore
11
11
  from ..depends import user_in_game
12
12
 
@@ -33,7 +33,7 @@ with contextlib.suppress(ImportError):
33
33
  gen = (
34
34
  seg.data["operatorId"]
35
35
  for seg in poke
36
- if seg.data["userId"] == event.self_id
36
+ if seg.data["userId"] == event.login.sn
37
37
  )
38
38
  return next(gen, None)
39
39
 
@@ -76,7 +76,7 @@ with contextlib.suppress(ImportError):
76
76
  user_id=user_id,
77
77
  group_id=(event.guild and event.guild.id) or event.channel.id,
78
78
  )
79
- and any(target.verify(group) for group in Game.starting_games)
79
+ and any(target.verify(group) for group in get_starting_games())
80
80
  )
81
81
 
82
82
  @on_message(rule=_rule_poke_join).handle()
@@ -86,7 +86,7 @@ with contextlib.suppress(ImportError):
86
86
  target: MsgTarget,
87
87
  ) -> None:
88
88
  user_id = extract_poke_tome(event) or event.get_user_id()
89
- players = next(p for g, p in Game.starting_games.items() if target.verify(g))
89
+ players = next(p for g, p in get_starting_games().items() if target.verify(g))
90
90
 
91
91
  if user_id not in players:
92
92
  # XXX:
@@ -114,4 +114,7 @@ with contextlib.suppress(ImportError):
114
114
  return False
115
115
 
116
116
  event = current_event.get()
117
- return isinstance(event, MessageCreatedEvent) and event.platform == "chronocat"
117
+ return (
118
+ isinstance(event, MessageCreatedEvent)
119
+ and event.login.platform == "chronocat"
120
+ )
@@ -6,7 +6,7 @@ from nonebot_plugin_alconna import MsgTarget, UniMessage
6
6
 
7
7
  from ...config import config
8
8
  from ...constant import STOP_COMMAND
9
- from ...game import Game
9
+ from ...game import get_starting_games
10
10
  from ...utils import InputStore
11
11
  from ..depends import user_in_game
12
12
 
@@ -50,7 +50,7 @@ with contextlib.suppress(ImportError):
50
50
  return (
51
51
  (event.target_id == event.self_id)
52
52
  and not user_in_game(bot.self_id, user_id, group_id)
53
- and any(target.verify(group) for group in Game.starting_games)
53
+ and any(target.verify(group) for group in get_starting_games())
54
54
  )
55
55
 
56
56
  @on_notice(rule=_rule_poke_join).handle()
@@ -60,7 +60,7 @@ with contextlib.suppress(ImportError):
60
60
  target: MsgTarget,
61
61
  ) -> None:
62
62
  user_id = event.get_user_id()
63
- players = next(p for g, p in Game.starting_games.items() if target.verify(g))
63
+ players = next(p for g, p in get_starting_games().items() if target.verify(g))
64
64
 
65
65
  if event.group_id is None or user_id in players:
66
66
  return