nonebot-plugin-slot-machine 0.0.4__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_slot_machine-0.0.4/LICENSE +21 -0
- nonebot_plugin_slot_machine-0.0.4/PKG-INFO +30 -0
- nonebot_plugin_slot_machine-0.0.4/README.md +12 -0
- nonebot_plugin_slot_machine-0.0.4/nonebot_plugin_slot_machine.egg-info/PKG-INFO +30 -0
- nonebot_plugin_slot_machine-0.0.4/nonebot_plugin_slot_machine.egg-info/SOURCES.txt +15 -0
- nonebot_plugin_slot_machine-0.0.4/nonebot_plugin_slot_machine.egg-info/dependency_links.txt +1 -0
- nonebot_plugin_slot_machine-0.0.4/nonebot_plugin_slot_machine.egg-info/requires.txt +10 -0
- nonebot_plugin_slot_machine-0.0.4/nonebot_plugin_slot_machine.egg-info/top_level.txt +1 -0
- nonebot_plugin_slot_machine-0.0.4/pyproject.toml +117 -0
- nonebot_plugin_slot_machine-0.0.4/setup.cfg +4 -0
- nonebot_plugin_slot_machine-0.0.4/slot_machine/plugins/slot_machine/__init__.py +307 -0
- nonebot_plugin_slot_machine-0.0.4/slot_machine/plugins/slot_machine/algorithm.py +439 -0
- nonebot_plugin_slot_machine-0.0.4/slot_machine/plugins/slot_machine/constants.py +47 -0
- nonebot_plugin_slot_machine-0.0.4/slot_machine/plugins/slot_machine/database.py +305 -0
- nonebot_plugin_slot_machine-0.0.4/slot_machine/plugins/slot_machine/image/image.png +0 -0
- nonebot_plugin_slot_machine-0.0.4/slot_machine/plugins/slot_machine/plugins/screw_work/__init__.py +335 -0
- nonebot_plugin_slot_machine-0.0.4/slot_machine/plugins/slot_machine/utils.py +268 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 万俊辉
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nonebot-plugin-slot-machine
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: NoneBot slot machine plugin
|
|
5
|
+
Requires-Python: <4.0,>=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: aiosqlite>=0.22.1
|
|
9
|
+
Requires-Dist: nonebot-adapter-milky>=1.2.0
|
|
10
|
+
Requires-Dist: nonebot-plugin-alconna>=0.62.0
|
|
11
|
+
Requires-Dist: nonebot-plugin-localstore>=0.7.4
|
|
12
|
+
Requires-Dist: nonebot2[aiohttp,fastapi]>=2.5.0
|
|
13
|
+
Requires-Dist: pillow>=10.0.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pyright[nodejs]; extra == "dev"
|
|
16
|
+
Requires-Dist: ruff; extra == "dev"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# slot_machine
|
|
20
|
+
|
|
21
|
+
## How to start
|
|
22
|
+
|
|
23
|
+
1. generate project using `nb create` .
|
|
24
|
+
2. create your plugin using `nb plugin create` .
|
|
25
|
+
3. writing your plugins under `slot_machine/plugins` folder.
|
|
26
|
+
4. run your bot using `nb run --reload` .
|
|
27
|
+
|
|
28
|
+
## Documentation
|
|
29
|
+
|
|
30
|
+
See [Docs](https://nonebot.dev/)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# slot_machine
|
|
2
|
+
|
|
3
|
+
## How to start
|
|
4
|
+
|
|
5
|
+
1. generate project using `nb create` .
|
|
6
|
+
2. create your plugin using `nb plugin create` .
|
|
7
|
+
3. writing your plugins under `slot_machine/plugins` folder.
|
|
8
|
+
4. run your bot using `nb run --reload` .
|
|
9
|
+
|
|
10
|
+
## Documentation
|
|
11
|
+
|
|
12
|
+
See [Docs](https://nonebot.dev/)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nonebot-plugin-slot-machine
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: NoneBot slot machine plugin
|
|
5
|
+
Requires-Python: <4.0,>=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: aiosqlite>=0.22.1
|
|
9
|
+
Requires-Dist: nonebot-adapter-milky>=1.2.0
|
|
10
|
+
Requires-Dist: nonebot-plugin-alconna>=0.62.0
|
|
11
|
+
Requires-Dist: nonebot-plugin-localstore>=0.7.4
|
|
12
|
+
Requires-Dist: nonebot2[aiohttp,fastapi]>=2.5.0
|
|
13
|
+
Requires-Dist: pillow>=10.0.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pyright[nodejs]; extra == "dev"
|
|
16
|
+
Requires-Dist: ruff; extra == "dev"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# slot_machine
|
|
20
|
+
|
|
21
|
+
## How to start
|
|
22
|
+
|
|
23
|
+
1. generate project using `nb create` .
|
|
24
|
+
2. create your plugin using `nb plugin create` .
|
|
25
|
+
3. writing your plugins under `slot_machine/plugins` folder.
|
|
26
|
+
4. run your bot using `nb run --reload` .
|
|
27
|
+
|
|
28
|
+
## Documentation
|
|
29
|
+
|
|
30
|
+
See [Docs](https://nonebot.dev/)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
nonebot_plugin_slot_machine.egg-info/PKG-INFO
|
|
5
|
+
nonebot_plugin_slot_machine.egg-info/SOURCES.txt
|
|
6
|
+
nonebot_plugin_slot_machine.egg-info/dependency_links.txt
|
|
7
|
+
nonebot_plugin_slot_machine.egg-info/requires.txt
|
|
8
|
+
nonebot_plugin_slot_machine.egg-info/top_level.txt
|
|
9
|
+
slot_machine/plugins/slot_machine/__init__.py
|
|
10
|
+
slot_machine/plugins/slot_machine/algorithm.py
|
|
11
|
+
slot_machine/plugins/slot_machine/constants.py
|
|
12
|
+
slot_machine/plugins/slot_machine/database.py
|
|
13
|
+
slot_machine/plugins/slot_machine/utils.py
|
|
14
|
+
slot_machine/plugins/slot_machine/image/image.png
|
|
15
|
+
slot_machine/plugins/slot_machine/plugins/screw_work/__init__.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
slot_machine
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nonebot-plugin-slot-machine"
|
|
3
|
+
version = "0.0.4"
|
|
4
|
+
description = "NoneBot slot machine plugin"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11, <4.0"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"aiosqlite>=0.22.1",
|
|
9
|
+
"nonebot-adapter-milky>=1.2.0",
|
|
10
|
+
"nonebot-plugin-alconna>=0.62.0",
|
|
11
|
+
"nonebot-plugin-localstore>=0.7.4",
|
|
12
|
+
"nonebot2[aiohttp,fastapi]>=2.5.0",
|
|
13
|
+
"pillow>=10.0.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["setuptools>=69"]
|
|
18
|
+
build-backend = "setuptools.build_meta"
|
|
19
|
+
|
|
20
|
+
[tool.setuptools.packages.find]
|
|
21
|
+
include = ["slot_machine*"]
|
|
22
|
+
|
|
23
|
+
[tool.setuptools.package-data]
|
|
24
|
+
"slot_machine.plugins.slot_machine" = ["image/*.png"]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
dev = [
|
|
28
|
+
"pyright[nodejs]",
|
|
29
|
+
"ruff"
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[tool.nonebot]
|
|
33
|
+
plugin_dirs = ["slot_machine/plugins"]
|
|
34
|
+
builtin_plugins = []
|
|
35
|
+
|
|
36
|
+
[tool.nonebot.adapters]
|
|
37
|
+
nonebot-adapter-milky = [
|
|
38
|
+
{ name = "nonebot-adapter-milky", module_name = "nonebot.adapters.milky" }
|
|
39
|
+
]
|
|
40
|
+
"@local" = []
|
|
41
|
+
|
|
42
|
+
[tool.nonebot.plugins]
|
|
43
|
+
"@local" = []
|
|
44
|
+
nonebot-plugin-alconna = ["nonebot_plugin_alconna"]
|
|
45
|
+
[tool.ruff]
|
|
46
|
+
line-length = 88
|
|
47
|
+
target-version = "py311"
|
|
48
|
+
|
|
49
|
+
[tool.ruff.format]
|
|
50
|
+
line-ending = "lf"
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
# For more rules, see https://docs.astral.sh/ruff/rules/.
|
|
54
|
+
select = [
|
|
55
|
+
"F", # Pyflakes
|
|
56
|
+
"W", # pycodestyle warnings
|
|
57
|
+
"E", # pycodestyle errors
|
|
58
|
+
"I", # isort
|
|
59
|
+
"C90", # mccabe
|
|
60
|
+
"N", # pep8-naming
|
|
61
|
+
"PL", # pylint
|
|
62
|
+
"UP", # pyupgrade
|
|
63
|
+
"YTT", # flake8-2020
|
|
64
|
+
"ANN", # flake8-annotations
|
|
65
|
+
"ASYNC", # flake8-async
|
|
66
|
+
"BLE", # flake8-blind-except
|
|
67
|
+
"FBT", # flake8-boolean-trap
|
|
68
|
+
"B", # flake8-bugbear
|
|
69
|
+
"A", # flake8-builtins
|
|
70
|
+
"COM", # flake8-commas
|
|
71
|
+
"C4", # flake8-comprehensions
|
|
72
|
+
"DTZ", # flake8-datetimez
|
|
73
|
+
"T10", # flake8-debugger
|
|
74
|
+
"ICN", # flake8-import-conventions
|
|
75
|
+
"PIE", # flake8-pie
|
|
76
|
+
"T20", # flake8-print
|
|
77
|
+
"PYI", # flake8-pyi
|
|
78
|
+
"Q", # flake8-quotes
|
|
79
|
+
"RSE", # flake8-raise
|
|
80
|
+
"RET", # flake8-return
|
|
81
|
+
"SIM", # flake8-simplify
|
|
82
|
+
"SLOT", # flake8-slots
|
|
83
|
+
"TID", # flake8-tidy-imports
|
|
84
|
+
"TC", # flake8-type-checking
|
|
85
|
+
"ARG", # flake8-unused-arguments
|
|
86
|
+
"PTH", # flake8-use-pathlib
|
|
87
|
+
# "ERA", # eradicate
|
|
88
|
+
"FAST", # FastAPI
|
|
89
|
+
"PERF", # Perflint
|
|
90
|
+
"PGH", # pygrep-hooks
|
|
91
|
+
"FURB", # refurb
|
|
92
|
+
"TRY", # tryceratops
|
|
93
|
+
"RUF", # Ruff-specific rules
|
|
94
|
+
]
|
|
95
|
+
ignore = [
|
|
96
|
+
"E402", # module-import-not-at-top-of-file # nonebot2 require() violates this
|
|
97
|
+
"B008", # function-call-in-default-argument # nonebot2 Depends() without Annotated violates this
|
|
98
|
+
"UP037", # quoted-annotation
|
|
99
|
+
# "RUF001", # ambiguous-unicode-character-string
|
|
100
|
+
# "RUF002", # ambiguous-unicode-character-docstring
|
|
101
|
+
# "RUF003", # ambiguous-unicode-character-comment
|
|
102
|
+
# "ANN201", # missing-return-type-undocumented-public-function
|
|
103
|
+
"ANN202", # missing-return-type-private-function
|
|
104
|
+
"ANN401", # any-type
|
|
105
|
+
"COM812", # missing-trailing-comma
|
|
106
|
+
"PLC0415", # import-outside-top-level
|
|
107
|
+
]
|
|
108
|
+
allowed-confusables = [",", "。", "“", "”", ":", ";", "?", "!", "【", "】", "《", "》", "…", "—", "(", ")", "、"]
|
|
109
|
+
|
|
110
|
+
[tool.ruff.lint.pyupgrade]
|
|
111
|
+
keep-runtime-typing = true
|
|
112
|
+
|
|
113
|
+
[tool.pyright]
|
|
114
|
+
# For Pylance/Pyright configurations, see https://microsoft.github.io/pyright/#/configuration.
|
|
115
|
+
pythonVersion = "3.11"
|
|
116
|
+
pythonPlatform = "All"
|
|
117
|
+
typeCheckingMode = "standard"
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from decimal import Decimal, InvalidOperation
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from nonebot import get_driver, load_plugins, logger, on_command
|
|
6
|
+
from nonebot.adapters.milky import MessageSegment
|
|
7
|
+
from nonebot.adapters.milky.event import MessageEvent
|
|
8
|
+
from nonebot.plugin import PluginMetadata
|
|
9
|
+
from nonebot_plugin_alconna import Alconna, Args, CommandMeta, on_alconna
|
|
10
|
+
|
|
11
|
+
from .algorithm import (
|
|
12
|
+
BetConfigError,
|
|
13
|
+
CascadeResult,
|
|
14
|
+
calculate_allowed_win_probability,
|
|
15
|
+
format_bet_summary,
|
|
16
|
+
parse_bet_config,
|
|
17
|
+
resolve_controlled_spin,
|
|
18
|
+
)
|
|
19
|
+
from .constants import REGISTRATION_REWARD
|
|
20
|
+
from .database import (
|
|
21
|
+
apply_spin_result,
|
|
22
|
+
get_bet_setting,
|
|
23
|
+
get_user,
|
|
24
|
+
initialize_database,
|
|
25
|
+
register_user,
|
|
26
|
+
transfer_user_coins,
|
|
27
|
+
upsert_bet_setting,
|
|
28
|
+
)
|
|
29
|
+
from .utils import (
|
|
30
|
+
GeneratedSpinImage,
|
|
31
|
+
SpinMessageContext,
|
|
32
|
+
build_forward_message,
|
|
33
|
+
draw_spin_result_image,
|
|
34
|
+
format_decimal,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
__plugin_meta__ = PluginMetadata(
|
|
38
|
+
name="slot_machine",
|
|
39
|
+
description="一个老虎机游戏插件",
|
|
40
|
+
usage=(
|
|
41
|
+
"注册老虎机/注册:领取初始金币\n"
|
|
42
|
+
"设置投注 <投注大小> <投注倍数>:保存投注设置\n"
|
|
43
|
+
"查询老虎机/查询:查看账号和投注信息\n"
|
|
44
|
+
"开始旋转:开始抽奖"
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
load_plugins(str(Path(__file__).parent / "plugins"))
|
|
49
|
+
|
|
50
|
+
slot_register = on_command(
|
|
51
|
+
"注册老虎机",
|
|
52
|
+
aliases={"注册"},
|
|
53
|
+
block=True,
|
|
54
|
+
)
|
|
55
|
+
slot_setting = on_alconna(
|
|
56
|
+
Alconna(
|
|
57
|
+
"设置投注",
|
|
58
|
+
Args["bet_size", str]["multiplier", int],
|
|
59
|
+
meta=CommandMeta(description="设置老虎机投注大小和投注倍数"),
|
|
60
|
+
),
|
|
61
|
+
aliases={"setslot"},
|
|
62
|
+
block=True,
|
|
63
|
+
)
|
|
64
|
+
slot_transfer = on_alconna(
|
|
65
|
+
Alconna(
|
|
66
|
+
"转账",
|
|
67
|
+
Args["receiver_account", str]["amount", str],
|
|
68
|
+
meta=CommandMeta(description="向其他老虎机账号转账金币"),
|
|
69
|
+
),
|
|
70
|
+
block=True,
|
|
71
|
+
)
|
|
72
|
+
slot_query = on_command(
|
|
73
|
+
"查询老虎机",
|
|
74
|
+
aliases={"查询"},
|
|
75
|
+
block=True,
|
|
76
|
+
)
|
|
77
|
+
slot_machine = on_command(
|
|
78
|
+
"开始旋转",
|
|
79
|
+
block=True,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
@get_driver().on_startup
|
|
83
|
+
async def startup_slot_machine() -> None:
|
|
84
|
+
await initialize_database()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def send_spin_result(event: MessageEvent, context: SpinMessageContext) -> None:
|
|
88
|
+
images: list[GeneratedSpinImage] = []
|
|
89
|
+
try:
|
|
90
|
+
images = list(
|
|
91
|
+
await asyncio.gather(
|
|
92
|
+
*(
|
|
93
|
+
draw_spin_result_image(
|
|
94
|
+
context=context,
|
|
95
|
+
cascade=cascade,
|
|
96
|
+
cascade_index=index,
|
|
97
|
+
)
|
|
98
|
+
for index, cascade in enumerate(context.all_cascades, start=1)
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if len(images) <= 3: # noqa: PLR2004
|
|
104
|
+
for image in images[:-1]:
|
|
105
|
+
await slot_machine.send(MessageSegment.image(raw=image.data))
|
|
106
|
+
await slot_machine.finish(MessageSegment.image(raw=images[-1].data))
|
|
107
|
+
|
|
108
|
+
await slot_machine.finish(build_forward_message(event, context, images))
|
|
109
|
+
finally:
|
|
110
|
+
for image in images:
|
|
111
|
+
image.path.unlink(missing_ok=True)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async def send_miss_result(context: SpinMessageContext, board: list[list[str]]) -> None:
|
|
115
|
+
image = await draw_spin_result_image(
|
|
116
|
+
context,
|
|
117
|
+
CascadeResult(
|
|
118
|
+
board=board,
|
|
119
|
+
highlighted_positions=frozenset(),
|
|
120
|
+
bonus_multiplier=1,
|
|
121
|
+
payout=Decimal(0),
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
try:
|
|
125
|
+
await slot_machine.finish(MessageSegment.image(raw=image.data))
|
|
126
|
+
finally:
|
|
127
|
+
image.path.unlink(missing_ok=True)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@slot_register.handle()
|
|
131
|
+
async def handle_slot_register(event: MessageEvent) -> None:
|
|
132
|
+
account = event.get_user_id()
|
|
133
|
+
registered = await register_user(account)
|
|
134
|
+
user = await get_user(account)
|
|
135
|
+
|
|
136
|
+
if user is None:
|
|
137
|
+
await slot_register.finish("注册失败,请稍后再试。")
|
|
138
|
+
|
|
139
|
+
if not registered:
|
|
140
|
+
await slot_register.finish(
|
|
141
|
+
"你已经注册过了。\n"
|
|
142
|
+
f"账号:{account}\n"
|
|
143
|
+
f"当前金币:{format_decimal(user.coins)}\n"
|
|
144
|
+
f"抽奖次数:{user.spin_count}"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
await slot_register.finish(
|
|
148
|
+
"注册成功。\n"
|
|
149
|
+
f"账号:{account}\n"
|
|
150
|
+
f"赠送金币:{format_decimal(REGISTRATION_REWARD)}\n"
|
|
151
|
+
f"当前金币:{format_decimal(user.coins)}"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@slot_setting.handle()
|
|
156
|
+
async def handle_slot_setting(
|
|
157
|
+
event: MessageEvent,
|
|
158
|
+
bet_size: str,
|
|
159
|
+
multiplier: int,
|
|
160
|
+
) -> None:
|
|
161
|
+
account = event.get_user_id()
|
|
162
|
+
user = await get_user(account)
|
|
163
|
+
|
|
164
|
+
if user is None:
|
|
165
|
+
await slot_setting.finish("你还没有注册。\n请先发送:注册老虎机")
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
bet_config = parse_bet_config(f"{bet_size} {multiplier}")
|
|
169
|
+
except BetConfigError:
|
|
170
|
+
await slot_setting.finish(
|
|
171
|
+
"请输入:设置投注 <投注大小> <投注倍数>,例如:设置投注 0.2 5\n"
|
|
172
|
+
"投注大小只能是 0.02、0.2 或 1,投注倍数只能是 1 到 10 的整数。"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
await upsert_bet_setting(account, bet_config)
|
|
176
|
+
await slot_setting.finish(f"已保存你的投注设置。\n{format_bet_summary(bet_config)}")
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@slot_transfer.handle()
|
|
180
|
+
async def handle_slot_transfer(
|
|
181
|
+
event: MessageEvent,
|
|
182
|
+
receiver_account: str,
|
|
183
|
+
amount: str,
|
|
184
|
+
) -> None:
|
|
185
|
+
sender_account = event.get_user_id()
|
|
186
|
+
sender = await get_user(sender_account)
|
|
187
|
+
if sender is None:
|
|
188
|
+
await slot_transfer.finish("你还没有注册。\n请先发送:注册老虎机")
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
transfer_amount = Decimal(amount)
|
|
192
|
+
except InvalidOperation:
|
|
193
|
+
await slot_transfer.finish("请输入正确金额,例如:转账 123456 10")
|
|
194
|
+
|
|
195
|
+
if transfer_amount <= 0:
|
|
196
|
+
await slot_transfer.finish("转账金额必须大于 0。")
|
|
197
|
+
|
|
198
|
+
receiver = await get_user(receiver_account)
|
|
199
|
+
if receiver is None:
|
|
200
|
+
await slot_transfer.finish("对方还没有注册老虎机账号。")
|
|
201
|
+
|
|
202
|
+
if sender_account == receiver_account:
|
|
203
|
+
await slot_transfer.finish("不能给自己转账。")
|
|
204
|
+
|
|
205
|
+
if sender.coins < transfer_amount:
|
|
206
|
+
await slot_transfer.finish(
|
|
207
|
+
"金币不足,无法转账。\n"
|
|
208
|
+
f"当前金币:{format_decimal(sender.coins)}\n"
|
|
209
|
+
f"转账金额:{format_decimal(transfer_amount)}"
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
updated_sender, updated_receiver = await transfer_user_coins(
|
|
213
|
+
sender_account,
|
|
214
|
+
receiver_account,
|
|
215
|
+
transfer_amount,
|
|
216
|
+
)
|
|
217
|
+
await slot_transfer.finish(
|
|
218
|
+
"转账成功。\n"
|
|
219
|
+
f"收款账号:{receiver_account}\n"
|
|
220
|
+
f"转账金额:{format_decimal(transfer_amount)} 金币\n"
|
|
221
|
+
f"你的剩余金币:{format_decimal(updated_sender.coins)}\n"
|
|
222
|
+
f"对方当前金币:{format_decimal(updated_receiver.coins)}"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@slot_query.handle()
|
|
227
|
+
async def handle_slot_query(event: MessageEvent) -> None:
|
|
228
|
+
account = event.get_user_id()
|
|
229
|
+
user = await get_user(account)
|
|
230
|
+
|
|
231
|
+
if user is None:
|
|
232
|
+
await slot_query.finish("你还没有注册。\n请先发送:注册老虎机")
|
|
233
|
+
|
|
234
|
+
bet_config = await get_bet_setting(account)
|
|
235
|
+
bet_text = (
|
|
236
|
+
format_bet_summary(bet_config)
|
|
237
|
+
if bet_config is not None
|
|
238
|
+
else "尚未设置投注"
|
|
239
|
+
)
|
|
240
|
+
await slot_query.finish(
|
|
241
|
+
"老虎机账号信息\n"
|
|
242
|
+
f"账号:{account}\n"
|
|
243
|
+
f"当前金币:{format_decimal(user.coins)}\n"
|
|
244
|
+
f"抽奖次数:{user.spin_count}\n"
|
|
245
|
+
f"中奖次数:{user.win_count}\n"
|
|
246
|
+
f"累计获得:{format_decimal(user.total_payout)} 金币\n\n"
|
|
247
|
+
f"当前投注:\n{bet_text}"
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@slot_machine.handle()
|
|
252
|
+
async def handle_slot_machine(event: MessageEvent) -> None:
|
|
253
|
+
account = event.get_user_id()
|
|
254
|
+
user = await get_user(account)
|
|
255
|
+
|
|
256
|
+
if user is None:
|
|
257
|
+
await slot_machine.finish("你还没有注册。\n请先发送:注册老虎机")
|
|
258
|
+
|
|
259
|
+
bet_config = await get_bet_setting(account)
|
|
260
|
+
if bet_config is None:
|
|
261
|
+
await slot_machine.finish(
|
|
262
|
+
"你还没有设置投注。\n"
|
|
263
|
+
"请先发送:设置投注 <投注大小> <投注倍数>\n"
|
|
264
|
+
"例如:设置投注 0.2 5"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
if user.coins < bet_config.total_bet:
|
|
268
|
+
await slot_machine.finish(
|
|
269
|
+
"金币不足,无法抽奖。\n"
|
|
270
|
+
f"当前金币:{format_decimal(user.coins)}\n"
|
|
271
|
+
f"本次需要:{format_decimal(bet_config.total_bet)}"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
allowed_probability = calculate_allowed_win_probability(
|
|
275
|
+
user.coins,
|
|
276
|
+
user.win_count,
|
|
277
|
+
user.total_payout,
|
|
278
|
+
)
|
|
279
|
+
logger.info(
|
|
280
|
+
f"老虎机抽奖概率 | 账号:{account} | "
|
|
281
|
+
f"金币:{format_decimal(user.coins)} | "
|
|
282
|
+
f"中奖次数:{user.win_count} | "
|
|
283
|
+
f"累计获得:{format_decimal(user.total_payout)} | "
|
|
284
|
+
f"本次概率:{allowed_probability:.2%}"
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
spin_result = resolve_controlled_spin(
|
|
288
|
+
bet_config,
|
|
289
|
+
user.coins,
|
|
290
|
+
user.win_count,
|
|
291
|
+
user.total_payout,
|
|
292
|
+
)
|
|
293
|
+
updated_user = await apply_spin_result(
|
|
294
|
+
account, bet_config.total_bet, spin_result.total_payout
|
|
295
|
+
)
|
|
296
|
+
context = SpinMessageContext(
|
|
297
|
+
account=account,
|
|
298
|
+
total_bet=format_decimal(bet_config.total_bet),
|
|
299
|
+
total_payout=format_decimal(spin_result.total_payout),
|
|
300
|
+
remaining_coins=format_decimal(updated_user.coins),
|
|
301
|
+
all_cascades=list(spin_result.cascades),
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
if not spin_result.cascades:
|
|
305
|
+
await send_miss_result(context, spin_result.final_board)
|
|
306
|
+
|
|
307
|
+
await send_spin_result(event, context)
|