nonebot-plugin-werewolf 1.1.11__tar.gz → 1.1.12__tar.gz
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-1.1.11 → nonebot_plugin_werewolf-1.1.12}/PKG-INFO +55 -34
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/README.md +52 -31
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/__init__.py +1 -1
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/config.py +36 -35
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/constant.py +0 -17
- nonebot_plugin_werewolf-1.1.12/nonebot_plugin_werewolf/dead_channel.py +79 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/game.py +46 -115
- nonebot_plugin_werewolf-1.1.12/nonebot_plugin_werewolf/matchers/_prepare_game.py +223 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/depends.py +2 -2
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/edit_preset.py +13 -12
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py +3 -3
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/poke/ob11_poke.py +3 -3
- nonebot_plugin_werewolf-1.1.12/nonebot_plugin_werewolf/matchers/start_game.py +123 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/superuser_ops.py +4 -8
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/models.py +19 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/player.py +35 -31
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/guard.py +2 -2
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/prophet.py +2 -2
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/shooter.py +2 -2
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/werewolf.py +18 -19
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/witch.py +4 -4
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/utils.py +18 -56
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf.egg-info/PKG-INFO +55 -34
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf.egg-info/SOURCES.txt +5 -1
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf.egg-info/requires.txt +2 -2
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/pyproject.toml +37 -14
- nonebot_plugin_werewolf-1.1.12/tests/test_start_game.py +145 -0
- nonebot_plugin_werewolf-1.1.12/tests/test_utils.py +16 -0
- nonebot_plugin_werewolf-1.1.11/nonebot_plugin_werewolf/matchers/start_game.py +0 -336
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/LICENSE +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/exception.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/__init__.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/edit_behavior.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/message_in_game.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/matchers/poke/__init__.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/player_set.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/__init__.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/civilian.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/hunter.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/idiot.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/jester.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/players/wolfking.py +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf.egg-info/dependency_links.txt +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf.egg-info/top_level.txt +0 -0
- {nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: nonebot-plugin-werewolf
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.12
|
4
4
|
Summary: 适用于 Nonebot2 的狼人杀插件
|
5
5
|
Author-email: wyf7685 <wyf7685@163.com>
|
6
6
|
License: MIT
|
@@ -11,9 +11,9 @@ Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
12
12
|
License-File: LICENSE
|
13
13
|
Requires-Dist: nonebot2>=2.4.0
|
14
|
-
Requires-Dist: nonebot-plugin-alconna>=0.
|
14
|
+
Requires-Dist: nonebot-plugin-alconna>=0.58.0
|
15
15
|
Requires-Dist: nonebot-plugin-localstore>=0.7.1
|
16
|
-
Requires-Dist: nonebot-plugin-uninfo>=0.
|
16
|
+
Requires-Dist: nonebot-plugin-uninfo>=0.8.0
|
17
17
|
Requires-Dist: nonebot-plugin-waiter>=0.8.0
|
18
18
|
Requires-Dist: anyio>=4.6.0
|
19
19
|
Dynamic: license-file
|
@@ -50,6 +50,21 @@ _✨ 简单的狼人杀插件 ✨_
|
|
50
50
|
|
51
51
|
和朋友们来一场紧张刺激的狼人杀游戏
|
52
52
|
|
53
|
+
<!-- ref: https://github.com/KomoriDev/Starify -->
|
54
|
+
|
55
|
+
> [!IMPORTANT]
|
56
|
+
> **收藏项目**,你将从 GitHub 上无延迟地接收所有发布通知~⭐️
|
57
|
+
|
58
|
+
<img width="100%" src="https://starify.komoridevs.icu/api/starify?owner=wyf7685&repo=nonebot-plugin-werewolf" alt="starify" />
|
59
|
+
|
60
|
+
<details>
|
61
|
+
<summary><kbd>Star History</kbd></summary>
|
62
|
+
<picture>
|
63
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=wyf7685/nonebot-plugin-werewolf&theme=dark&type=Date" />
|
64
|
+
<img width="100%" src="https://star-history.com/#wyf7685/nonebot-plugin-werewolf&Date" />
|
65
|
+
</picture>
|
66
|
+
</details>
|
67
|
+
|
53
68
|
## 💿 安装
|
54
69
|
|
55
70
|
> [!note]
|
@@ -121,7 +136,7 @@ _✨ 简单的狼人杀插件 ✨_
|
|
121
136
|
|
122
137
|
`werewolf__enable_poke` 仅在 `OneBot V11` 适配器 / `Satori/chronocat` 下生效
|
123
138
|
|
124
|
-
`werewolf__enable_button` 仅在 `Telegram`
|
139
|
+
`werewolf__enable_button` 仅在 `Telegram` 适配器下通过测试,不保证在其他适配器的可用性,如有疑问欢迎提出。
|
125
140
|
|
126
141
|
<details>
|
127
142
|
<summary> werewolf__require_at 示例 </summary>
|
@@ -136,15 +151,16 @@ werewolf__require_at=false
|
|
136
151
|
# 狼人杀命令需要 at, 中止游戏命令不需要 at
|
137
152
|
werewolf__require_at='{"start": true, "terminate": false}'
|
138
153
|
```
|
154
|
+
|
139
155
|
</details>
|
140
|
-
<br/>
|
141
156
|
|
142
157
|
`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
158
|
|
147
|
-
|
159
|
+
- 一般情况下不需要修改此配置, 插件的默认优先级可以参考 [这里](./nonebot_plugin_werewolf/config.py) 的 `MatcherPriorityConfig`
|
160
|
+
- 如果遇到与其他插件的命令冲突, 可考虑修改此处的优先级配置
|
161
|
+
- 配置应填入 JSON 对象, 可用键: `start` `terminate` `preset` `behavior` `in_game` `stop`
|
162
|
+
|
163
|
+
## 🚀 使用
|
148
164
|
|
149
165
|
> [!note]
|
150
166
|
>
|
@@ -165,19 +181,19 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
165
181
|
|
166
182
|
</details>
|
167
183
|
|
168
|
-
### 指令表
|
184
|
+
### 📋 指令表
|
169
185
|
|
170
|
-
| 指令 | 权限 | 需要@ |
|
171
|
-
| :-----------------: | :-----------------: | :---: |
|
172
|
-
| `werewolf`/`狼人杀` | 群员 | 是 |
|
173
|
-
| `开始游戏` | 游戏发起者 | 否 | 群聊
|
174
|
-
| `结束游戏` | 游戏发起者/超级用户 | 否 | 群聊
|
175
|
-
| `当前玩家` | 群员 | 否 | 群聊
|
176
|
-
| `加入游戏` | 群员 | 否 | 群聊
|
177
|
-
| `退出游戏` | 群员 | 否 | 群聊
|
178
|
-
| `中止游戏` | 超级用户 | 是 |
|
179
|
-
| `狼人杀预设` | 超级用户 | 否 |
|
180
|
-
| `狼人杀配置` | 超级用户 | 否 |
|
186
|
+
| 指令 | 权限 | 需要@ | 范围 | 说明 |
|
187
|
+
| :-----------------: | :-----------------: | :---: | :---------------: | :--------------------------: |
|
188
|
+
| `werewolf`/`狼人杀` | 群员 | 是 | 群聊 _[游戏外]_ | 发起游戏 (进入准备阶段) |
|
189
|
+
| `开始游戏` | 游戏发起者 | 否 | 群聊 _[准备阶段]_ | 游戏发起者开始游戏 |
|
190
|
+
| `结束游戏` | 游戏发起者/超级用户 | 否 | 群聊 _[准备阶段]_ | 游戏发起者/超级用户 结束游戏 |
|
191
|
+
| `当前玩家` | 群员 | 否 | 群聊 _[准备阶段]_ | 列出参与游戏的玩家列表 |
|
192
|
+
| `加入游戏` | 群员 | 否 | 群聊 _[准备阶段]_ | 玩家加入游戏 |
|
193
|
+
| `退出游戏` | 群员 | 否 | 群聊 _[准备阶段]_ | 玩家退出游戏 |
|
194
|
+
| `中止游戏` | 超级用户 | 是 | 群聊 _[游戏内]_ | 超级用户强制中止游戏 |
|
195
|
+
| `狼人杀预设` | 超级用户 | 否 | 任意 _[游戏外]_ | 超级用户编辑游戏预设 |
|
196
|
+
| `狼人杀配置` | 超级用户 | 否 | 任意 _[游戏外]_ | 超级用户编辑游戏配置 |
|
181
197
|
|
182
198
|
- `超级用户` 为 nonebot2 配置项中的 `SUPERUSERS`, 配置说明参考 [官方文档](https://nonebot.dev/docs/appendices/config#superusers)
|
183
199
|
|
@@ -191,7 +207,7 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
191
207
|
|
192
208
|
- _其他交互参考游戏内提示_
|
193
209
|
|
194
|
-
### 游戏内容
|
210
|
+
### 🎭 游戏内容
|
195
211
|
|
196
212
|
> [!note]
|
197
213
|
>
|
@@ -202,14 +218,14 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
202
218
|
插件中保存了一份 [职业预设](./nonebot_plugin_werewolf/constant.py), 内容如下
|
203
219
|
|
204
220
|
| 总人数 | 狼人 | 神职 | 平民 |
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
221
|
+
| :----: | :--: | :--: | :--: |
|
222
|
+
| 6 | 1 | 2 | 3 |
|
223
|
+
| 7 | 2 | 2 | 3 |
|
224
|
+
| 8 | 2 | 3 | 3 |
|
225
|
+
| 9 | 2 | 4 | 3 |
|
226
|
+
| 10 | 3 | 4 | 3 |
|
227
|
+
| 11 | 3 | 5 | 3 |
|
228
|
+
| 12 | 4 | 5 | 3 |
|
213
229
|
|
214
230
|
职业预设可以通过命令 `狼人杀预设 职业 ...` 修改
|
215
231
|
|
@@ -254,7 +270,6 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
254
270
|
> 其效果等同于以上描述中的单条命令 `狼人杀预设 狼人 狼人 狼王 狼人 狼人`
|
255
271
|
|
256
272
|
</details>
|
257
|
-
<br/>
|
258
273
|
|
259
274
|
对于 `小丑` 职业,当预设中的平民数量大于或等于 2 时,将有 _一定概率_ 将其中一个平民替换为小丑。
|
260
275
|
|
@@ -262,12 +277,14 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
262
277
|
|
263
278
|
小丑生成概率可以通过命令 `狼人杀预设 小丑 <概率>` 设置,默认值为 0 (不生成小丑)。
|
264
279
|
|
265
|
-
### 已知问题
|
280
|
+
### 🔧 已知问题
|
266
281
|
|
267
282
|
<details>
|
268
283
|
<summary>已知问题</summary>
|
269
284
|
|
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
|
285
|
+
- 截止 chronocat [v0.2.19](https://github.com/chrononeko/chronocat/tree/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
|
286
|
+
|
287
|
+
- v1.1.6 添加的按钮操作在 `discord` 适配器中不可用, 已在 v1.1.12 禁用 (2e31d43)
|
271
288
|
|
272
289
|
</details>
|
273
290
|
|
@@ -278,6 +295,10 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
278
295
|
|
279
296
|
<!-- CHANGELOG -->
|
280
297
|
|
298
|
+
- 2025.06.01 v1.1.12
|
299
|
+
|
300
|
+
- 禁用 `discord` 适配器中的按钮操作 ~~以后会写适配的...吗?~~
|
301
|
+
|
281
302
|
- 2025.04.20 v1.1.11
|
282
303
|
|
283
304
|
- 添加配置项 `werewolf__require_at`, 用于配置命令是否需要 at 机器人触发
|
@@ -362,7 +383,7 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
362
383
|
|
363
384
|
</details>
|
364
385
|
|
365
|
-
## 鸣谢
|
386
|
+
## 🎉 鸣谢
|
366
387
|
|
367
388
|
- [`nonebot/nonebot2`](https://github.com/nonebot/nonebot2): 跨平台 Python 异步机器人框架
|
368
389
|
- [`nonebot/plugin-alconna`](https://github.com/nonebot/plugin-alconna): 跨平台的消息处理接口
|
@@ -30,6 +30,21 @@ _✨ 简单的狼人杀插件 ✨_
|
|
30
30
|
|
31
31
|
和朋友们来一场紧张刺激的狼人杀游戏
|
32
32
|
|
33
|
+
<!-- ref: https://github.com/KomoriDev/Starify -->
|
34
|
+
|
35
|
+
> [!IMPORTANT]
|
36
|
+
> **收藏项目**,你将从 GitHub 上无延迟地接收所有发布通知~⭐️
|
37
|
+
|
38
|
+
<img width="100%" src="https://starify.komoridevs.icu/api/starify?owner=wyf7685&repo=nonebot-plugin-werewolf" alt="starify" />
|
39
|
+
|
40
|
+
<details>
|
41
|
+
<summary><kbd>Star History</kbd></summary>
|
42
|
+
<picture>
|
43
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=wyf7685/nonebot-plugin-werewolf&theme=dark&type=Date" />
|
44
|
+
<img width="100%" src="https://star-history.com/#wyf7685/nonebot-plugin-werewolf&Date" />
|
45
|
+
</picture>
|
46
|
+
</details>
|
47
|
+
|
33
48
|
## 💿 安装
|
34
49
|
|
35
50
|
> [!note]
|
@@ -101,7 +116,7 @@ _✨ 简单的狼人杀插件 ✨_
|
|
101
116
|
|
102
117
|
`werewolf__enable_poke` 仅在 `OneBot V11` 适配器 / `Satori/chronocat` 下生效
|
103
118
|
|
104
|
-
`werewolf__enable_button` 仅在 `Telegram`
|
119
|
+
`werewolf__enable_button` 仅在 `Telegram` 适配器下通过测试,不保证在其他适配器的可用性,如有疑问欢迎提出。
|
105
120
|
|
106
121
|
<details>
|
107
122
|
<summary> werewolf__require_at 示例 </summary>
|
@@ -116,15 +131,16 @@ werewolf__require_at=false
|
|
116
131
|
# 狼人杀命令需要 at, 中止游戏命令不需要 at
|
117
132
|
werewolf__require_at='{"start": true, "terminate": false}'
|
118
133
|
```
|
134
|
+
|
119
135
|
</details>
|
120
|
-
<br/>
|
121
136
|
|
122
137
|
`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)
|
123
|
-
- 一般情况下不需要修改此配置, 插件的默认优先级可以参考 [这里](./nonebot_plugin_werewolf/config.py) 的 `MatcherPriorityConfig`
|
124
|
-
- 如果遇到与其他插件的命令冲突, 可考虑修改此处的优先级配置
|
125
|
-
- 配置应填入 JSON 对象, 可用键: `start` `terminate` `preset` `behavior` `in_game` `stop`
|
126
138
|
|
127
|
-
|
139
|
+
- 一般情况下不需要修改此配置, 插件的默认优先级可以参考 [这里](./nonebot_plugin_werewolf/config.py) 的 `MatcherPriorityConfig`
|
140
|
+
- 如果遇到与其他插件的命令冲突, 可考虑修改此处的优先级配置
|
141
|
+
- 配置应填入 JSON 对象, 可用键: `start` `terminate` `preset` `behavior` `in_game` `stop`
|
142
|
+
|
143
|
+
## 🚀 使用
|
128
144
|
|
129
145
|
> [!note]
|
130
146
|
>
|
@@ -145,19 +161,19 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
145
161
|
|
146
162
|
</details>
|
147
163
|
|
148
|
-
### 指令表
|
164
|
+
### 📋 指令表
|
149
165
|
|
150
|
-
| 指令 | 权限 | 需要@ |
|
151
|
-
| :-----------------: | :-----------------: | :---: |
|
152
|
-
| `werewolf`/`狼人杀` | 群员 | 是 |
|
153
|
-
| `开始游戏` | 游戏发起者 | 否 | 群聊
|
154
|
-
| `结束游戏` | 游戏发起者/超级用户 | 否 | 群聊
|
155
|
-
| `当前玩家` | 群员 | 否 | 群聊
|
156
|
-
| `加入游戏` | 群员 | 否 | 群聊
|
157
|
-
| `退出游戏` | 群员 | 否 | 群聊
|
158
|
-
| `中止游戏` | 超级用户 | 是 |
|
159
|
-
| `狼人杀预设` | 超级用户 | 否 |
|
160
|
-
| `狼人杀配置` | 超级用户 | 否 |
|
166
|
+
| 指令 | 权限 | 需要@ | 范围 | 说明 |
|
167
|
+
| :-----------------: | :-----------------: | :---: | :---------------: | :--------------------------: |
|
168
|
+
| `werewolf`/`狼人杀` | 群员 | 是 | 群聊 _[游戏外]_ | 发起游戏 (进入准备阶段) |
|
169
|
+
| `开始游戏` | 游戏发起者 | 否 | 群聊 _[准备阶段]_ | 游戏发起者开始游戏 |
|
170
|
+
| `结束游戏` | 游戏发起者/超级用户 | 否 | 群聊 _[准备阶段]_ | 游戏发起者/超级用户 结束游戏 |
|
171
|
+
| `当前玩家` | 群员 | 否 | 群聊 _[准备阶段]_ | 列出参与游戏的玩家列表 |
|
172
|
+
| `加入游戏` | 群员 | 否 | 群聊 _[准备阶段]_ | 玩家加入游戏 |
|
173
|
+
| `退出游戏` | 群员 | 否 | 群聊 _[准备阶段]_ | 玩家退出游戏 |
|
174
|
+
| `中止游戏` | 超级用户 | 是 | 群聊 _[游戏内]_ | 超级用户强制中止游戏 |
|
175
|
+
| `狼人杀预设` | 超级用户 | 否 | 任意 _[游戏外]_ | 超级用户编辑游戏预设 |
|
176
|
+
| `狼人杀配置` | 超级用户 | 否 | 任意 _[游戏外]_ | 超级用户编辑游戏配置 |
|
161
177
|
|
162
178
|
- `超级用户` 为 nonebot2 配置项中的 `SUPERUSERS`, 配置说明参考 [官方文档](https://nonebot.dev/docs/appendices/config#superusers)
|
163
179
|
|
@@ -171,7 +187,7 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
171
187
|
|
172
188
|
- _其他交互参考游戏内提示_
|
173
189
|
|
174
|
-
### 游戏内容
|
190
|
+
### 🎭 游戏内容
|
175
191
|
|
176
192
|
> [!note]
|
177
193
|
>
|
@@ -182,14 +198,14 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
182
198
|
插件中保存了一份 [职业预设](./nonebot_plugin_werewolf/constant.py), 内容如下
|
183
199
|
|
184
200
|
| 总人数 | 狼人 | 神职 | 平民 |
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
201
|
+
| :----: | :--: | :--: | :--: |
|
202
|
+
| 6 | 1 | 2 | 3 |
|
203
|
+
| 7 | 2 | 2 | 3 |
|
204
|
+
| 8 | 2 | 3 | 3 |
|
205
|
+
| 9 | 2 | 4 | 3 |
|
206
|
+
| 10 | 3 | 4 | 3 |
|
207
|
+
| 11 | 3 | 5 | 3 |
|
208
|
+
| 12 | 4 | 5 | 3 |
|
193
209
|
|
194
210
|
职业预设可以通过命令 `狼人杀预设 职业 ...` 修改
|
195
211
|
|
@@ -234,7 +250,6 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
234
250
|
> 其效果等同于以上描述中的单条命令 `狼人杀预设 狼人 狼人 狼王 狼人 狼人`
|
235
251
|
|
236
252
|
</details>
|
237
|
-
<br/>
|
238
253
|
|
239
254
|
对于 `小丑` 职业,当预设中的平民数量大于或等于 2 时,将有 _一定概率_ 将其中一个平民替换为小丑。
|
240
255
|
|
@@ -242,12 +257,14 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
242
257
|
|
243
258
|
小丑生成概率可以通过命令 `狼人杀预设 小丑 <概率>` 设置,默认值为 0 (不生成小丑)。
|
244
259
|
|
245
|
-
### 已知问题
|
260
|
+
### 🔧 已知问题
|
246
261
|
|
247
262
|
<details>
|
248
263
|
<summary>已知问题</summary>
|
249
264
|
|
250
|
-
- 截止 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
|
265
|
+
- 截止 chronocat [v0.2.19](https://github.com/chrononeko/chronocat/tree/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
|
266
|
+
|
267
|
+
- v1.1.6 添加的按钮操作在 `discord` 适配器中不可用, 已在 v1.1.12 禁用 (2e31d43)
|
251
268
|
|
252
269
|
</details>
|
253
270
|
|
@@ -258,6 +275,10 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
258
275
|
|
259
276
|
<!-- CHANGELOG -->
|
260
277
|
|
278
|
+
- 2025.06.01 v1.1.12
|
279
|
+
|
280
|
+
- 禁用 `discord` 适配器中的按钮操作 ~~以后会写适配的...吗?~~
|
281
|
+
|
261
282
|
- 2025.04.20 v1.1.11
|
262
283
|
|
263
284
|
- 添加配置项 `werewolf__require_at`, 用于配置命令是否需要 at 机器人触发
|
@@ -342,7 +363,7 @@ werewolf__require_at='{"start": true, "terminate": false}'
|
|
342
363
|
|
343
364
|
</details>
|
344
365
|
|
345
|
-
## 鸣谢
|
366
|
+
## 🎉 鸣谢
|
346
367
|
|
347
368
|
- [`nonebot/nonebot2`](https://github.com/nonebot/nonebot2): 跨平台 Python 异步机器人框架
|
348
369
|
- [`nonebot/plugin-alconna`](https://github.com/nonebot/plugin-alconna): 跨平台的消息处理接口
|
{nonebot_plugin_werewolf-1.1.11 → nonebot_plugin_werewolf-1.1.12}/nonebot_plugin_werewolf/config.py
RENAMED
@@ -12,37 +12,36 @@ from .constant import (
|
|
12
12
|
DEFAULT_PRIESTHOOD_PRIORITY,
|
13
13
|
DEFAULT_ROLE_PRESET,
|
14
14
|
DEFAULT_WEREWOLF_PRIORITY,
|
15
|
-
stop_command_prompt,
|
16
15
|
)
|
17
16
|
from .models import Role
|
18
17
|
|
19
18
|
|
20
19
|
class ConfigFile(BaseModel):
|
21
|
-
|
22
|
-
|
20
|
+
_file_: ClassVar[Path]
|
21
|
+
_cache_: ClassVar[Self | None] = None
|
23
22
|
|
24
23
|
def __init_subclass__(cls, **kwargs: Any) -> None: # noqa: ANN401
|
25
24
|
super().__init_subclass__(**kwargs)
|
26
|
-
if not cls.
|
25
|
+
if not cls._file_.exists():
|
27
26
|
cls().save()
|
28
27
|
|
29
28
|
@classmethod
|
30
29
|
def load(cls) -> Self:
|
31
|
-
return type_validate_json(cls, cls.
|
30
|
+
return type_validate_json(cls, cls._file_.read_text())
|
32
31
|
|
33
32
|
@classmethod
|
34
33
|
def get(cls, *, use_cache: bool = True) -> Self:
|
35
|
-
if cls.
|
36
|
-
cls.
|
37
|
-
return cls.
|
34
|
+
if cls._cache_ is None or not use_cache:
|
35
|
+
cls._cache_ = cls.load()
|
36
|
+
return cls._cache_
|
38
37
|
|
39
38
|
def save(self) -> None:
|
40
|
-
self.
|
41
|
-
type(self).
|
39
|
+
self._file_.write_text(json.dumps(model_dump(self)))
|
40
|
+
type(self)._cache_ = self
|
42
41
|
|
43
42
|
|
44
43
|
class PresetData(ConfigFile):
|
45
|
-
|
44
|
+
_file_: ClassVar[Path] = get_plugin_data_file("preset.json")
|
46
45
|
|
47
46
|
role_preset: dict[int, tuple[int, int, int]] = DEFAULT_ROLE_PRESET.copy()
|
48
47
|
werewolf_priority: list[Role] = DEFAULT_WEREWOLF_PRIORITY.copy()
|
@@ -50,36 +49,33 @@ class PresetData(ConfigFile):
|
|
50
49
|
jester_probability: float = Field(default=0.0, ge=0.0, le=1.0)
|
51
50
|
|
52
51
|
|
52
|
+
class _Timeout(BaseModel):
|
53
|
+
prepare: int = Field(default=5 * 60, ge=5 * 60)
|
54
|
+
speak: int = Field(default=60, ge=60)
|
55
|
+
group_speak: int = Field(default=120, ge=120)
|
56
|
+
interact: int = Field(default=60, ge=60)
|
57
|
+
vote: int = Field(default=60, ge=60)
|
58
|
+
werewolf: int = Field(default=120, ge=120)
|
59
|
+
|
60
|
+
@property
|
61
|
+
def speak_timeout_prompt(self) -> str:
|
62
|
+
return f"限时{self.speak / 60:.1f}分钟, 发送 “{stop_command_prompt}” 结束发言"
|
63
|
+
|
64
|
+
@property
|
65
|
+
def group_speak_timeout_prompt(self) -> str:
|
66
|
+
return (
|
67
|
+
f"限时{self.group_speak / 60:.1f}分钟, "
|
68
|
+
f"全员发送 “{stop_command_prompt}” 结束发言"
|
69
|
+
)
|
70
|
+
|
71
|
+
|
53
72
|
class GameBehavior(ConfigFile):
|
54
|
-
|
73
|
+
_file_: ClassVar[Path] = get_plugin_data_file("behavior.json")
|
55
74
|
|
56
75
|
show_roles_list_on_start: bool = False
|
57
76
|
speak_in_turn: bool = False
|
58
77
|
dead_channel_rate_limit: int = 8 # per minute
|
59
78
|
werewolf_multi_select: bool = False
|
60
|
-
|
61
|
-
class _Timeout(BaseModel):
|
62
|
-
prepare: int = Field(default=5 * 60, ge=5 * 60)
|
63
|
-
speak: int = Field(default=60, ge=60)
|
64
|
-
group_speak: int = Field(default=120, ge=120)
|
65
|
-
interact: int = Field(default=60, ge=60)
|
66
|
-
vote: int = Field(default=60, ge=60)
|
67
|
-
werewolf: int = Field(default=120, ge=120)
|
68
|
-
|
69
|
-
@property
|
70
|
-
def speak_timeout_prompt(self) -> str:
|
71
|
-
return (
|
72
|
-
f"限时{self.speak / 60:.1f}分钟, "
|
73
|
-
f"发送 “{stop_command_prompt()}” 结束发言"
|
74
|
-
)
|
75
|
-
|
76
|
-
@property
|
77
|
-
def group_speak_timeout_prompt(self) -> str:
|
78
|
-
return (
|
79
|
-
f"限时{self.group_speak / 60:.1f}分钟, "
|
80
|
-
f"全员发送 “{stop_command_prompt()}” 结束发言"
|
81
|
-
)
|
82
|
-
|
83
79
|
timeout: Final[_Timeout] = _Timeout()
|
84
80
|
|
85
81
|
|
@@ -123,3 +119,8 @@ class Config(BaseModel):
|
|
123
119
|
|
124
120
|
config = nonebot.get_plugin_config(Config).werewolf
|
125
121
|
nonebot.logger.debug(f"加载插件配置: {config}")
|
122
|
+
|
123
|
+
stop_command_prompt = (
|
124
|
+
next(iter(sorted(nonebot.get_driver().config.command_start, key=len)), "")
|
125
|
+
+ config.get_stop_command()[0]
|
126
|
+
)
|
@@ -1,25 +1,8 @@
|
|
1
|
-
import functools
|
2
|
-
from typing import TYPE_CHECKING
|
3
|
-
|
4
1
|
from .models import GameStatus, KillReason, Role, RoleGroup
|
5
2
|
|
6
3
|
STOP_COMMAND = "{{stop}}"
|
7
4
|
|
8
5
|
|
9
|
-
def stop_command_prompt() -> str:
|
10
|
-
import nonebot
|
11
|
-
|
12
|
-
from .config import config # circular import
|
13
|
-
|
14
|
-
cmd_starts = sorted(nonebot.get_driver().config.command_start, key=len)
|
15
|
-
return next(iter(cmd_starts), "") + config.get_stop_command()[0]
|
16
|
-
|
17
|
-
|
18
|
-
if not TYPE_CHECKING:
|
19
|
-
stop_command_prompt = functools.cache(stop_command_prompt)
|
20
|
-
del TYPE_CHECKING
|
21
|
-
|
22
|
-
|
23
6
|
ROLE_NAME_CONV: dict[Role | RoleGroup, str] = {
|
24
7
|
Role.WEREWOLF: "狼人",
|
25
8
|
Role.WOLFKING: "狼王",
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import contextlib
|
2
|
+
from typing import NoReturn
|
3
|
+
|
4
|
+
import anyio
|
5
|
+
import anyio.lowlevel
|
6
|
+
from nonebot_plugin_alconna import UniMessage
|
7
|
+
|
8
|
+
from .config import GameBehavior
|
9
|
+
from .player import Player
|
10
|
+
from .player_set import PlayerSet
|
11
|
+
|
12
|
+
|
13
|
+
class DeadChannel:
|
14
|
+
players: PlayerSet
|
15
|
+
finished: anyio.Event
|
16
|
+
counter: dict[str, int]
|
17
|
+
|
18
|
+
def __init__(self, players: PlayerSet, finished: anyio.Event) -> None:
|
19
|
+
self.players = players
|
20
|
+
self.finished = finished
|
21
|
+
self.counter = {p.user_id: 0 for p in players}
|
22
|
+
|
23
|
+
async def _decrease(self, user_id: str) -> None:
|
24
|
+
await anyio.sleep(60)
|
25
|
+
self.counter[user_id] -= 1
|
26
|
+
|
27
|
+
async def _wait_finished(self) -> None:
|
28
|
+
await self.finished.wait()
|
29
|
+
self._task_group.cancel_scope.cancel()
|
30
|
+
|
31
|
+
async def _broadcast(self) -> NoReturn:
|
32
|
+
stream = self.stream[1]
|
33
|
+
while True:
|
34
|
+
player, msg = await stream.receive()
|
35
|
+
msg = UniMessage.text(f"玩家 {player.name}:\n") + msg
|
36
|
+
target = self.players.killed().exclude(player)
|
37
|
+
try:
|
38
|
+
await target.broadcast(msg)
|
39
|
+
except Exception as err:
|
40
|
+
with contextlib.suppress(Exception):
|
41
|
+
await player.send(f"消息转发失败: {err!r}")
|
42
|
+
|
43
|
+
async def _receive(self, player: Player) -> NoReturn:
|
44
|
+
await player.killed.wait()
|
45
|
+
await anyio.lowlevel.checkpoint()
|
46
|
+
user_id = player.user_id
|
47
|
+
stream = self.stream[0]
|
48
|
+
|
49
|
+
await player.send(
|
50
|
+
"ℹ️你已加入死者频道,请勿在群组内继续发言\n"
|
51
|
+
"私聊发送消息将转发至其他已死亡玩家",
|
52
|
+
)
|
53
|
+
await (
|
54
|
+
self.players.killed()
|
55
|
+
.exclude(player)
|
56
|
+
.broadcast(f"ℹ️玩家 {player.name} 加入了死者频道")
|
57
|
+
)
|
58
|
+
|
59
|
+
while True:
|
60
|
+
msg = await player.receive()
|
61
|
+
self.counter[user_id] += 1
|
62
|
+
self._task_group.start_soon(self._decrease, user_id)
|
63
|
+
|
64
|
+
# 发言频率限制
|
65
|
+
if self.counter[user_id] > GameBehavior.get().dead_channel_rate_limit:
|
66
|
+
await player.send("❌发言频率超过限制, 该消息被屏蔽")
|
67
|
+
continue
|
68
|
+
|
69
|
+
# 推送消息
|
70
|
+
await stream.send((player, msg))
|
71
|
+
|
72
|
+
async def run(self) -> None:
|
73
|
+
self.stream = anyio.create_memory_object_stream[tuple[Player, UniMessage]](16)
|
74
|
+
send, recv = self.stream
|
75
|
+
async with send, recv, anyio.create_task_group() as self._task_group:
|
76
|
+
self._task_group.start_soon(self._wait_finished)
|
77
|
+
self._task_group.start_soon(self._broadcast)
|
78
|
+
for p in self.players:
|
79
|
+
self._task_group.start_soon(self._receive, p)
|