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.
- nonebot_plugin_werewolf/__init__.py +1 -1
- nonebot_plugin_werewolf/config.py +76 -18
- nonebot_plugin_werewolf/constant.py +54 -46
- nonebot_plugin_werewolf/exception.py +2 -4
- nonebot_plugin_werewolf/game.py +193 -166
- nonebot_plugin_werewolf/matchers/__init__.py +1 -0
- nonebot_plugin_werewolf/matchers/depends.py +4 -4
- nonebot_plugin_werewolf/matchers/edit_behavior.py +205 -0
- nonebot_plugin_werewolf/matchers/edit_preset.py +11 -11
- nonebot_plugin_werewolf/matchers/message_in_game.py +3 -1
- nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py +8 -5
- nonebot_plugin_werewolf/matchers/poke/ob11_poke.py +3 -3
- nonebot_plugin_werewolf/matchers/start_game.py +213 -175
- nonebot_plugin_werewolf/matchers/superuser_ops.py +3 -3
- nonebot_plugin_werewolf/models.py +31 -19
- nonebot_plugin_werewolf/player_set.py +10 -8
- nonebot_plugin_werewolf/players/__init__.py +1 -1
- nonebot_plugin_werewolf/players/can_shoot.py +15 -15
- nonebot_plugin_werewolf/players/civilian.py +1 -1
- nonebot_plugin_werewolf/players/guard.py +16 -14
- nonebot_plugin_werewolf/players/hunter.py +1 -1
- nonebot_plugin_werewolf/players/idiot.py +3 -3
- nonebot_plugin_werewolf/players/{joker.py → jester.py} +4 -5
- nonebot_plugin_werewolf/players/player.py +93 -29
- nonebot_plugin_werewolf/players/prophet.py +11 -10
- nonebot_plugin_werewolf/players/werewolf.py +63 -31
- nonebot_plugin_werewolf/players/witch.py +29 -12
- nonebot_plugin_werewolf/players/wolfking.py +1 -1
- nonebot_plugin_werewolf/utils.py +106 -7
- {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/METADATA +27 -20
- nonebot_plugin_werewolf-1.1.8.dist-info/RECORD +35 -0
- {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/WHEEL +1 -1
- nonebot_plugin_werewolf-1.1.6.dist-info/RECORD +0 -34
- {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/LICENSE +0 -0
- {nonebot_plugin_werewolf-1.1.6.dist-info → nonebot_plugin_werewolf-1.1.8.dist-info}/top_level.txt +0 -0
@@ -1,45 +1,103 @@
|
|
1
1
|
import json
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Any, ClassVar, Final
|
4
|
+
from typing_extensions import Self
|
2
5
|
|
3
|
-
|
6
|
+
import nonebot
|
4
7
|
from nonebot.compat import model_dump, type_validate_json
|
5
8
|
from nonebot_plugin_localstore import get_plugin_data_file
|
6
9
|
from pydantic import BaseModel, Field
|
7
|
-
from typing_extensions import Self
|
8
10
|
|
9
11
|
from .constant import (
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
DEFAULT_PRIESTHOOD_PRIORITY,
|
13
|
+
DEFAULT_ROLE_PRESET,
|
14
|
+
DEFAULT_WEREWOLF_PRIORITY,
|
15
|
+
stop_command_prompt,
|
13
16
|
)
|
14
17
|
from .models import Role
|
15
18
|
|
16
19
|
|
17
|
-
class
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
class ConfigFile(BaseModel):
|
21
|
+
FILE: ClassVar[Path]
|
22
|
+
_cache: ClassVar[Self | None] = None
|
23
|
+
|
24
|
+
def __init_subclass__(cls, **kwargs: Any) -> None: # noqa: ANN401
|
25
|
+
super().__init_subclass__(**kwargs)
|
26
|
+
if not cls.FILE.exists():
|
27
|
+
cls().save()
|
22
28
|
|
23
29
|
@classmethod
|
24
30
|
def load(cls) -> Self:
|
25
|
-
return type_validate_json(cls,
|
31
|
+
return type_validate_json(cls, cls.FILE.read_text())
|
32
|
+
|
33
|
+
@classmethod
|
34
|
+
def get(cls, *, use_cache: bool = True) -> Self:
|
35
|
+
if cls._cache is None or not use_cache:
|
36
|
+
cls._cache = cls.load()
|
37
|
+
return cls._cache
|
26
38
|
|
27
39
|
def save(self) -> None:
|
28
|
-
|
40
|
+
self.FILE.write_text(json.dumps(model_dump(self)))
|
41
|
+
type(self)._cache = self # noqa: SLF001
|
42
|
+
|
43
|
+
|
44
|
+
class PresetData(ConfigFile):
|
45
|
+
FILE: ClassVar[Path] = get_plugin_data_file("preset.json")
|
46
|
+
|
47
|
+
role_preset: dict[int, tuple[int, int, int]] = DEFAULT_ROLE_PRESET.copy()
|
48
|
+
werewolf_priority: list[Role] = DEFAULT_WEREWOLF_PRIORITY.copy()
|
49
|
+
priesthood_proirity: list[Role] = DEFAULT_PRIESTHOOD_PRIORITY.copy()
|
50
|
+
jester_probability: float = Field(default=0.0, ge=0.0, le=1.0)
|
51
|
+
|
52
|
+
|
53
|
+
class GameBehavior(ConfigFile):
|
54
|
+
FILE: ClassVar[Path] = get_plugin_data_file("behavior.json")
|
55
|
+
|
56
|
+
show_roles_list_on_start: bool = False
|
57
|
+
speak_in_turn: bool = False
|
58
|
+
dead_channel_rate_limit: int = 8 # per minute
|
59
|
+
|
60
|
+
class _Timeout(BaseModel):
|
61
|
+
prepare: int = Field(default=5 * 60, ge=5 * 60)
|
62
|
+
speak: int = Field(default=60, ge=60)
|
63
|
+
group_speak: int = Field(default=120, ge=120)
|
64
|
+
interact: int = Field(default=60, ge=60)
|
65
|
+
vote: int = Field(default=60, ge=60)
|
66
|
+
werewolf: int = Field(default=120, ge=120)
|
67
|
+
|
68
|
+
@property
|
69
|
+
def speak_timeout_prompt(self) -> str:
|
70
|
+
return (
|
71
|
+
f"限时{self.speak / 60:.1f}分钟, "
|
72
|
+
f"发送 “{stop_command_prompt()}” 结束发言"
|
73
|
+
)
|
74
|
+
|
75
|
+
@property
|
76
|
+
def group_speak_timeout_prompt(self) -> str:
|
77
|
+
return (
|
78
|
+
f"限时{self.group_speak / 60:.1f}分钟, "
|
79
|
+
f"全员发送 “{stop_command_prompt()}” 结束发言"
|
80
|
+
)
|
81
|
+
|
82
|
+
timeout: Final[_Timeout] = _Timeout()
|
29
83
|
|
30
84
|
|
31
85
|
class PluginConfig(BaseModel):
|
32
86
|
enable_poke: bool = True
|
33
87
|
enable_button: bool = False
|
88
|
+
stop_command: str | set[str] = "stop"
|
89
|
+
|
90
|
+
def get_stop_command(self) -> list[str]:
|
91
|
+
return (
|
92
|
+
[self.stop_command]
|
93
|
+
if isinstance(self.stop_command, str)
|
94
|
+
else sorted(self.stop_command, key=len)
|
95
|
+
)
|
34
96
|
|
35
97
|
|
36
98
|
class Config(BaseModel):
|
37
99
|
werewolf: PluginConfig = PluginConfig()
|
38
100
|
|
39
101
|
|
40
|
-
|
41
|
-
|
42
|
-
PresetData().save()
|
43
|
-
|
44
|
-
config = get_plugin_config(Config).werewolf
|
45
|
-
logger.debug(f"加载插件配置: {config}")
|
102
|
+
config = nonebot.get_plugin_config(Config).werewolf
|
103
|
+
nonebot.logger.debug(f"加载插件配置: {config}")
|
@@ -1,55 +1,63 @@
|
|
1
|
+
import functools
|
2
|
+
|
1
3
|
import nonebot
|
2
4
|
|
3
5
|
from .models import GameStatus, KillReason, Role, RoleGroup
|
4
6
|
|
7
|
+
STOP_COMMAND = "{{stop}}"
|
5
8
|
COMMAND_START = next(
|
6
9
|
iter(sorted(nonebot.get_driver().config.command_start, key=len)), ""
|
7
10
|
)
|
8
|
-
STOP_COMMAND_PROMPT = f"{COMMAND_START}stop"
|
9
|
-
STOP_COMMAND = "{{stop}}"
|
10
11
|
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
Role.
|
21
|
-
Role.
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
@functools.cache
|
14
|
+
def stop_command_prompt() -> str:
|
15
|
+
from .config import config # circular import
|
16
|
+
|
17
|
+
return COMMAND_START + config.get_stop_command()[0]
|
18
|
+
|
19
|
+
|
20
|
+
ROLE_NAME_CONV: dict[Role | RoleGroup, str] = {
|
21
|
+
Role.WEREWOLF: "狼人",
|
22
|
+
Role.WOLFKING: "狼王",
|
23
|
+
Role.PROPHET: "预言家",
|
24
|
+
Role.WITCH: "女巫",
|
25
|
+
Role.HUNTER: "猎人",
|
26
|
+
Role.GUARD: "守卫",
|
27
|
+
Role.IDIOT: "白痴",
|
28
|
+
Role.JESTER: "小丑",
|
29
|
+
Role.CIVILIAN: "平民",
|
30
|
+
RoleGroup.WEREWOLF: "狼人",
|
31
|
+
RoleGroup.GOODGUY: "好人",
|
32
|
+
RoleGroup.OTHERS: "其他",
|
25
33
|
}
|
26
34
|
|
27
|
-
|
28
|
-
Role.
|
29
|
-
Role.
|
30
|
-
Role.
|
31
|
-
Role.
|
32
|
-
Role.
|
33
|
-
Role.
|
34
|
-
Role.
|
35
|
-
Role.
|
36
|
-
Role.
|
35
|
+
ROLE_EMOJI: dict[Role, str] = {
|
36
|
+
Role.WEREWOLF: "🐺",
|
37
|
+
Role.WOLFKING: "🐺👑",
|
38
|
+
Role.PROPHET: "🔮",
|
39
|
+
Role.WITCH: "🧙♀️",
|
40
|
+
Role.HUNTER: "🕵️",
|
41
|
+
Role.GUARD: "🛡️",
|
42
|
+
Role.IDIOT: "👨🏻🦲",
|
43
|
+
Role.JESTER: "🤡",
|
44
|
+
Role.CIVILIAN: "👨🏻🌾",
|
37
45
|
}
|
38
46
|
|
39
|
-
|
40
|
-
GameStatus.
|
41
|
-
GameStatus.
|
42
|
-
GameStatus.
|
47
|
+
GAME_STATUS_CONV: dict[GameStatus, str] = {
|
48
|
+
GameStatus.GOODGUY: "好人",
|
49
|
+
GameStatus.WEREWOLF: "狼人",
|
50
|
+
GameStatus.JESTER: "小丑",
|
43
51
|
}
|
44
52
|
|
45
|
-
|
46
|
-
KillReason.
|
47
|
-
KillReason.
|
48
|
-
KillReason.
|
49
|
-
KillReason.
|
53
|
+
REPORT_TEXT: dict[KillReason, tuple[str, str]] = {
|
54
|
+
KillReason.WEREWOLF: ("🔪", "刀了"),
|
55
|
+
KillReason.POISON: ("🧪", "毒死"),
|
56
|
+
KillReason.SHOOT: ("🔫", "射杀"),
|
57
|
+
KillReason.VOTE: ("🗳️", "票出"),
|
50
58
|
}
|
51
59
|
|
52
|
-
|
60
|
+
DEFAULT_ROLE_PRESET: dict[int, tuple[int, int, int]] = {
|
53
61
|
# 总人数: (狼, 神, 民)
|
54
62
|
6: (1, 2, 3),
|
55
63
|
7: (2, 2, 3),
|
@@ -59,16 +67,16 @@ default_role_preset: dict[int, tuple[int, int, int]] = {
|
|
59
67
|
11: (3, 5, 3),
|
60
68
|
12: (4, 5, 3),
|
61
69
|
}
|
62
|
-
|
63
|
-
Role.
|
64
|
-
Role.
|
65
|
-
Role.
|
66
|
-
Role.
|
70
|
+
DEFAULT_WEREWOLF_PRIORITY: list[Role] = [
|
71
|
+
Role.WEREWOLF,
|
72
|
+
Role.WEREWOLF,
|
73
|
+
Role.WOLFKING,
|
74
|
+
Role.WEREWOLF,
|
67
75
|
]
|
68
|
-
|
69
|
-
Role.
|
70
|
-
Role.
|
71
|
-
Role.
|
72
|
-
Role.
|
73
|
-
Role.
|
76
|
+
DEFAULT_PRIESTHOOD_PRIORITY: list[Role] = [
|
77
|
+
Role.WITCH,
|
78
|
+
Role.PROPHET,
|
79
|
+
Role.HUNTER,
|
80
|
+
Role.GUARD,
|
81
|
+
Role.IDIOT,
|
74
82
|
]
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
1
|
from typing import TYPE_CHECKING
|
4
2
|
|
5
3
|
if TYPE_CHECKING:
|
@@ -13,7 +11,7 @@ class Error(Exception):
|
|
13
11
|
class GameFinished(Error): # noqa: N818
|
14
12
|
"""游戏结束时抛出,无视游戏进程进入结算"""
|
15
13
|
|
16
|
-
status: GameStatus
|
14
|
+
status: "GameStatus"
|
17
15
|
|
18
|
-
def __init__(self, status: GameStatus) -> None:
|
16
|
+
def __init__(self, status: "GameStatus") -> None:
|
19
17
|
self.status = status
|