让回复 celeste 允许不用带有前缀

This commit is contained in:
2026-02-28 13:49:28 +08:00
parent f9f8ae4e67
commit 33934ef7b5
2 changed files with 64 additions and 12 deletions

View File

@ -0,0 +1,38 @@
# Celeste
爬山小游戏,移植自 Ccleste是 Celeste Classic即 PICO-8版。
使用 `wasdxc` 和数字进行操作。
## 操作说明
`wsad` 是上下左右摇杆方向,或者是方向键。`c` 是跳跃键,`x` 是冲刺键。
使用空格分隔每一个操作,每个操作持续一帧。如果后面跟着数字,则持续那么多帧。
### 例子 1
```
xc 180
```
按下 xc 一帧,然后空置 180 帧。
### 例子 2
```
d10 cd d10 xdw d20
```
向右走 10 帧,向右跳一帧,再继续按下右 10 帧,按下向右上冲刺一帧,再按下右 20 帧。
## 指令使用说明
直接说 `celeste` 会开启一个新的游戏。但是,你需要在后面跟有操作,才能够渲染 gif 图出来。
一个常见的开始操作是直接发送 `celeste xc 130`,即按下 xc 两个按键触发 PICO 版的开始游戏,然后等待 130 秒动画播放完毕。
对于一个已经存在而且时间不是非常久远的 gif 图,只要是由 bot 自己发送出来的,就可以在它的基础上继续游戏。回复这条消息,可以继续游戏。
一种很常见的技巧是回复一个已经存在的 gif 图 `celeste 1`,此时会空操作一帧并且渲染画面。你可以用这种方法查看一个 gif 图的游戏目前的状态。

View File

@ -3,7 +3,7 @@ import subprocess
import tempfile
from typing import Any
from loguru import logger
from nonebot import on_command
from nonebot import on_message
from pydantic import BaseModel
from nonebot.adapters import Event, Bot
@ -43,15 +43,11 @@ celeste_status = DataManager(CelesteStatus, DATA_PATH / "celeste-status.json")
# ↓ 这里的 Type Hinting 是为了能 fit 进去 set[str | tuple[str, ...]]
aliases: set[Any] = {"蔚蓝", "爬山", "鳌太线"}
aliases: set[Any] = {"celeste", "蔚蓝", "爬山", "鳌太线"}
ALLOW_CHARS = "wasdxc0123456789 \t\n\r"
cmd = on_command(cmd="celeste", aliases=aliases)
@cmd.handle()
async def _(msg: UniMsg, evt: Event, bot: Bot):
async def get_prev(evt: Event, bot: Bot) -> str | None:
prev = None
if isinstance(evt, OB11MessageEvent):
if evt.reply is not None:
@ -61,8 +57,30 @@ async def _(msg: UniMsg, evt: Event, bot: Bot):
if seg.type == 'reply':
msgid = seg.get('id')
prev = f"QQ:{bot.self_id}:" + str(msgid)
if prev is not None:
async with celeste_status.get_data() as data:
prev = data.records.get(prev)
return prev
actions = msg.extract_plain_text().strip().removeprefix("celeste")
async def match_celeste(evt: Event, bot: Bot, msg: UniMsg) -> bool:
prev = await get_prev(evt, bot)
text = msg.extract_plain_text().strip()
if any(text.startswith(a) for a in aliases):
return True
if prev is not None:
return True
return False
# cmd = on_command(cmd="celeste", aliases=aliases)
cmd = on_message(rule=match_celeste)
@cmd.handle()
async def _(msg: UniMsg, evt: Event, bot: Bot):
prev = await get_prev(evt, bot)
actions = msg.extract_plain_text().strip()
for alias in aliases:
actions = actions.removeprefix(alias)
actions = actions.strip()
@ -71,10 +89,6 @@ async def _(msg: UniMsg, evt: Event, bot: Bot):
if any((c not in ALLOW_CHARS) for c in actions):
return
if prev is not None:
async with celeste_status.get_data() as data:
prev = data.records.get(prev)
await ensure_artifact(arti_ccleste_wrap_linux)
await ensure_artifact(arti_ccleste_wrap_windows)