From 59bb2068df60fbdbc3559cd7025101739963f590 Mon Sep 17 00:00:00 2001 From: Art_Sakura <1754798088@qq.com> Date: Thu, 20 Mar 2025 18:06:38 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E6=96=B0=E5=A2=9E=E6=94=B6?= =?UTF-8?q?=E8=8E=B7=E9=80=BB=E8=BE=91=20=E2=9C=A8=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=92=AD=E7=A7=8D=E9=80=BB=E8=BE=91=20=E2=9C=A8=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E7=BB=98=E5=88=B6=E4=BD=9C=E7=89=A9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __init__.py | 3 +- command.py | 112 ++++--- database.py | 130 +++++--- farm/farm.py | 333 ++++++++++++++++---- farm/shop.py | 27 +- resource/background/{gains.png => ripe.png} | Bin resource/plant/胡萝卜/4.png | Bin 16099 -> 17917 bytes 7 files changed, 454 insertions(+), 151 deletions(-) rename resource/background/{gains.png => ripe.png} (100%) diff --git a/__init__.py b/__init__.py index 2025009..0107e5a 100644 --- a/__init__.py +++ b/__init__.py @@ -36,8 +36,7 @@ async def start(): # 初始化读取Json await g_pJsonManager.init() - aaa = await g_pFarmManager.sowing("1754798088", "胡萝卜", 1) - logger.info(aaa) + # await g_pFarmManager.harvest("1754798088") # 析构函数 @driver.on_shutdown diff --git a/command.py b/command.py index 3f74d7b..650f4e1 100644 --- a/command.py +++ b/command.py @@ -35,14 +35,12 @@ diuse_farm = on_alconna( "我的农场", Option("--all", action=store_true), Subcommand("my-point", help_text="我的农场币"), - Subcommand("plant-shop", help_text="种子商店"), - Subcommand("buy-plant", Args["name?", str]["num?", int], help_text="购买种子"), - Subcommand("my-plant", help_text="我的种子"), - Subcommand("my-props", help_text="我的农场道具"), + Subcommand("seed-shop", help_text="种子商店"), + Subcommand("buy-seed", Args["name?", str]["num?", int], help_text="购买种子"), + Subcommand("my-seed", help_text="我的种子"), Subcommand("sowing", Args["name?", str]["num?", int], help_text="播种"), - Subcommand("buy", Args["name?", str]["num?", int], help_text="购买道具"), - Subcommand("use", Args["name?", str]["num?", int], help_text="使用道具"), - Subcommand("gold-list", Args["num?", int], help_text="金币排行"), + Subcommand("harvest", help_text="收获"), + Subcommand("my-plant", help_text="我的作物") ), priority=5, rule=to_me(), @@ -82,11 +80,11 @@ async def _(session: Uninfo): diuse_farm.shortcut( "种子商店", command="我的农场", - arguments=["plant-shop"], + arguments=["seed-shop"], prefix=True, ) -@diuse_farm.assign("plant-shop") +@diuse_farm.assign("seed-shop") async def _(session: Uninfo): uid = str(session.user.id) point = await g_pSqlManager.getUserPointByUid(uid) @@ -95,17 +93,17 @@ async def _(session: Uninfo): await MessageUtils.build_message("尚未开通农场").send() return None - image = await g_pShopManager.getPlantShopImage() + image = await g_pShopManager.getSeedShopImage() await MessageUtils.build_message(image).send() diuse_farm.shortcut( "购买种子(?P.*?)", command="我的农场", - arguments=["buy-plant", "{name}"], + arguments=["buy-seed", "{name}"], prefix=True, ) -@diuse_farm.assign("buy-plant") +@diuse_farm.assign("buy-seed") async def _(session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", 1),): if not name.available: await MessageUtils.build_message( @@ -119,12 +117,75 @@ async def _(session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("n await MessageUtils.build_message("尚未开通农场").send() return None - result = await g_pShopManager.buyPlant(uid, name.result, num.result) + result = await g_pShopManager.buySeed(uid, name.result, num.result) await MessageUtils.build_message(result).send(reply_to=True) diuse_farm.shortcut( "我的种子", command="我的农场", + arguments=["my-seed"], + prefix=True, +) + +@diuse_farm.assign("my-seed") +async def _(session: Uninfo): + uid = str(session.user.id) + point = await g_pSqlManager.getUserPointByUid(uid) + + if point < 0: + await MessageUtils.build_message("尚未开通农场").send() + return None + + result = await g_pFarmManager.getUserSeedByUid(uid) + await MessageUtils.build_message(result).send(reply_to=True) + +diuse_farm.shortcut( + "播种(?P.*?)", + command="我的农场", + arguments=["sowing", "{name}"], + prefix=True, +) + +@diuse_farm.assign("sowing") +async def _(session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", 1),): + if not name.available: + await MessageUtils.build_message( + "请在指令后跟需要播种的种子名称" + ).finish(reply_to=True) + + uid = str(session.user.id) + point = await g_pSqlManager.getUserPointByUid(uid) + + if point < 0: + await MessageUtils.build_message("尚未开通农场").send() + return None + + result = await g_pFarmManager.sowing(uid, name.result, num.result) + await MessageUtils.build_message(result).send(reply_to=True) + + +diuse_farm.shortcut( + "收获", + command="我的农场", + arguments=["harvest"], + prefix=True, +) + +@diuse_farm.assign("harvest") +async def _(session: Uninfo): + uid = str(session.user.id) + point = await g_pSqlManager.getUserPointByUid(uid) + + if point < 0: + await MessageUtils.build_message("尚未开通农场").send() + return None + + result = await g_pFarmManager.harvest(uid) + await MessageUtils.build_message(result).send(reply_to=True) + +diuse_farm.shortcut( + "我的作物", + command="我的农场", arguments=["my-plant"], prefix=True, ) @@ -140,28 +201,3 @@ async def _(session: Uninfo): result = await g_pFarmManager.getUserPlantByUid(uid) await MessageUtils.build_message(result).send(reply_to=True) - -diuse_farm.shortcut( - "播种(?P.*?)", - command="我的农场", - arguments=["sowing", "{name}"], - prefix=True, -) - -async def _(session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", 1),): - if not name.available: - await MessageUtils.build_message( - "请在指令后跟需要播种的种子名称" - ).finish(reply_to=True) - - uid = str(session.user.id) - point = await g_pSqlManager.getUserPointByUid(uid) - - if point < 0: - await MessageUtils.build_message("尚未开通农场").send() - return None - - return None - - # result = await g_pShopManager.buyPlant(uid, name.result, num.result) - # await MessageUtils.build_message(result).send(reply_to=True) diff --git a/database.py b/database.py index ab3a0dc..0c85944 100644 --- a/database.py +++ b/database.py @@ -1,6 +1,7 @@ import os from datetime import datetime, timedelta from io import StringIO +from math import e from typing import Any, List, Optional import aiosqlite @@ -55,7 +56,8 @@ class CSqlManager: CREATE TABLE storehouse ( uid INTEGER PRIMARY KEY AUTOINCREMENT, item TEXT DEFAULT '', - plant TEXT DEFAULT '' + plant TEXT DEFAULT '', + seed TEXT DEFAULT '' ); """ @@ -106,31 +108,16 @@ class CSqlManager: return False @classmethod - async def executeDBCursor(cls, command: str) -> Optional[List[Any]]: - """执行自定义SQL并返回查询结果 + async def initUserInfoByUid(cls, uid: str, name: str = "", exp: int = 0, point: int = 100): + """初始化用户信息 Args: - command (str): SQL查询语句 - - Returns: - Optional[List[Any]]: 查询结果列表(成功时),None(失败时) + uid (str): 用户Uid + name (str): 农场名称 + exp (int): 农场经验 + point (int): 农场币 """ - if len(command) <= 0: - logger.warning("空数据库命令") - return None - try: - async with cls.m_pDB.execute(command) as cursor: - # 将Row对象转换为字典列表 - results = [dict(row) for row in await cursor.fetchall()] - return results - except Exception as e: - logger.error(f"数据库执行失败: {e}") - return None - - @classmethod - async def initUserInfoByUid(cls, - uid: str, name: str = "", exp: int = 0, point: int = 100): #用户信息 userInfo = f""" INSERT INTO user (uid, name, exp, point) VALUES ({uid}, '{name}', {str(exp)}, {str(point)}) @@ -141,6 +128,7 @@ class CSqlManager: INSERT INTO storehouse (uid) VALUES ({uid}); """ + #用户土地 userSoilInfo = f""" INSERT INTO soil (uid) VALUES ({uid}); """ @@ -304,48 +292,62 @@ class CSqlManager: return soilNumber @classmethod - async def getUserSoilStatusBySoilID(cls, uid: str, soil: str) -> bool: + async def getUserSoilStatusBySoilID(cls, uid: str, soil: str) -> tuple[bool, str]: """根据土地块获取用户土地状态 Args: uid (str): 用户Uid - soil (str): 土地块 + soil (str): 土地id Returns: - bool: 是否可以播种 + tuple[bool, str]: [是否可以播种,土地信息] """ if len(uid) <= 0: - return False + return False, "" async with cls.m_pDB.execute(f"SELECT {soil} FROM soil WHERE uid = '{uid}'") as cursor: async for row in cursor: - if row[0] == None: - return True + if row[0] == None or len(row[0]) <= 0: + return True, "" + else: + return False, row[0] - return False + return False, "" @classmethod - async def updateUserSoilStatusBySowing(cls, uid: str, soil: str, plant: str) -> bool: + async def updateUserSoilStatusByPlantName(cls, uid: str, soil: str, plant: str = "", status: int = 0) -> bool: + """根据种子名称使用户播种 + + Args: + uid (str): 用户Uid + soil (str): 土地id + plant (str): 种子名称 + + Returns: + bool: 是否更新成功 + """ if len(uid) <= 0: return False - #获取种子信息 这里能崩我吃 - plantInfo = g_pJsonManager.m_pPlant['plant'][plant] # type: ignore + if len(plant) <= 0: + s = f",,,{status}" + else: + #获取种子信息 这里能崩我吃 + plantInfo = g_pJsonManager.m_pPlant['plant'][plant] # type: ignore + currentTime = datetime.now() + newTime = currentTime + timedelta(minutes=int(plantInfo['time'])) - currentTime = datetime.now() - newTime = currentTime + timedelta(minutes=int(plantInfo['time'])) + #种子名称,种下时间,预计成熟时间,地状态:0:无 1:长草 2:生虫 3:缺水 4:枯萎状态 + s = f"{plant},{int(currentTime.timestamp())},{int(newTime.timestamp())},{status}" - #种子名称,当前阶段,预计长大/预计下个阶段,地状态:0:无 1:长草 2:生虫 3:缺水 4:枯萎状态 - status = f"{plant},1,{int(newTime.timestamp())},0" - - sql = f"UPDATE soil SET {soil} = '{status}' WHERE uid = '{uid}'" + sql = f"UPDATE soil SET {soil} = '{s}' WHERE uid = '{uid}'" return await cls.executeDB(sql) @classmethod - async def getUserPlantByUid(cls, uid: str) -> str: + async def getUserSeedByUid(cls, uid: str) -> str: """获取用户仓库种子信息 Args: @@ -355,6 +357,49 @@ class CSqlManager: str: 仓库种子信息 """ + if len(uid) <= 0: + return "" + + try: + async with cls.m_pDB.execute(f"SELECT seed FROM storehouse WHERE uid = '{uid}'") as cursor: + async for row in cursor: + return row[0] + + return "" + except Exception as e: + logger.warning(f"getUserSeedByUid查询失败: {e}") + return "" + + @classmethod + async def updateUserSeedByUid(cls, uid: str, seed: str) -> bool: + """更新用户种子仓库 + + Args: + uid (str): 用户Uid + seed (str): 种子名称 + + Returns: + bool: + """ + + if len(uid) <= 0: + return False + + sql = f"UPDATE storehouse SET seed = '{seed}' WHERE uid = '{uid}'" + + return await cls.executeDB(sql) + + @classmethod + async def getUserPlantByUid(cls, uid: str) -> str: + """获取用户仓库作物信息 + + Args: + info (list[dict]): 用户信息 + + Returns: + str: 仓库作物信息 + """ + if len(uid) <= 0: return "" @@ -370,13 +415,14 @@ class CSqlManager: @classmethod async def updateUserPlantByUid(cls, uid: str, plant: str) -> bool: - """添加用户仓库种子信息 + """更新用户作物仓库 Args: - info (list[dict]): 种子信息 + uid (str): 用户Uid + plant (str): 作物名称 Returns: - bool: 是否添加成功 + bool: """ if len(uid) <= 0: diff --git a/farm/farm.py b/farm/farm.py index ca01ac3..6602815 100644 --- a/farm/farm.py +++ b/farm/farm.py @@ -1,4 +1,8 @@ -from numpy import arange +import asyncio +import logging +from datetime import datetime +from io import StringIO +from typing import Dict, List, Tuple from zhenxun.services.log import logger from zhenxun.utils._build_image import BuildImage @@ -22,15 +26,15 @@ class CFarmManager: """ soilNumber = await g_pSqlManager.getUserLevelByUid(uid) - img = BuildImage(background=g_sResourcePath / "background/background.jpg") + img = BuildImage(background = g_sResourcePath / "background/background.jpg") soilSize = g_pJsonManager.m_pSoil['size'] # type: ignore #TODO 缺少判断用户土地资源状况 - soil = BuildImage(background=g_sResourcePath / "soil/普通土地.png") + soil = BuildImage(background = g_sResourcePath / "soil/普通土地.png") await soil.resize(0, soilSize[0], soilSize[1]) - grass = BuildImage(background=g_sResourcePath / "soil/草土地.png") + grass = BuildImage(background = g_sResourcePath / "soil/草土地.png") await grass.resize(0, soilSize[0], soilSize[1]) soilPos = g_pJsonManager.m_pSoil['soil'] # type: ignore @@ -38,7 +42,9 @@ class CFarmManager: x = 0 y = 0 - isFirst = True + isFirstExpansion = True #首次添加扩建图片 + isFirstRipe = True + plant = None for index, level in enumerate(soilUnlock): x = soilPos[str(index + 1)]['x'] y = soilPos[str(index + 1)]['y'] @@ -47,25 +53,88 @@ class CFarmManager: if soilNumber >= int(level): await img.paste(soil, (x, y)) - #TODO 缺少判断土地上是否有农作物 - plant = BuildImage(background=g_sResourcePath / "plant/basic/0.png") - await plant.resize(0, 35, 58) - await img.paste(plant, (x + 100, y + 50)) + isPlant, plant, isRipe= await cls.drawSoilPlant(uid, f"soil{str(index + 1)}") + + if isPlant: + await img.paste(plant, (x + soilSize[0] // 2 - plant.width // 2, + y + soilSize[1] // 2 - plant.height // 2)) + + #首次添加可收获图片 + if isRipe and isFirstRipe: + ripe = BuildImage(background = g_sResourcePath / "background/ripe.png") + + await img.paste(ripe, (x + soilSize[0] // 2 - ripe.width // 2, + y - ripe.height // 2)) + + isFirstRipe = False else: await img.paste(grass, (x, y)) - if isFirst: - isFirst = False + if isFirstExpansion: + isFirstExpansion = False #首次添加扩建图片 - expansion = BuildImage(background=g_sResourcePath / "background/expansion.png") + expansion = BuildImage(background = g_sResourcePath / "background/expansion.png") await expansion.resize(0, 69, 69) - await img.paste(expansion, (x + 85, y + 20)) + await img.paste(expansion, (x + soilSize[0] // 2 - expansion.width // 2, + y + soilSize[1] // 2 - expansion.height)) + await img.resize(0.6) return img.pic2bytes() @classmethod - async def getUserPlantByUid(cls, uid: str) -> bytes: + async def drawSoilPlant(cls, uid: str, soilid: str) -> tuple[bool, BuildImage, bool]: + """绘制植物资源 + + Args: + uid (str): 用户Uid + soilid (str): 土地id + + Returns: + tuple[bool, BuildImage]: [绘制是否成功,资源图片, 是否成熟] + """ + + plant = None + soilStatus, soilInfo = await g_pSqlManager.getUserSoilStatusBySoilID(uid, soilid) + + if soilStatus == True: + return False, None, False + else: + soilInfo = soilInfo.split(',') + plantInfo = g_pJsonManager.m_pPlant['plant'][soilInfo[0]] # type: ignore + + if int(soilInfo[3]) == 4: + plant = BuildImage(background = g_sResourcePath / f"plant/basic/9.png") + + return True, plant, False + + currentTime = datetime.now() + matureTime = datetime.fromtimestamp(int(soilInfo[2])) + + if currentTime >= matureTime: + phase = int(plantInfo['phase']) + plant = BuildImage(background = g_sResourcePath / f"plant/{soilInfo[0]}/{phase - 1}.png") + + return True, plant, True + else: + plantedTime = datetime.fromtimestamp(int(soilInfo[1])) + + elapsedTime = currentTime - plantedTime + elapsedMinutes = elapsedTime.total_seconds() / 60 + + currentStage = int(elapsedMinutes / (plantInfo['time'] / (plantInfo['phase'] - 1))) + + #TODO 缺少判断部分种子是否是通用0阶段图片 + if currentStage <= 0: + plant = BuildImage(background = g_sResourcePath / f"plant/basic/0.png") + await plant.resize(0, 35, 58) + else: + plant = BuildImage(background = g_sResourcePath / f"plant/{soilInfo[0]}/{currentStage}.png") + + return True, plant, False + + @classmethod + async def getUserSeedByUid(cls, uid: str) -> bytes: """获取用户种子仓库 Args: @@ -88,12 +157,194 @@ class CFarmManager: "是否可以上架交易行" ] + seed = await g_pSqlManager.getUserSeedByUid(uid) + + if seed == None: + result = await ImageTemplate.table_page( + "种子仓库", + "播种示例:@小真寻 播种 大白菜 [数量]", + column_name, + data_list, + ) + + return result.pic2bytes() + + sell = "" + for item in seed.split(','): + if '|' in item: + seedName, count = item.split('|', 1) # 分割一次,避免多竖线问题 + try: + plantInfo = g_pJsonManager.m_pPlant['plant'][seedName] # type: ignore + + icon = "" + icon_path = g_sResourcePath / f"plant/{seedName}/icon.png" + if icon_path.exists(): + icon = (icon_path, 33, 33) + + if plantInfo['again'] == True: + sell = "可以" + else: + sell = "不可以" + + data_list.append( + [ + icon, + seedName, + count, + plantInfo['experience'], + plantInfo['harvest'], + plantInfo['time'], + plantInfo['crop'], + plantInfo['again'], + sell + ] + ) + + except Exception as e: + continue + + result = await ImageTemplate.table_page( + "种子仓库", + "播种示例:@小真寻 播种 大白菜 [数量]", + column_name, + data_list, + ) + + return result.pic2bytes() + + @classmethod + async def sowing(cls, uid: str, name: str, num: int = -1) -> str: + """播种 + + Args: + uid (str): 用户Uid + name (str): 播种种子名称 + num (int, optional): 播种数量 + + Returns: + str: + """ + plant = await g_pSqlManager.getUserSeedByUid(uid) + + if plant == None: + return "你的种子仓库是空的,快去买点吧!" + + plantDict = {} + for item in plant.split(','): + if '|' in item: + seed_name, count = item.split('|', 1) + plantDict[seed_name] = int(count) + + isAll = False + if num == -1: + isAll = True + + soilNumber = await g_pSqlManager.getUserSoilByUid(uid) + + for i in range(1, soilNumber + 1): + if plantDict[name] > 0: + if isAll or num > 0: + soilName = f"soil{i}" + success, message = await g_pSqlManager.getUserSoilStatusBySoilID(uid, soilName) + if success: + # 更新种子数量 + num -= 1 + plantDict[name] -= 1 + if plantDict[name] == 0: + del plantDict[name] + + # 更新数据库 + await g_pSqlManager.updateUserSoilStatusByPlantName(uid, soilName, name) + + await g_pSqlManager.updateUserSeedByUid( + uid, + ','.join([f"{k}|{v}" for k, v in plantDict.items()]) + ) + + if num > 0: + return f"播种数量超出解锁土地数量,已将可播种土地成功播种{name}!仓库还剩下{plantDict[name]}个种子" + else: + return f"播种{name}成功!仓库还剩下{plantDict[name]}个种子" + + @classmethod + async def harvest(cls, uid: str) -> str: + """收获作物 + + Args: + uid (str): 用户Uid + + Returns: + str: 返回 + """ + + soilNumber = await g_pSqlManager.getUserLevelByUid(uid) + soilUnlock = g_pJsonManager.m_pLevel['soil'] # type: ignore + + plant = {} + + soilNames = [f"soil{i + 1}" for i, level in enumerate(soilUnlock) if soilNumber >= level] + soilStatuses = await asyncio.gather(*[ + g_pSqlManager.getUserSoilStatusBySoilID(uid, name) + for name in soilNames + ]) + + plant: Dict[str, int] = {} + harvest_records: List[str] = [] + + for (soil_name, (status, info)) in zip(soilNames, soilStatuses): + if not status: + soil_info = info.split(',') + plant_id = soil_info[0] + plant_info = g_pJsonManager.m_pPlant['plant'][plant_id] # type: ignore + + current_time = datetime.now() + mature_time = datetime.fromtimestamp(int(soil_info[2])) + + if current_time >= mature_time: + plant[plant_id] = plant.get(plant_id, 0) + plant_info['harvest'] + harvest_records.append(f"收获作物:{plant_id},数量为:{plant_info['harvest']}") + + # 批量更新数据库操作 + await g_pSqlManager.updateUserSoilStatusByPlantName(uid, soil_name, "", 4) + + if not plant: + return "可收获作物为0哦~ 不要试图拔苗助长" + else: + # 批量更新用户作物数据 + await g_pSqlManager.updateUserPlantByUid( + uid, + ','.join([f"{k}|{v}" for k, v in plant.items()]) + ) + + return "\n".join(harvest_records) + + @classmethod + async def getUserPlantByUid(cls, uid: str) -> bytes: + """获取用户作物仓库 + + Args: + uid (str): 用户Uid + + Returns: + bytes: 返回图片 + """ + + data_list = [] + column_name = [ + "-", + "作物名称", + "数量", + "单价", + "总价", + "是否可以上架交易行" + ] + plant = await g_pSqlManager.getUserPlantByUid(uid) if plant == None: result = await ImageTemplate.table_page( - "种子仓库", - "播种示例:@小真寻 播种 大白菜", + "作物仓库", + "播种示例:@小真寻 出售作物 大白菜 [数量]", column_name, data_list, ) @@ -122,11 +373,8 @@ class CFarmManager: icon, plantName, count, - plantInfo['experience'], - plantInfo['harvest'], - plantInfo['time'], - plantInfo['crop'], - plantInfo['again'], + plantInfo['price'], + count * int(plantInfo['price']), sell ] ) @@ -135,51 +383,12 @@ class CFarmManager: continue result = await ImageTemplate.table_page( - "种子商店", - "购买示例:@小真寻 购买种子 大白菜 5", + "作物仓库", + "播种示例:@小真寻 出售作物 大白菜 [数量]", column_name, data_list, ) return result.pic2bytes() - @classmethod - async def sowing(cls, uid: str, name: str, num: int = 1) -> str: - """播种 - - Args: - uid (str): 用户Uid - name (str): 播种种子名称 - num (int, optional): 播种数量 - - Returns: - str: - """ - plant = await g_pSqlManager.getUserPlantByUid(uid) - - if plant == None: - return "你的种子仓库是空的,快去买点吧!" - - for item in plant.split(','): - if '|' in item: - plantName, count = item.split('|', 1) # 分割一次,避免多竖线问题 - - #判断仓库是否有当前播种种子 - if plantName == name: - count = int(count) - - #获取用户解锁多少块地 - soilName = "" - soilNumber = await g_pSqlManager.getUserSoilByUid(uid) - #遍历地块,查看地块是否可以播种 - for i in arange(1, soilNumber + 1): - if count > 0: - soilName = f"soil{str(i)}" - #如果可以播种 - if await g_pSqlManager.getUserSoilStatusBySoilID(uid, soilName): - count -= 1 - await g_pSqlManager.updateUserSoilStatusBySowing(uid, soilName, plantName) - return f"播种{plantName}成功!" - return "播种失败" - g_pFarmManager = CFarmManager() diff --git a/farm/shop.py b/farm/shop.py index bb6b76c..ae1f751 100644 --- a/farm/shop.py +++ b/farm/shop.py @@ -9,11 +9,13 @@ from ..database import g_pSqlManager class CShopManager: @classmethod - async def getPlantShopImage(cls) -> bytes: - """by ATTomato + async def getSeedShopImage(cls) -> bytes: + """获取商店页面 + + TODO: 缺少翻页功能 Returns: - bytes: _description_ + bytes: 返回商店图片bytes """ data_list = [] @@ -68,7 +70,18 @@ class CShopManager: return result.pic2bytes() @classmethod - async def buyPlant(cls, uid: str, name: str, num: int = 1) -> str: + async def buySeed(cls, uid: str, name: str, num: int = 1) -> str: + """购买种子 + + Args: + uid (str): 用户Uid + name (str): 植物名称 + num (int, optional): 购买数量 + + Returns: + str: + """ + if num <= 0: return "请输入购买数量!" @@ -89,7 +102,7 @@ class CShopManager: if point < total: return "你的农场币不够哦~ 快速速氪金吧!" else: - p = await g_pSqlManager.getUserPlantByUid(uid) + p = await g_pSqlManager.getUserSeedByUid(uid) if not p == None: for item in p.split(','): @@ -102,10 +115,10 @@ class CShopManager: else: userPlants[name] = num - plant_list = [f"{k}|{v}" for k, v in userPlants.items()] + plantList = [f"{k}|{v}" for k, v in userPlants.items()] await g_pSqlManager.updateUserPointByUid(uid, point - total) - await g_pSqlManager.updateUserPlantByUid(uid, ','.join(plant_list)) + await g_pSqlManager.updateUserSeedByUid(uid, ','.join(plantList)) return f"成功购买{name},当前仓库数量为:{userPlants[name]},花费{total}农场币, 剩余{point - total}农场币" diff --git a/resource/background/gains.png b/resource/background/ripe.png similarity index 100% rename from resource/background/gains.png rename to resource/background/ripe.png diff --git a/resource/plant/胡萝卜/4.png b/resource/plant/胡萝卜/4.png index a96ab4048c59fee099eaadeee2cf1f9ae338eb0f..8507c1a1511bd467749ae99ba72820688aa7fce0 100644 GIT binary patch literal 17917 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 literal 16099 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