diff --git a/nonebot_plugin_marshoai/plugins/twisuki_petcat/__init__.py b/nonebot_plugin_marshoai/plugins/twisuki_petcat/__init__.py index b6573dc3..66dbd446 100644 --- a/nonebot_plugin_marshoai/plugins/twisuki_petcat/__init__.py +++ b/nonebot_plugin_marshoai/plugins/twisuki_petcat/__init__.py @@ -1,9 +1,79 @@ -from nonebot_plugin_marshoai.plugin import PluginMetadata +from nonebot_plugin_marshoai.plugin import ( + Integer, + Parameter, + PluginMetadata, + String, + on_function_call, +) -from .pc_cat import * +from . import pc_cat, pc_info, pc_shop, pc_token __marsho_meta__ = PluginMetadata( name="养猫插件", description="在Marsho这里赛博养猫", author="Twisuki", ) + + +# 交互 +@on_function_call(description="传入猫猫种类, 新建一只猫猫").params( + type=String(description='猫猫种类, 默认"猫1", 可留空') +) +async def cat_new(type: str) -> str: + """新建猫猫""" + return pc_cat.cat_new(type) + + +@on_function_call( + description="传入token(一串长20的b64字符串), 新名字, 选用技能, 进行猫猫的初始化" +).params( + token=String(description="token(一串长20的b64字符串)"), + name=String(description="新名字"), + skill=String(description="技能"), +) +async def cat_init(token: str, name: str, skill: str) -> str: + """初始化猫猫""" + return pc_cat.cat_init(token, name, skill) + + +@on_function_call(description="传入token, 查看猫猫信息").params( + token=String(description="token(一串长20的b64字符串)"), +) +async def cat_show(token: str) -> str: + """查询信息""" + return pc_cat.cat_show(token) + + +@on_function_call(description="传入token, 玩猫").params( + token=String(description="token(一串长20的b64字符串)"), +) +async def cat_play(token: str) -> str: + """玩猫""" + return pc_cat.cat_play(token) + + +@on_function_call(description="传入token, 投喂猫猫").params( + token=String(description="token(一串长20的b64字符串)"), +) +async def cat_feed(token: str) -> str: + """喂猫""" + return pc_cat.cat_feed(token) + + +# 帮助 +@on_function_call(description="帮助文档/如何创建一只猫猫").params() +async def help_cat_new() -> str: + return pc_info.help_cat_new() + + +@on_function_call(description="可选种类").params() +async def help_cat_type() -> str: + return pc_info.print_type_list() + + +@on_function_call(description="可选技能").params() +async def help_cat_skill() -> str: + return pc_info.print_skill_list() + + +# 商店 diff --git a/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_cat.py b/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_cat.py index adfaf1e9..37bb2bfb 100644 --- a/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_cat.py +++ b/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_cat.py @@ -1,33 +1,241 @@ # 主交互 - +import functools from datetime import datetime +from typing import List -from nonebot_plugin_marshoai.plugin import String, on_function_call +from nonebot.log import logger -from .pc_token import ERROR_DICT, dict_to_token, token_to_dict +from . import pc_info, pc_token +from .pc_info import SKILL_LIST, TYPE_LIST, value_output +from .pc_token import dict_to_token, token_to_dict + +"""特判标准 +1. 默认, 未初始化: name = Default0 +2. 错误: name = ERROR! +3. 死亡: skill = [False] * 8 +""" -@on_function_call(description="创建一个新的猫对象(养一只新猫)").params( - name=String(description="猫的名字") -) -async def create_cat(name: str) -> str: - cat_data = { - "name": name, - "age": ERROR_DICT["age"], - "type": ERROR_DICT["type"], - "health": ERROR_DICT["health"], - "saturation": ERROR_DICT["saturation"], - "energy": ERROR_DICT["energy"], - "skill": ERROR_DICT["skill"], - "date": (datetime(2025, 1, 1) - datetime.now()).days, - } - token = dict_to_token(cat_data) - return f"猫对象创建成功,Token: {token}" +# 私用列表 +DEFAULT_DICT = { + "name": "Default0", + "age": 0, + "type": 0, + "health": 0, + "saturation": 0, + "energy": 0, + "skill": [False] * 8, + "date": 0, +} +DEFAULT_TOKEN = "6IyszC6tjoYAAAAAAAAC" -@on_function_call(description="查询猫对象信息").params( - token=String(description="猫对象的Token(是一串类似base64的字符串)") -) -async def query_cat(token: str) -> str: - cat_data = token_to_dict(token) - return f"猫的名字: {cat_data['name']}, 年龄: {cat_data['age']}, 种类: {cat_data['type']}, 生命值: {cat_data['health']}, 饱食度: {cat_data['saturation']}, 活力值: {cat_data['energy']}, 技能: {cat_data['skill']}, 日期: {cat_data['date']}" +# 交互前数据更新 +def cat_update(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + if args: + token = args[0] + + data = token_to_dict(token) + + # 检查 + if data["name"] == "Default0": + return "猫猫尚未初始化, 请初始化猫猫" + + if data["name"] == "ERROR!": + return ( + "token出错" + f'token应为Base64字符串, 当前token : "{token}"' + f"当前token长度应为20, 当前长度 : {len(token)}" + ) + + if data["skill"] == [False] * 8: + return ( + "很不幸, 猫猫已死亡" + f'名字 : {data["name"]}' + f'年龄 : {data["age"]}' + ) + + date = data["date"] + now = (datetime(2025, 1, 1) - datetime.now()).days + + # 喂食状态更新 + if now - date > 5: + data["saturation"] = max(data["saturation"] - 64, 0) + data["health"] = max(data["health"] - 32, 0) + data["energy"] = max(data["energy"] - 32, 0) + elif now - date > 2: + data["saturation"] = max(data["saturation"] - 16, 0) + data["health"] = max(data["health"] - 8, 0) + data["energy"] = max(data["energy"] - 16, 0) + + # 机能状态更新 + if data["saturation"] / 1.27 < 20: + data["health"] = max(data["health"] - 8, 0) + elif data["saturation"] / 1.27 > 80: + data["health"] = min(data["health"] + 8, 127) + + # 生长检查 + if now % 7 == 0: + # 死亡 + if data["health"] / 1.27 < 20: + data["health"] = 0 + + death = DEFAULT_DICT + death["name"] = data["name"] + data = death + + # 生长 + if data["health"] / 1.27 > 60 and data["saturation"] / 1.27 > 40: + data["age"] = min(data["age"] + 1, 15) + + token = dict_to_token(data) + new_args = (token,) + args[1:] + return func(*new_args, **kwargs) + + return wrapper + + +# 创建对象 +def cat_new(type: str = "猫1") -> str: + data = DEFAULT_DICT + + if type not in TYPE_LIST: + return ( + f'未知的"{type}"种类, 请重新选择.' + f"\n可选种类 : {pc_info.print_type_list()}" + ) + + data["type"] = TYPE_LIST.index(type) + token = dict_to_token(data) + return ( + f'猫猫已创建, 种类为 : "{type}"; \ntoken : "{token}",' + f"\n请妥善保存token, 这是猫猫的唯一标识符!" + f"\n新的猫猫还没有起名字, 请对猫猫进行初始化, 起一个长度小于等于8位的名字(仅限大小写字母+数字+特殊符号), 并选取一个技能." + f"\n技能列表 : {pc_info.print_skill_list()}" + ) + + +# 初始化对象 +def cat_init(token: str, name: str, skill: str) -> str: + data = token_to_dict(token) + if data["name"] != "Default0": + logger.info("初始化失败!") + return "该猫猫已进行交互, 无法进行初始化!" + + if skill not in SKILL_LIST: + return ( + f'未知的"{skill}"技能, 请重新选择.' + f"技能列表 : {pc_info.print_skill_list()}" + ) + + data["name"] = name + data["skill"][SKILL_LIST.index(skill)] = True + data["health"] = 127 + data["saturation"] = 127 + data["energy"] = 127 + token = dict_to_token(data) + return ( + f'初始化完成, 名字 : "{data["name"]}", 种类 : "{data["type"]}", 技能 : "{skill}"' + f'\n新token : "{token}"' + f"\n请妥善保存token, 这是猫猫的唯一标识符!" + ) + + +# 查看信息 +@cat_update +def cat_show(token: str) -> str: + result = pc_info.print_info(token) + data = token_to_dict(token) + + if data["health"] / 1.27 < 20: + return result + "\n猫猫健康状况非常差! 甚至濒临死亡!! 请立即前往医院救治!!" + + if data["health"] / 1.27 < 60: + result += "\n猫猫健康状况较差, 请投喂食物或陪猫猫玩耍" + if data["saturation"] / 1.27 < 40: + result += "\n猫猫很饿, 请投喂食物" + if data["energy"] / 1.27 < 20: + result += "\n猫猫很累, 请抱猫睡觉, 不要投喂食物或陪它玩耍" + return result + + +# 陪猫猫玩耍 +@cat_update +def cat_play(token: str) -> str: + data = token_to_dict(token) + if data["health"] / 1.27 < 20: + return "猫猫健康状况非常差! 甚至濒临死亡!! 请立即前往医院救治!!" + + if data["saturation"] / 1.27 < 40: + return "猫猫很饿, 拒接玩耍请求." + + if data["energy"] / 1.27 < 20: + return "猫猫很累, 拒接玩耍请求" + + data["health"] = min(data["health"] + 16, 127) + data["saturation"] = max(data["saturation"] - 16, 0) + data["energy"] = max(data["energy"] - 8, 0) + + token = dict_to_token(data) + return ( + f'你陪猫猫玩耍了一个小时, 猫猫的生命值上涨到了{value_output(data["health"])}' + f'\n新token : "{token}"' + "\n请妥善保存token, 这是猫猫的唯一标识符!" + ) + + +# 喂食 +@cat_update +def cat_feed(token: str) -> str: + data = token_to_dict(token) + if data["health"] / 1.27 < 20: + return "猫猫健康状况非常差! 甚至濒临死亡!! 请立即前往医院救治!!" + + if data["saturation"] / 1.27 > 80: + return "猫猫并不饿, 不需要喂食" + + if data["energy"] / 1.27 < 40: + return "猫猫很累, 请抱猫睡觉, 不要投喂食物或陪它玩耍" + + data["saturation"] = min(data["saturation"] + 32, 127) + data["date"] = (datetime(2025, 1, 1) - datetime.now()).days + + token = dict_to_token(data) + return ( + f'你投喂了2单位标准猫粮, 猫猫的饱食度提升到了{value_output(data["saturation"])}' + f'\n新token : "{token}"' + "\n请妥善保存token, 这是猫猫的唯一标识符!" + ) + + +# 睡觉 +@cat_update +def cat_sleep(token: str) -> str: + data = token_to_dict(token) + if data["health"] / 1.27 < 20: + return "猫猫健康状况非常差! 甚至濒临死亡!! 请立即前往医院救治!!" + + if data["saturation"] / 1.27 < 40: + return "猫猫很饿, 请喂食." + + if data["energy"] / 1.27 > 80: + return "猫猫很精神, 不需要睡觉" + + data["health"] = min(data["health"] + 8, 127) + data["energy"] = min(data["energy"] + 16, 0) + + token = dict_to_token(data) + return ( + f'你抱猫休息了一阵子, 猫猫的活力值提升到了{value_output(data["energy"])}' + f'\n新token : "{token}"' + "\n请妥善保存token, 这是猫猫的唯一标识符!" + ) + + +"""饼 + 1. 商店系统 + 2. 技能系统 + 3. 提高复杂性和难度 +""" diff --git a/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_info.py b/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_info.py new file mode 100644 index 00000000..69ac4a63 --- /dev/null +++ b/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_info.py @@ -0,0 +1,77 @@ +# 插件使用复杂, 这里用作输出提示信息. +# 如: 帮助, 每次操作后对猫猫状态的描述\打印特殊列表 +# 公用列表数据转到这里存储 + + +from nonebot.log import logger + +from .pc_token import dict_to_token, token_to_dict + +# 公用列表 +TYPE_LIST = ["猫1", "猫2", "猫3", "猫4", "猫5", "猫6", "猫7", "猫8"] +SKILL_LIST = ["s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8"] + + +# 提示词打印 +# 打印种类列表 +def print_type_list() -> str: + result = "" + for type in TYPE_LIST: + result += f'"{type}", ' + result = result[:-2] + return f"({result})" + + +# 打印技能列表 +def print_skill_list() -> str: + result = "" + for skill in SKILL_LIST: + result += f'"{skill}", ' + result = result[:-2] + return f"({result})" + + +# 127位值 - 100%快速转换 +def value_output(num: int) -> str: + value = int(num / 1.27) + return str(value) + + +# 打印状态 +def print_info(token: str) -> str: + data = token_to_dict(token) + return ( + "状态信息: " + f'\n\t名字 : {data["name"]}' + f'\n\t种类 : {TYPE_LIST[data["type"]]}' + f'\n\t生命值 : {value_output(data["health"])}' + f'\n\t饱食度 : {value_output(data["saturation"])}' + f"\n\t活力值 : {value_output(data['energy'])}" + f"\n\t技能 : {print_skill(token)}" + f"\n新token : {token}" + f"\ntoken已更新, 请妥善保存token, 这是猫猫的唯一标识符!" + ) + + +# 打印已有技能 +def print_skill(token: str) -> str: + result = "" + data = token_to_dict(token) + for index in range(0, len(SKILL_LIST) - 1): + if data["skill"][index]: + result += f"{SKILL_LIST[index]}, " + logger.info(data["skill"]) + return result[:-2] + + +# 帮助 +# 创建猫猫 +def help_cat_new() -> str: + return ( + "新建一只猫猫, 首先选择猫猫的种类, 获取初始化token;" + "然后用这个token, 选择名字和一个技能进行初始化;" + "初始化结束才表示猫猫正式创建成功." + "\ntoken为猫的唯一标识符, 每次交互都需要传入token" + f"\n种类可选 : {print_type_list()}" + f"\n技能可选 : {print_skill_list()}" + ) diff --git a/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_token.py b/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_token.py index 40ee1583..98346be8 100644 --- a/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_token.py +++ b/nonebot_plugin_marshoai/plugins/twisuki_petcat/pc_token.py @@ -35,10 +35,6 @@ from typing import List from nonebot.log import logger -# 公用列表 -TYPE_LIST = ["猫1", "猫2", "猫3", "猫4", "猫5", "猫6", "猫7", "猫8"] -SKILL_LIST = ["s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8"] - # 私用列表 ERROR_DICT = { "name": "ERROR!", @@ -99,6 +95,8 @@ def byte_to_bool(byte_data: bytes, length: int = 0) -> List[bool]: # 数据解码 def token_to_dict(token: str) -> dict: + logger.info(f"开始解码...\n{token}") + data = { "name": "Default0", "age": 0, @@ -119,7 +117,7 @@ def token_to_dict(token: str) -> dict: return ERROR_DICT # 拆分code - name_length = bool_to_int(code[0:3]) + name_length = bool_to_int(code[0:3]) + 1 name_code = code[3:67] age = bool_to_int(code[67:71]) type = bool_to_int(code[71:74]) @@ -130,7 +128,7 @@ def token_to_dict(token: str) -> dict: date = bool_to_int(code[103:120]) # 解析code - name = "" + name: str = "" try: for i in range(name_length): character_code = bool_to_byte(name_code[8 * i : 8 * i + 8]) @@ -148,15 +146,22 @@ def token_to_dict(token: str) -> dict: data["skill"] = skill data["date"] = date + logger.success(f"解码完成, 数据为\n{data}") return data # 数据编码 def dict_to_token(data: dict) -> str: + logger.info(f"开始编码...\n{data}") + code = [False] * 120 # 拆分data name_length = len(data["name"]) + if name_length > 8: + logger.error("name过长") + return ERROR_TOKEN + name = data["name"] age = data["age"] type = data["type"] @@ -164,10 +169,10 @@ def dict_to_token(data: dict) -> str: saturation = data["saturation"] energy = data["energy"] skill = data["skill"] - date = (datetime(2025, 1, 1) - datetime.now()).days + date = data["date"] # 填入code - code[0:3] = int_to_bool(name_length, 3) + code[0:3] = int_to_bool(name_length - 1, 3) name_code = [False] * 64 try: for i in range(name_length): @@ -190,4 +195,6 @@ def dict_to_token(data: dict) -> str: # 转换token token_byte = bool_to_byte(code) token = base64.b64encode(token_byte).decode() + + logger.success(f"编码完成, token为\n{token}") return token