nonebot-plugin-werewolf 1.1.3__py3-none-any.whl → 1.1.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.
- nonebot_plugin_werewolf/__init__.py +3 -1
- nonebot_plugin_werewolf/config.py +18 -55
- nonebot_plugin_werewolf/constant.py +20 -58
- nonebot_plugin_werewolf/exception.py +1 -1
- nonebot_plugin_werewolf/game.py +286 -245
- nonebot_plugin_werewolf/matchers/__init__.py +2 -0
- nonebot_plugin_werewolf/matchers/depends.py +50 -0
- nonebot_plugin_werewolf/matchers/edit_preset.py +263 -0
- nonebot_plugin_werewolf/matchers/message_in_game.py +18 -3
- nonebot_plugin_werewolf/matchers/poke/__init__.py +8 -0
- nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py +117 -0
- nonebot_plugin_werewolf/matchers/{ob11_ext.py → poke/ob11_poke.py} +21 -19
- nonebot_plugin_werewolf/matchers/start_game.py +266 -28
- nonebot_plugin_werewolf/matchers/superuser_ops.py +24 -0
- nonebot_plugin_werewolf/models.py +73 -0
- nonebot_plugin_werewolf/player_set.py +33 -34
- nonebot_plugin_werewolf/players/can_shoot.py +15 -20
- nonebot_plugin_werewolf/players/civilian.py +3 -3
- nonebot_plugin_werewolf/players/guard.py +16 -22
- nonebot_plugin_werewolf/players/hunter.py +3 -3
- nonebot_plugin_werewolf/players/idiot.py +4 -4
- nonebot_plugin_werewolf/players/joker.py +8 -4
- nonebot_plugin_werewolf/players/player.py +133 -70
- nonebot_plugin_werewolf/players/prophet.py +8 -15
- nonebot_plugin_werewolf/players/werewolf.py +54 -30
- nonebot_plugin_werewolf/players/witch.py +33 -38
- nonebot_plugin_werewolf/players/wolfking.py +3 -3
- nonebot_plugin_werewolf/utils.py +109 -179
- {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.6.dist-info}/METADATA +78 -66
- nonebot_plugin_werewolf-1.1.6.dist-info/RECORD +34 -0
- {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.6.dist-info}/WHEEL +1 -1
- nonebot_plugin_werewolf/_timeout.py +0 -110
- nonebot_plugin_werewolf-1.1.3.dist-info/RECORD +0 -29
- {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.6.dist-info}/LICENSE +0 -0
- {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.6.dist-info}/top_level.txt +0 -0
nonebot_plugin_werewolf/utils.py
CHANGED
@@ -1,18 +1,20 @@
|
|
1
|
-
import
|
1
|
+
import functools
|
2
2
|
import itertools
|
3
|
-
import re
|
4
3
|
from collections import defaultdict
|
5
|
-
from typing import Any, ClassVar
|
4
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeVar, cast
|
6
5
|
|
7
|
-
import
|
8
|
-
import
|
9
|
-
from
|
10
|
-
from
|
11
|
-
from nonebot.utils import escape_tag
|
12
|
-
from nonebot_plugin_alconna import MsgTarget, Target, UniMessage, UniMsg
|
13
|
-
from nonebot_plugin_uninfo import Uninfo
|
6
|
+
import anyio
|
7
|
+
import anyio.streams.memory
|
8
|
+
from nonebot_plugin_alconna import UniMessage
|
9
|
+
from nonebot_plugin_uninfo import Session
|
14
10
|
|
15
|
-
from .
|
11
|
+
from .constant import STOP_COMMAND
|
12
|
+
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
from .player_set import PlayerSet
|
15
|
+
from .players import Player
|
16
|
+
|
17
|
+
T = TypeVar("T")
|
16
18
|
|
17
19
|
|
18
20
|
def check_index(text: str, arrlen: int) -> int | None:
|
@@ -23,198 +25,126 @@ def check_index(text: str, arrlen: int) -> int | None:
|
|
23
25
|
return None
|
24
26
|
|
25
27
|
|
28
|
+
def link(text: str, url: str | None) -> str:
|
29
|
+
return text if url is None else f"\u001b]8;;{url}\u0007{text}\u001b]8;;\u0007"
|
30
|
+
|
31
|
+
|
32
|
+
def extract_session_member_nick(session: Session) -> str | None:
|
33
|
+
return (
|
34
|
+
(session.member and session.member.nick)
|
35
|
+
or session.user.nick
|
36
|
+
or session.user.name
|
37
|
+
)
|
38
|
+
|
39
|
+
|
40
|
+
class _InputTask:
|
41
|
+
_event: anyio.Event
|
42
|
+
_msg: UniMessage
|
43
|
+
|
44
|
+
def __init__(self) -> None:
|
45
|
+
self._event = anyio.Event()
|
46
|
+
|
47
|
+
def set(self, msg: UniMessage) -> None:
|
48
|
+
self._msg = msg
|
49
|
+
self._event.set()
|
50
|
+
|
51
|
+
async def wait(self) -> UniMessage:
|
52
|
+
await self._event.wait()
|
53
|
+
return self._msg
|
54
|
+
|
55
|
+
|
26
56
|
class InputStore:
|
27
|
-
locks: ClassVar[dict[str,
|
28
|
-
|
29
|
-
clear_handle: ClassVar[dict[str, asyncio.Handle]] = {}
|
57
|
+
locks: ClassVar[dict[str, anyio.Lock]] = defaultdict(anyio.Lock)
|
58
|
+
tasks: ClassVar[dict[str, _InputTask]] = {}
|
30
59
|
|
31
|
-
@
|
32
|
-
def
|
33
|
-
|
34
|
-
del cls.locks[key]
|
35
|
-
if key in cls.clear_handle:
|
36
|
-
del cls.clear_handle[key]
|
60
|
+
@staticmethod
|
61
|
+
def _key(user_id: str, group_id: str | None) -> str:
|
62
|
+
return f"{group_id}_{user_id}"
|
37
63
|
|
38
64
|
@classmethod
|
39
65
|
async def fetch(cls, user_id: str, group_id: str | None = None) -> UniMessage[Any]:
|
40
|
-
key =
|
66
|
+
key = cls._key(user_id, group_id)
|
41
67
|
async with cls.locks[key]:
|
42
|
-
cls.
|
68
|
+
cls.tasks[key] = task = _InputTask()
|
43
69
|
try:
|
44
|
-
return await
|
70
|
+
return await task.wait()
|
45
71
|
finally:
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
72
|
+
cls.tasks.pop(key, None)
|
73
|
+
|
74
|
+
@classmethod
|
75
|
+
async def fetch_until_stop(cls, user_id: str, group_id: str | None = None) -> None:
|
76
|
+
while True:
|
77
|
+
msg = await cls.fetch(user_id, group_id)
|
78
|
+
if msg.extract_plain_text().strip() == STOP_COMMAND:
|
79
|
+
return
|
51
80
|
|
52
81
|
@classmethod
|
53
82
|
def put(cls, msg: UniMessage, user_id: str, group_id: str | None = None) -> None:
|
54
|
-
key =
|
55
|
-
if
|
56
|
-
|
83
|
+
key = cls._key(user_id, group_id)
|
84
|
+
if task := cls.tasks.pop(key, None):
|
85
|
+
task.set(msg)
|
57
86
|
|
87
|
+
@classmethod
|
88
|
+
def cleanup(cls, players: list[str], group_id: str) -> None:
|
89
|
+
for p, g in itertools.product(players, (group_id, None)):
|
90
|
+
key = cls._key(p, g)
|
91
|
+
if key in cls.locks:
|
92
|
+
del cls.locks[key]
|
93
|
+
if key in cls.tasks:
|
94
|
+
del cls.tasks[key]
|
58
95
|
|
59
|
-
def user_in_game(self_id: str, user_id: str, group_id: str | None) -> bool:
|
60
|
-
from .game import Game
|
61
96
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
for p in itertools.chain(*[g.players for g in Game.running_games])
|
66
|
-
)
|
97
|
+
@functools.cache
|
98
|
+
def cached_player_set() -> type["PlayerSet"]:
|
99
|
+
from .player_set import PlayerSet
|
67
100
|
|
68
|
-
|
69
|
-
return self_id == game.group.self_id and group_id == game.group.id
|
101
|
+
return PlayerSet
|
70
102
|
|
71
|
-
if game := next(filter(check, Game.running_games), None):
|
72
|
-
return any(user_id == player.user_id for player in game.players)
|
73
103
|
|
74
|
-
|
104
|
+
def as_player_set(*player: "Player") -> "PlayerSet":
|
105
|
+
return cached_player_set()(player)
|
75
106
|
|
76
107
|
|
77
|
-
|
78
|
-
|
108
|
+
class ObjectStream(Generic[T]):
|
109
|
+
__unset = object()
|
110
|
+
_send: anyio.streams.memory.MemoryObjectSendStream[T]
|
111
|
+
_recv: anyio.streams.memory.MemoryObjectReceiveStream[T]
|
112
|
+
_closed: anyio.Event
|
79
113
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
return user_in_game(bot.self_id, target.id, None)
|
84
|
-
return user_in_game(bot.self_id, event.get_user_id(), target.id)
|
114
|
+
def __init__(self, max_buffer_size: float = 0) -> None:
|
115
|
+
self._send, self._recv = anyio.create_memory_object_stream(max_buffer_size)
|
116
|
+
self._closed = anyio.Event()
|
85
117
|
|
118
|
+
async def send(self, obj: T) -> None:
|
119
|
+
await self._send.send(obj)
|
86
120
|
|
87
|
-
async def
|
88
|
-
|
121
|
+
async def recv(self) -> T:
|
122
|
+
result = self.__unset
|
89
123
|
|
124
|
+
async def _recv() -> None:
|
125
|
+
nonlocal result
|
126
|
+
result = await self._recv.receive()
|
127
|
+
tg.cancel_scope.cancel()
|
90
128
|
|
91
|
-
async def
|
92
|
-
|
129
|
+
async def _cancel() -> None:
|
130
|
+
await self._closed.wait()
|
131
|
+
tg.cancel_scope.cancel()
|
93
132
|
|
133
|
+
async with anyio.create_task_group() as tg:
|
134
|
+
tg.start_soon(_recv)
|
135
|
+
tg.start_soon(_cancel)
|
94
136
|
|
95
|
-
|
96
|
-
|
97
|
-
event: Event,
|
98
|
-
group: Target,
|
99
|
-
) -> None:
|
100
|
-
async def same_group(target: MsgTarget) -> bool:
|
101
|
-
return group.verify(target)
|
137
|
+
if result is self.__unset:
|
138
|
+
raise anyio.EndOfStream
|
102
139
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
) ->
|
113
|
-
|
114
|
-
name = session.user.nick or session.user.name or user_id
|
115
|
-
if session.member:
|
116
|
-
name = session.member.nick or name
|
117
|
-
return (
|
118
|
-
user_id,
|
119
|
-
msg.extract_plain_text().strip(),
|
120
|
-
name,
|
121
|
-
)
|
122
|
-
|
123
|
-
async for user, text, name in wait(default=(None, "", "")):
|
124
|
-
if user is None:
|
125
|
-
continue
|
126
|
-
await queue.put((user, text, re.sub(r"[\u2066-\u2069]", "", name)))
|
127
|
-
|
128
|
-
|
129
|
-
async def _prepare_game_handle(
|
130
|
-
queue: asyncio.Queue[tuple[str, str, str]],
|
131
|
-
players: dict[str, str],
|
132
|
-
admin_id: str,
|
133
|
-
) -> None:
|
134
|
-
logger = nonebot.logger.opt(colors=True)
|
135
|
-
|
136
|
-
while True:
|
137
|
-
user, text, name = await queue.get()
|
138
|
-
msg = UniMessage.at(user).text("\n")
|
139
|
-
colored = f"<y>{escape_tag(name)}</y>(<c>{escape_tag(user)}</c>)"
|
140
|
-
|
141
|
-
match (text, user == admin_id):
|
142
|
-
case ("开始游戏", True):
|
143
|
-
player_num = len(players)
|
144
|
-
role_preset = config.get_role_preset()
|
145
|
-
if player_num < min(role_preset):
|
146
|
-
await (
|
147
|
-
msg.text(f"⚠️游戏至少需要 {min(role_preset)} 人, ")
|
148
|
-
.text(f"当前已有 {player_num} 人")
|
149
|
-
.send()
|
150
|
-
)
|
151
|
-
elif player_num > max(role_preset):
|
152
|
-
await (
|
153
|
-
msg.text(f"⚠️游戏最多需要 {max(role_preset)} 人, ")
|
154
|
-
.text(f"当前已有 {player_num} 人")
|
155
|
-
.send()
|
156
|
-
)
|
157
|
-
elif player_num not in role_preset:
|
158
|
-
await (
|
159
|
-
msg.text(f"⚠️不存在总人数为 {player_num} 的预设, ")
|
160
|
-
.text("无法开始游戏")
|
161
|
-
.send()
|
162
|
-
)
|
163
|
-
else:
|
164
|
-
await msg.text("✏️游戏即将开始...").send()
|
165
|
-
logger.info(f"游戏发起者 {colored} 开始游戏")
|
166
|
-
return
|
167
|
-
|
168
|
-
case ("开始游戏", False):
|
169
|
-
await msg.text("⚠️只有游戏发起者可以开始游戏").send()
|
170
|
-
|
171
|
-
case ("结束游戏", True):
|
172
|
-
logger.info(f"游戏发起者 {colored} 结束游戏")
|
173
|
-
await msg.text("ℹ️已结束当前游戏").finish()
|
174
|
-
|
175
|
-
case ("结束游戏", False):
|
176
|
-
await msg.text("⚠️只有游戏发起者可以结束游戏").send()
|
177
|
-
|
178
|
-
case ("加入游戏", True):
|
179
|
-
await msg.text("ℹ️游戏发起者已经加入游戏了").send()
|
180
|
-
|
181
|
-
case ("加入游戏", False):
|
182
|
-
if user not in players:
|
183
|
-
players[user] = name
|
184
|
-
logger.info(f"玩家 {colored} 加入游戏")
|
185
|
-
await msg.text("✅成功加入游戏").send()
|
186
|
-
else:
|
187
|
-
await msg.text("ℹ️你已经加入游戏了").send()
|
188
|
-
|
189
|
-
case ("退出游戏", True):
|
190
|
-
await msg.text("ℹ️游戏发起者无法退出游戏").send()
|
191
|
-
|
192
|
-
case ("退出游戏", False):
|
193
|
-
if user in players:
|
194
|
-
del players[user]
|
195
|
-
logger.info(f"玩家 {colored} 退出游戏")
|
196
|
-
await msg.text("✅成功退出游戏").send()
|
197
|
-
else:
|
198
|
-
await msg.text("ℹ️你还没有加入游戏").send()
|
199
|
-
|
200
|
-
case ("当前玩家", _):
|
201
|
-
msg.text("✨当前玩家:\n")
|
202
|
-
for idx, name in enumerate(players.values(), 1):
|
203
|
-
msg.text(f"\n{idx}. {name}")
|
204
|
-
await msg.send()
|
205
|
-
|
206
|
-
|
207
|
-
async def prepare_game(event: Event, players: dict[str, str]) -> None:
|
208
|
-
from .game import Game
|
209
|
-
|
210
|
-
group = UniMessage.get_target(event)
|
211
|
-
Game.starting_games[group] = players
|
212
|
-
|
213
|
-
queue: asyncio.Queue[tuple[str, str, str]] = asyncio.Queue()
|
214
|
-
task_receive = asyncio.create_task(_prepare_game_receive(queue, event, group))
|
215
|
-
|
216
|
-
try:
|
217
|
-
await _prepare_game_handle(queue, players, event.get_user_id())
|
218
|
-
finally:
|
219
|
-
task_receive.cancel()
|
220
|
-
del Game.starting_games[group]
|
140
|
+
return cast(T, result)
|
141
|
+
|
142
|
+
def close(self) -> None:
|
143
|
+
self._closed.set()
|
144
|
+
|
145
|
+
@property
|
146
|
+
def closed(self) -> bool:
|
147
|
+
return self._closed.is_set()
|
148
|
+
|
149
|
+
async def wait_closed(self) -> None:
|
150
|
+
await self._closed.wait()
|
{nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.6.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nonebot-plugin-werewolf
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.6
|
4
4
|
Summary: 适用于 Nonebot2 的狼人杀插件
|
5
5
|
Author-email: wyf7685 <wyf7685@163.com>
|
6
6
|
License: MIT
|
@@ -12,8 +12,10 @@ Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
13
13
|
Requires-Dist: nonebot2 >=2.3.3
|
14
14
|
Requires-Dist: nonebot-plugin-alconna >=0.52.1
|
15
|
+
Requires-Dist: nonebot-plugin-localstore >=0.7.1
|
15
16
|
Requires-Dist: nonebot-plugin-uninfo >=0.4.0
|
16
17
|
Requires-Dist: nonebot-plugin-waiter >=0.7.1
|
18
|
+
Requires-Dist: anyio >=4.6.0
|
17
19
|
|
18
20
|
<div align="center">
|
19
21
|
<a href="https://v2.nonebot.dev/store">
|
@@ -42,6 +44,8 @@ _✨ 简单的狼人杀插件 ✨_
|
|
42
44
|
[](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/pyright.yml)
|
43
45
|
[](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/pypi-publish.yml)
|
44
46
|
|
47
|
+
<!-- https://github.com/lgc2333/nonebot-registry-badge -->
|
48
|
+
|
45
49
|
[](https://registry.nonebot.dev/plugin/nonebot-plugin-werewolf:nonebot_plugin_werewolf)
|
46
50
|
[](https://registry.nonebot.dev/plugin/nonebot-plugin-werewolf:nonebot_plugin_werewolf)
|
47
51
|
|
@@ -54,7 +58,7 @@ _✨ 简单的狼人杀插件 ✨_
|
|
54
58
|
## 💿 安装
|
55
59
|
|
56
60
|
> [!note]
|
57
|
-
>
|
61
|
+
>
|
58
62
|
> 请确保 NoneBot2 使用的 Python 解释器版本 >=3.10
|
59
63
|
|
60
64
|
<details open>
|
@@ -102,17 +106,16 @@ _✨ 简单的狼人杀插件 ✨_
|
|
102
106
|
|
103
107
|
## ⚙️ 配置
|
104
108
|
|
105
|
-
在 nonebot2 项目的 `.env`
|
109
|
+
在 nonebot2 项目的 `.env` 文件中添加如下配置:
|
110
|
+
|
111
|
+
| 配置项 | 必填 | 默认值 | 说明 |
|
112
|
+
| :-----------------------: | :---: | :-----: | :------------------------: |
|
113
|
+
| `werewolf__enable_poke` | 否 | `True` | 是否使用戳一戳简化操作流程 |
|
114
|
+
| `werewolf__enable_button` | 否 | `False` | 是否在交互中添加按钮 |
|
106
115
|
|
107
|
-
|
108
|
-
| :-----------------------------: | :--: | :----: | :-----------------------------------------------------------: |
|
109
|
-
| `werewolf__enable_poke` | 否 | `True` | 是否使用戳一戳简化操作流程<br/>仅在 `OneBot V11` 适配器下生效 |
|
110
|
-
| `werewolf__role_preset` | 否 | - | 覆写插件内置的职业预设 |
|
111
|
-
| `werewolf__werewolf_priority` | 否 | - | 自定义狼人职业优先级 |
|
112
|
-
| `werewolf__priesthood_proirity` | 否 | - | 自定义神职职业优先级 |
|
113
|
-
| `werewolf__joker_probability` | 否 | `0.0` | 小丑职业替换平民的概率, 范围`[0,1]` |
|
116
|
+
`werewolf__enable_poke` 仅在 `OneBot V11` 适配器 / `Satori/chronocat` 下生效
|
114
117
|
|
115
|
-
`
|
118
|
+
`werewolf__enable_button` 仅在 `Telegram` 适配器下通过测试,不保证在其他适配器的可用性。如有疑问欢迎提出。
|
116
119
|
|
117
120
|
## 🎉 使用
|
118
121
|
|
@@ -131,24 +134,31 @@ _✨ 简单的狼人杀插件 ✨_
|
|
131
134
|
|
132
135
|
而对于野生机器人,现有协议端通常不支持或不建议使用临时私聊消息。
|
133
136
|
|
134
|
-
|
137
|
+
在使用本插件前,应当确保机器人可以正常向玩家发送私聊消息。~~即保证机器人与玩家为好友关系~~
|
135
138
|
|
136
139
|
</details>
|
137
140
|
|
138
141
|
### 指令表
|
139
142
|
|
140
|
-
| 指令 |
|
141
|
-
| :-----------------: |
|
142
|
-
| `werewolf`/`狼人杀` |
|
143
|
-
| `开始游戏` |
|
144
|
-
| `结束游戏` |
|
145
|
-
| `当前玩家` |
|
146
|
-
| `加入游戏` |
|
147
|
-
| `退出游戏` |
|
143
|
+
| 指令 | 权限 | 需要@ | 范围 | 说明 |
|
144
|
+
| :-----------------: | :-----------------: | :---: | :---: | :---------------------------------------: |
|
145
|
+
| `werewolf`/`狼人杀` | 群员 | 是 | 群聊 | 发起游戏 (进入准备阶段) |
|
146
|
+
| `开始游戏` | 游戏发起者 | 否 | 群聊 | _[准备阶段]_ 游戏发起者开始游戏 |
|
147
|
+
| `结束游戏` | 游戏发起者/超级用户 | 否 | 群聊 | _[准备阶段]_ 游戏发起者/超级用户 结束游戏 |
|
148
|
+
| `当前玩家` | 群员 | 否 | 群聊 | _[准备阶段]_ 列出参与游戏的玩家列表 |
|
149
|
+
| `加入游戏` | 群员 | 否 | 群聊 | _[准备阶段]_ 玩家加入游戏 |
|
150
|
+
| `退出游戏` | 群员 | 否 | 群聊 | _[准备阶段]_ 玩家退出游戏 |
|
151
|
+
| `中止游戏` | 超级用户 | 是 | 群聊 | _[游戏内]_ 超级用户强制中止游戏 |
|
152
|
+
| `狼人杀预设` | 超级用户 | 否 | 任意 | _[游戏外]_ 超级用户编辑游戏预设 |
|
153
|
+
|
154
|
+
- 发起游戏时添加 `restart`/`重开`, 可加载上一次游戏的玩家列表, 快速发起游戏。例: `werewolf restart`/`狼人杀 重开`
|
155
|
+
|
156
|
+
- `狼人杀预设` 命令用法可通过 `狼人杀预设 --help` 获取,或参考 [游戏内容](#游戏内容) 部分的介绍
|
148
157
|
|
149
|
-
_
|
158
|
+
- 对于 `OneBot V11` 适配器和 `Satori` 适配器的 `chronocat`, 启用配置项 `werewolf__enable_poke` 后, 可以使用戳一戳代替 _准备阶段_ 的 `加入游戏` 操作 和 游戏内的 `stop` 命令
|
159
|
+
|
160
|
+
- _其他交互参考游戏内提示_
|
150
161
|
|
151
|
-
对于 `OneBot V11` 适配器, 启用配置项 `werewolf__enable_poke` 后, 可以使用戳一戳代替 _准备阶段_ 的 `加入游戏` 操作 和 游戏内的 `/stop` 命令
|
152
162
|
|
153
163
|
### 游戏内容
|
154
164
|
|
@@ -162,31 +172,22 @@ _其他交互参考游戏内提示_
|
|
162
172
|
|
163
173
|
| 总人数 | 狼人 | 神职 | 平民 |
|
164
174
|
| ------ | ---- | ---- | ---- |
|
165
|
-
| 6
|
166
|
-
| 7
|
167
|
-
| 8
|
168
|
-
| 9
|
169
|
-
| 10
|
170
|
-
| 11
|
171
|
-
| 12
|
175
|
+
| 6 | 1 | 2 | 3 |
|
176
|
+
| 7 | 2 | 2 | 3 |
|
177
|
+
| 8 | 2 | 3 | 3 |
|
178
|
+
| 9 | 2 | 4 | 3 |
|
179
|
+
| 10 | 3 | 4 | 3 |
|
180
|
+
| 11 | 3 | 5 | 3 |
|
181
|
+
| 12 | 4 | 5 | 3 |
|
172
182
|
|
173
|
-
|
183
|
+
职业预设可以通过命令 `狼人杀预设 职业 ...` 修改
|
174
184
|
|
175
185
|
<details>
|
176
186
|
<summary>示例</summary>
|
177
187
|
|
178
|
-
|
179
|
-
|
180
|
-
```env
|
181
|
-
werewolf__role_preset='
|
182
|
-
[
|
183
|
-
[6, 1, 3, 2],
|
184
|
-
[7, 2, 3, 2]
|
185
|
-
]
|
186
|
-
'
|
187
|
-
```
|
188
|
+
- 命令: `狼人杀预设 职业 6 1 3 2`
|
188
189
|
|
189
|
-
|
190
|
+
- 上述命令指定当总人数为 6 时,狼人、神职、平民的数量分别为 1、3、2
|
190
191
|
|
191
192
|
</details>
|
192
193
|
<br/>
|
@@ -196,45 +197,43 @@ werewolf__role_preset='
|
|
196
197
|
- `狼人`: `狼人`, `狼人`, `狼王`, `狼人`
|
197
198
|
- `神职`: `女巫`, `预言家`, `猎人`, `守卫`, `白痴`
|
198
199
|
|
199
|
-
|
200
|
+
职业分配优先级可以通过命令 `狼人杀预设 狼人/神职` 修改
|
200
201
|
|
201
202
|
<details>
|
202
203
|
<summary>示例</summary>
|
203
204
|
|
204
|
-
####
|
205
|
+
#### 命令 `狼人杀预设 狼人`
|
206
|
+
|
207
|
+
- 命令: `狼人杀预设 狼人 狼 狼王 狼 狼`
|
205
208
|
|
206
|
-
|
207
|
-
werewolf__werewolf_priority=[1, 2, 1, 1]
|
208
|
-
```
|
209
|
+
- 上述命令指定狼人的职业优先级为 `狼人`, `狼王`, `狼人`, `狼人`
|
209
210
|
|
210
|
-
|
211
|
+
#### 命令 `狼人杀预设 神职`
|
211
212
|
|
212
|
-
|
213
|
+
- 命令: `狼人杀预设 神职 预言家 女巫 猎人 守卫 白痴`
|
213
214
|
|
214
|
-
|
215
|
-
|
216
|
-
|
215
|
+
- 上述命令指定狼人的职业优先级为 `预言家`, `女巫`, `猎人`, `守卫`, `白痴`
|
216
|
+
|
217
|
+
> [!note]
|
218
|
+
>
|
219
|
+
> 以上两条命令均支持交互式输入
|
220
|
+
>
|
221
|
+
> 例:向机器人发送命令 `狼人杀预设 狼人`,在接下来的一条消息中发送 `狼人 狼王 狼人 狼人`
|
222
|
+
>
|
223
|
+
> 其效果等同于以上描述中的单条命令 `狼人杀预设 狼人 狼人 狼王 狼人 狼人`
|
217
224
|
|
218
|
-
|
225
|
+
</details>
|
226
|
+
<br/>
|
219
227
|
|
220
|
-
|
228
|
+
对于 `小丑` 职业,当预设中的平民数量大于或等于 2 时,将有 *一定概率* 将其中一个平民替换为小丑。
|
221
229
|
|
222
|
-
|
230
|
+
小丑属于第三方阵营,胜利条件为在投票阶段被票出,在预言家查验及游戏进程判断时视作平民。
|
223
231
|
|
224
|
-
|
232
|
+
小丑生成概率可以通过命令 `狼人杀预设 小丑 <概率>` 设置,默认值为 0 (不生成小丑)。
|
225
233
|
|
226
|
-
|
227
|
-
| -------- | ------ |
|
228
|
-
| `狼人` | `1` |
|
229
|
-
| `狼王` | `2` |
|
230
|
-
| `预言家` | `11` |
|
231
|
-
| `女巫` | `12` |
|
232
|
-
| `猎人` | `13` |
|
233
|
-
| `守卫` | `14` |
|
234
|
-
| `白痴` | `15` |
|
235
|
-
| `平民` | `0` |
|
234
|
+
### 已知问题
|
236
235
|
|
237
|
-
|
236
|
+
- 截止 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
|
238
237
|
|
239
238
|
## 📝 更新日志
|
240
239
|
|
@@ -243,6 +242,19 @@ werewolf__priesthood_proirity=[11, 12, 13, 14, 15]
|
|
243
242
|
|
244
243
|
<!-- CHANGELOG -->
|
245
244
|
|
245
|
+
- 2024.10.31 v1.1.6
|
246
|
+
|
247
|
+
- 新增超级用户中止游戏 (#7)
|
248
|
+
- 新增快速发起上次游戏 (#8)
|
249
|
+
- 准备阶段添加可选的交互按钮
|
250
|
+
- 新增超级用户修改游戏预设 (#9)
|
251
|
+
|
252
|
+
- 2024.10.23 v1.1.5
|
253
|
+
|
254
|
+
- 添加对 chronocat:poke 的支持
|
255
|
+
- 游戏内 stop 命令使用 COMMAND_START
|
256
|
+
- 使用 `anyio` 重写并发逻辑
|
257
|
+
|
246
258
|
- 2024.10.06 v1.1.3
|
247
259
|
|
248
260
|
- 使用 `RF-Tar-Railt/nonebot-plugin-uninfo` 获取用户数据
|
@@ -0,0 +1,34 @@
|
|
1
|
+
nonebot_plugin_werewolf/__init__.py,sha256=ZomfjWnGRnFuh3I__spYbLRE1Z3wTUthwXzc5x8YPJw,931
|
2
|
+
nonebot_plugin_werewolf/config.py,sha256=bMRRqNVWNsFDKyijxZZYPN7DCAf9bYf2MdfbPXE239w,1287
|
3
|
+
nonebot_plugin_werewolf/constant.py,sha256=_ngw2xtXVZMTQXQ0gv4l9h4Lo1jq5v28fKLOGJ7G57o,1796
|
4
|
+
nonebot_plugin_werewolf/exception.py,sha256=2F2kZsMaRIa7jOiIQJiM10K7Z59ouCpaZENcnEcEEXQ,398
|
5
|
+
nonebot_plugin_werewolf/game.py,sha256=xU8IcrWQNRUjzfPIAbm1XCeshwfy8SWgxapUP1_NGOw,18925
|
6
|
+
nonebot_plugin_werewolf/models.py,sha256=ljWy6BaTVyIK4Ng-wUVRteBLZe2pQLf8l3yWFZzWXHQ,1505
|
7
|
+
nonebot_plugin_werewolf/player_set.py,sha256=84hZOOAaPjTyZZDje6mNy7zm4G5UH2nGDq1pvDNFT9w,2538
|
8
|
+
nonebot_plugin_werewolf/utils.py,sha256=PBgadYdF3IQbaVPjcmstmsOGddfPvj8rcbiYQllHFYY,4096
|
9
|
+
nonebot_plugin_werewolf/matchers/__init__.py,sha256=BnzEDmW8n1wkyI-un0DYXt2k_6CFv6NE8itZ2daw4zQ,174
|
10
|
+
nonebot_plugin_werewolf/matchers/depends.py,sha256=poMQJ7Mzd3IZFvh2MvnfYdnnb2c-r6XFK_IOr50PL3o,1321
|
11
|
+
nonebot_plugin_werewolf/matchers/edit_preset.py,sha256=gKd1csoR9u4VoeulTtxUUgxsOdgB0SDC1FMxMRdgw5I,8087
|
12
|
+
nonebot_plugin_werewolf/matchers/message_in_game.py,sha256=lW0TMC85B-g9wZQcL7Q-LQSYyvO4-uem3Ye1szX2hU8,837
|
13
|
+
nonebot_plugin_werewolf/matchers/start_game.py,sha256=YM4VGKpV8GQ29SgPh0jvWUHnx8onAvx_m4RWyeuRxmc,10187
|
14
|
+
nonebot_plugin_werewolf/matchers/superuser_ops.py,sha256=Xjsmwzkt6Y-M_QlQwUL0EXN_fDqEqKSM4fcLk9fTvDY,685
|
15
|
+
nonebot_plugin_werewolf/matchers/poke/__init__.py,sha256=gYysvGjztN3iDQpX6v5nkPT195FXnk7fqP9kzByTES0,220
|
16
|
+
nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py,sha256=SrFN8dQELFVDR5US9sOcE2gaOnH7AFiRVVK2RNa-Y5o,4023
|
17
|
+
nonebot_plugin_werewolf/matchers/poke/ob11_poke.py,sha256=LROxtbauw4xbB8UKglsx6b6hkKWs_17HmgK4NTXW1HY,2640
|
18
|
+
nonebot_plugin_werewolf/players/__init__.py,sha256=djAI5XxR2I-XvnH-lVqX_YCHB_AiT-6jdmwFE1ffN_0,379
|
19
|
+
nonebot_plugin_werewolf/players/can_shoot.py,sha256=Z0AR_jCfcU1ps5629sWB_mH8O_iVLy8-DyePgBfznNA,1814
|
20
|
+
nonebot_plugin_werewolf/players/civilian.py,sha256=9m-bgzqHji-9Aejl2TnchSIRw_SZpKLqCGdaEWXhopc,155
|
21
|
+
nonebot_plugin_werewolf/players/guard.py,sha256=gHPlIfBXtQ8MSoWvucIIq0XrJQx9KIIKIVl-jwAHhgc,1132
|
22
|
+
nonebot_plugin_werewolf/players/hunter.py,sha256=q17IjSXt5knDAc49NbV0NCwNW7qASqODUNgC0L1zqeI,193
|
23
|
+
nonebot_plugin_werewolf/players/idiot.py,sha256=jz13BN4BsYcmiZdTwSlXUm4yc0KR8GUmQmq2GI7_Kzo,1431
|
24
|
+
nonebot_plugin_werewolf/players/joker.py,sha256=n_jlddGMpFJ0O0sc_1J6IybfPsPJSWeS4GC0S6IZoTk,826
|
25
|
+
nonebot_plugin_werewolf/players/player.py,sha256=hEbGRF5vrgKYKKEC5DB3JUIG6SEyvoHTYGZUqHPjf8Q,6953
|
26
|
+
nonebot_plugin_werewolf/players/prophet.py,sha256=wrTR8BnktiZ8aEI4VzYa5kt4GXyFnyi5wZmCO933-rE,917
|
27
|
+
nonebot_plugin_werewolf/players/werewolf.py,sha256=jZMzYE0LiwsxO8XHMlWRk25XO5gGe24t87NqzLc3I4A,3287
|
28
|
+
nonebot_plugin_werewolf/players/witch.py,sha256=FOM_MMKUjO6QpOQK9JvHq9zwa4GTVCVnW7UtPgT_BTw,2360
|
29
|
+
nonebot_plugin_werewolf/players/wolfking.py,sha256=Y_G1eDdFYGTip5Pl9Sz0OvPsP0aiiFH8NkfGiFu7r1E,438
|
30
|
+
nonebot_plugin_werewolf-1.1.6.dist-info/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
|
31
|
+
nonebot_plugin_werewolf-1.1.6.dist-info/METADATA,sha256=pBGQnG8aePnlLEcZBlF_BqrIe4Y4O8oMK5mFwPGLWwg,11954
|
32
|
+
nonebot_plugin_werewolf-1.1.6.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
33
|
+
nonebot_plugin_werewolf-1.1.6.dist-info/top_level.txt,sha256=wLTfg8sTKbH9lLT9LtU118C9cTspEBJareLsrYM52YA,24
|
34
|
+
nonebot_plugin_werewolf-1.1.6.dist-info/RECORD,,
|