From 98ae76560bff62cedf78a0479b6ad8ece505afbb Mon Sep 17 00:00:00 2001 From: Art_Sakura <1754798088@qq.com> Date: Fri, 21 Mar 2025 18:14:50 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20=E5=8A=A0=E5=85=A5=E5=BC=80?= =?UTF-8?q?=E5=9E=A6=E6=9D=A1=E4=BB=B6=20=E2=9C=A8=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=81=B7=E8=8F=9C=E5=8A=9F=E8=83=BD=20=F0=9F=90=9B=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E8=B4=AD=E4=B9=B0=E7=A7=8D=E5=AD=90=E6=97=B6=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E5=88=A4=E6=96=AD=E7=AD=89=E7=BA=A7=E7=9A=84BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __init__.py | 3 +- command.py | 40 ++++++++-- config/level.json | 86 +++++++++++++++++++- database.py | 52 ++++++------ farm/farm.py | 197 +++++++++++++++++++++++++++------------------- farm/shop.py | 82 +++++++++++++++++++ 6 files changed, 343 insertions(+), 117 deletions(-) diff --git a/__init__.py b/__init__.py index 0379d6e..23d56ec 100644 --- a/__init__.py +++ b/__init__.py @@ -27,7 +27,8 @@ __plugin_meta__ = PluginMetadata( 铲除 我的作物 出售作物 [作物/种子名称] [数量] - 购买农场币 [数量] + 偷菜 at + 购买农场币 [数量] 金币转换农场币比率是 1 : 2 """.strip(), extra=PluginExtraData( author="Art_Sakura", diff --git a/command.py b/command.py index 868b32c..7491521 100644 --- a/command.py +++ b/command.py @@ -1,6 +1,7 @@ from nonebot.rule import to_me -from nonebot_plugin_alconna import (Alconna, AlconnaQuery, Args, Match, Option, - Query, Subcommand, on_alconna, store_true) +from nonebot_plugin_alconna import (Alconna, AlconnaQuery, Args, At, Match, + MultiVar, Option, Query, Subcommand, + on_alconna, store_true) from nonebot_plugin_uninfo import Uninfo from zhenxun.services.log import logger @@ -43,10 +44,11 @@ diuse_farm = on_alconna( Subcommand("eradicate", help_text="铲除"), Subcommand("my-plant", help_text="我的作物"), Subcommand("sell-plant", Args["name?", str]["num?", int], help_text="出售作物"), - Subcommand("buy-point", Args["num?", int], help_text="购买农场币") + Subcommand("stealing", Args["target?", At], help_text="偷菜"), + Subcommand("buy-point", Args["num?", int], help_text="购买农场币"), + #Subcommand("sell-point", Args["num?", int], help_text="转换金币") ), priority=5, - rule=to_me(), block=True, ) @@ -246,7 +248,7 @@ async def _(session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("n await MessageUtils.build_message("尚未开通农场").send() return None - result = await g_pFarmManager.sellPlantByUid(uid, name.result, num.result) + result = await g_pShopManager.sellPlantByUid(uid, name.result, num.result) await MessageUtils.build_message(result).send(reply_to=True) diuse_farm.shortcut( @@ -256,7 +258,7 @@ diuse_farm.shortcut( prefix=True, ) -@diuse_farm.assign("sell-plant") +@diuse_farm.assign("buy-point") async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)): if num.result <= 0: await MessageUtils.build_message( @@ -273,5 +275,31 @@ async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)): result = await g_pFarmManager.buyPointByUid(uid, num.result) await MessageUtils.build_message(result).send(reply_to=True) +diuse_farm.shortcut( + "偷菜", + command="我的农场", + arguments=["stealing"], + prefix=True, +) +@diuse_farm.assign("stealing") +async def _(session: Uninfo, target: Match[At]): + uid = str(session.user.id) + point = await g_pSqlManager.getUserPointByUid(uid) + if point < 0: + await MessageUtils.build_message("尚未开通农场").send() + return None + + if not target.available: + await MessageUtils.build_message("请在指令后跟需要at的人").finish(reply_to=True) + + tar = target.result + point = await g_pSqlManager.getUserPointByUid(tar.target) + + if point < 0: + await MessageUtils.build_message("尚未开通农场").send() + return None + + result = await g_pFarmManager.stealing(uid, tar.target) + await MessageUtils.build_message(result).send(reply_to=True) diff --git a/config/level.json b/config/level.json index 7a9df1c..50166c8 100644 --- a/config/level.json +++ b/config/level.json @@ -19,7 +19,87 @@ }, "soil":[1, 1, 1, 2, 3, 5, 7, 9, 12, 15, 18, 21, 25, 29, 33, 38, 43, 48, 54, 60, - 66, 72, 78, 85, 92, 99, 106, 114, 120, 130], - - "point":[0, 2000, 5000, 10000, 30000, 50000] + 66, 72, 78, 85, 92, 99, 106, 114, 120, 130 + ], + "reclamation": + { + "4": + { + "level": 3, + "point": 800, + "item": "" + }, + "5": + { + "level": 5, + "point": 1300, + "item": "" + }, + "6": + { + "level": 7, + "point": 3200, + "item": "" + }, + "7": + { + "level": 9, + "point": 5500, + "item": "" + }, + "8": + { + "level": 12, + "point": 12000, + "item": "" + }, + "9": + { + "level": 15, + "point": 19800, + "item": "" + }, + "10": + { + "level":3, + "point": 3000, + "item": "" + }, + "11": + { + "level":3, + "point": 3000, + "item": "" + }, + "12": + { + "level":3, + "point": 3000, + "item": "" + }, + "13": + { + "level":3, + "point": 3000, + "item": "" + }, + "14": + { + "level":3, + "point": 3000, + "item": "" + }, + "15": + { + "level":3, + "point": 3000, + "item": "" + }, + "16": + { + "level":3, + "point": 3000, + "item": "" + } + } } diff --git a/database.py b/database.py index 5eb8b07..d6b2e8c 100644 --- a/database.py +++ b/database.py @@ -1,5 +1,5 @@ import os -from datetime import datetime, timedelta +from datetime import date, datetime, timedelta from io import StringIO from math import e from typing import Any, List, Optional @@ -47,7 +47,9 @@ class CSqlManager: uid INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, exp INTEGER DEFAULT 0, - point INTEGER DEFAULT 0 + point INTEGER DEFAULT 0, + soil INTEGER DEFAULT 3, + stealing TEXT DEFAULT NULL ); """ @@ -120,7 +122,7 @@ class CSqlManager: #用户信息 userInfo = f""" - INSERT INTO user (uid, name, exp, point) VALUES ({uid}, '{name}', {str(exp)}, {str(point)}) + INSERT INTO user (uid, name, exp, point, soil, stealing) VALUES ({uid}, '{name}', {exp}, {point}, 3, '{date.today()}|5') """ #用户仓库 @@ -145,7 +147,7 @@ class CSqlManager: return True @classmethod - async def getUserInfoByUid(cls, uid: str) -> list[dict]: + async def getUserInfoByUid(cls, uid: str) -> dict: """根据用户Uid获取用户信息 Args: @@ -155,27 +157,27 @@ class CSqlManager: list[dict]: 用户信息 """ if len(uid) <= 0: - return [] + return {} try: async with cls.m_pDB.execute( "SELECT * FROM user WHERE uid = ?", (uid,) ) as cursor: - results = [] - async for row in cursor: - user_dict = { + userDict = { "uid": row[0], "name": row[1], "exp": row[2], "point": row[3], + "soil": row[4], + "stealing": row[5] } - results.append(user_dict) - return results + return userDict + return {} except Exception as e: logger.warning(f"getUserInfoByUid查询失败: {e}") - return [] + return {} @classmethod async def getUserPointByUid(cls, uid: str) -> int: @@ -318,18 +320,16 @@ class CSqlManager: int: 解锁几块地 """ if len(uid) <= 0: - return -1 + return 0 - level = await cls.getUserLevelByUid(uid) - soilNumber = 0 - soil_list = g_pJsonManager.m_pLevel['soil'] # type: ignore + async with cls.m_pDB.execute(f"SELECT soil FROM user WHERE uid = '{uid}'") as cursor: + async for row in cursor: + if row[0] == None or len(row[0]) <= 0: + return 0 + else: + return int(row[0]) - #获取解锁地块 - for soil in soil_list: - if level >= soil: - soilNumber += 1 - - return soilNumber + return 0 @classmethod async def getUserSoilStatusBySoilID(cls, uid: str, soil: str) -> tuple[bool, str]: @@ -355,7 +355,9 @@ class CSqlManager: return False, "" @classmethod - async def updateUserSoilStatusByPlantName(cls, uid: str, soil: str, plant: str = "", status: int = 0) -> bool: + async def updateUserSoilStatusByPlantName(cls, uid: str, soil: str, + plant: str = "", + status: int = 0) -> bool: """根据种子名称使用户播种 Args: @@ -371,7 +373,7 @@ class CSqlManager: return False if len(plant) <= 0 and status == 4: - s = f",,,{status}" + s = f",,,{status}," elif len(plant) <= 0 and status != 4: s = "" else: @@ -381,8 +383,8 @@ class CSqlManager: 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:枯萎,是否被偷 示例:QQ号-偷取数量|QQ号-偷取数量 + s = f"{plant},{int(currentTime.timestamp())},{int(newTime.timestamp())},{status}," sql = f"UPDATE soil SET {soil} = '{s}' WHERE uid = '{uid}'" diff --git a/farm/farm.py b/farm/farm.py index efdbf50..ec6c339 100644 --- a/farm/farm.py +++ b/farm/farm.py @@ -1,9 +1,10 @@ import asyncio -from datetime import datetime +import random +from datetime import date, datetime from io import StringIO -from math import exp from typing import Dict, List, Tuple +from Python311.Lib.PIL.ImImagePlugin import number from zhenxun.models.user_console import UserConsole from zhenxun.services.log import logger from zhenxun.utils._build_image import BuildImage @@ -31,10 +32,9 @@ class CFarmManager: p = await g_pSqlManager.getUserPointByUid(uid) - await g_pSqlManager.updateUserPointByUid(uid, point + p) - - return f"充值{num}农场币成功,当前农场币:{point + p}" + await g_pSqlManager.updateUserPointByUid(uid, num + p) + return f"充值{num}农场币成功,当前农场币:{num + p}" @classmethod async def drawFarmByUid(cls, uid: str) -> bytes: @@ -60,19 +60,19 @@ class CFarmManager: await grass.resize(0, soilSize[0], soilSize[1]) soilPos = g_pJsonManager.m_pSoil['soil'] # type: ignore - soilUnlock = g_pJsonManager.m_pLevel['soil'] # type: ignore + soilUnlock = await g_pSqlManager.getUserSoilByUid(uid) x = 0 y = 0 isFirstExpansion = True #首次添加扩建图片 isFirstRipe = True plant = None - for index, level in enumerate(soilUnlock): + for index in range(0, 30): x = soilPos[str(index + 1)]['x'] y = soilPos[str(index + 1)]['y'] #如果土地已经到达对应等级 - if soilNumber >= int(level): + if index > soilUnlock: await img.paste(soil, (x, y)) isPlant, plant, isRipe= await cls.drawSoilPlant(uid, f"soil{str(index + 1)}") @@ -285,7 +285,7 @@ class CFarmManager: ) if num > 0: - return f"播种数量超出解锁土地数量,已将可播种土地成功播种{name}!仓库还剩下{plantDict[name]}个种子" + return f"播种数量超出开垦土地数量,已将可播种土地成功播种{name}!仓库还剩下{plantDict[name]}个种子" else: return f"播种{name}成功!仓库还剩下{plantDict[name]}个种子" @@ -300,19 +300,18 @@ class CFarmManager: str: 返回 """ - soilNumber = await g_pSqlManager.getUserLevelByUid(uid) - soilUnlock = g_pJsonManager.m_pLevel['soil'] # type: ignore + soilUnlock = await g_pSqlManager.getUserSoilByUid(uid) plant = {} - soilNames = [f"soil{i + 1}" for i, level in enumerate(soilUnlock) if soilNumber >= level] + soilNames = [f"soil{i}" for i in range(soilUnlock)] soilStatuses = await asyncio.gather(*[ g_pSqlManager.getUserSoilStatusBySoilID(uid, name) for name in soilNames ]) plant: Dict[str, int] = {} - harvest_records: List[str] = [] + harvestRecords: List[str] = [] experience = 0 for (soil_name, (status, info)) in zip(soilNames, soilStatuses): @@ -325,15 +324,24 @@ class CFarmManager: matureTime = datetime.fromtimestamp(int(soilInfo[2])) if currentTime >= matureTime: - plant[plantId] = plant.get(plantId, 0) + plantInfo['harvest'] - experience += plantInfo['experience'] - harvest_records.append(f"收获作物:{plantId},数量为:{plantInfo['harvest']},经验为:{plantInfo['experience']}") + number = plantInfo['harvest'] - # 批量更新数据库操作 + #判断该土地作物是否被透过 + if len(soilInfo[4]) > 0: + stealingStatus = soilInfo[4].split('|') + for isUser in stealingStatus: + user = isUser.split('-') + number -= user[1] + + plant[plantId] = plant.get(plantId, 0) + number + experience += plantInfo['experience'] + harvestRecords.append(f"收获作物:{plantId},数量为:{number},经验为:{plantInfo['experience']}") + + #批量更新数据库操作 await g_pSqlManager.updateUserSoilStatusByPlantName(uid, soil_name, "", 4) if experience > 0: - harvest_records.append(f"\t累计获得经验:{experience}") + harvestRecords.append(f"\t累计获得经验:{experience}") exp = await g_pSqlManager.getUserExpByUid(uid) await g_pSqlManager.UpdateUserExpByUid(uid, exp + experience) @@ -346,7 +354,7 @@ class CFarmManager: ','.join([f"{k}|{v}" for k, v in plant.items()]) ) - return "\n".join(harvest_records) + return "\n".join(harvestRecords) @classmethod async def eradicate(cls, uid: str) -> str: @@ -359,10 +367,9 @@ class CFarmManager: str: 返回 """ - soilNumber = await g_pSqlManager.getUserLevelByUid(uid) - soilUnlock = g_pJsonManager.m_pLevel['soil'] # type: ignore + soilUnlock = await g_pSqlManager.getUserSoilByUid(uid) - soilNames = [f"soil{i + 1}" for i, level in enumerate(soilUnlock) if soilNumber >= level] + soilNames = [f"soil{i}" for i in range(soilUnlock)] soilStatuses = await asyncio.gather(*[ g_pSqlManager.getUserSoilStatusBySoilID(uid, name) for name in soilNames @@ -436,13 +443,15 @@ class CFarmManager: else: sell = "不可以" + number = count * int(plantInfo['price']) + data_list.append( [ icon, plantName, count, plantInfo['price'], - count * int(plantInfo['price']), + number, sell ] ) @@ -460,82 +469,106 @@ class CFarmManager: return result.pic2bytes() @classmethod - async def sellPlantByUid(cls, uid: str, name: str = "", num: int = 1) -> str: - """出售作物 + async def stealing(cls, uid: str, target: str) -> str: + """偷菜 Args: uid (str): 用户Uid + target (str): 被偷用户Uid Returns: - str: + str: 返回 """ - plant = await g_pSqlManager.getUserPlantByUid(uid) + #用户信息 + userInfo = await g_pSqlManager.getUserInfoByUid(uid) + #用户可偷次数 + userStealing = userInfo["stealing"].split('|') - if plant == None: - return "你仓库没有可以出售的作物" + if date.fromisoformat(userStealing[0]) != date.today(): + userStealing[0] = date.today() + userStealing[1] = 5 - point = 0 - totalSold = 0 - remainingItems = [] + if int(userStealing[1]) <= 0: + return "你今天可偷次数到达上限啦,手下留情吧" - items = plant.split(',') - if len(name) <= 0: - #出售全部 - for item in items: - if '|' in item: - plant_name, count_str = item.split('|', 1) - try: - count = int(count_str) - plant_info = g_pJsonManager.m_pPlant['plant'][plant_name] # type: ignore - point += plant_info['price'] * count - except Exception: + #获取用户 + soilUnlock = int(userInfo["soil"]) + + plant = {} + + #根据解锁土地,获取每块土地状态信息 + soilNames = [f"soil{i}" for i in range(soilUnlock)] + soilStatuses = await asyncio.gather(*[ + g_pSqlManager.getUserSoilStatusBySoilID(target, name) + for name in soilNames + ]) + + plant: Dict[str, int] = {} + harvestRecords: List[str] = [] + + isStealing = False + for(soilName, (status, info)) in zip(soilNames, soilStatuses): + isStealing = False + + if not status: + soilInfo = info.split(',') + plantId = soilInfo[0] + plantInfo = g_pJsonManager.m_pPlant['plant'][plantId] # type: ignore + + currentTime = datetime.now() + matureTime = datetime.fromtimestamp(int(soilInfo[2])) + + stealingNumber = 0 + + if currentTime >= matureTime: + #先获取用户是否偷过该土地 + stealingStatus = soilInfo[4].split('|') + for isUser in stealingStatus: + user = isUser.split('-') + + if user[0] == uid: + isStealing = True + break + + stealingNumber += int(user[1]) + + #如果偷过,则跳过该土地 + if isStealing: continue - await g_pSqlManager.updateUserPlantByUid(uid, "") # 清空仓库 + stealingNumber -= plantInfo['harvest'] + randomNumber = random.choice([1, 2]) + randomNumber = min(randomNumber, stealingNumber) + + if randomNumber > 0: + plant[plantId] = plant.get(plantId, 0) + randomNumber + harvestRecords.append(f"成功偷到作物:{plantId},数量为:{randomNumber}") + + stealingStatus += f"|{uid}-{randomNumber}" + + #如果将作物偷完,就直接更新状态 并记录用户偷取过 + if plantInfo['harvest'] - randomNumber + stealingNumber == 0: + sql = f"UPDATE soil SET {soilName} = ',,,4,{stealingStatus}' WHERE uid = '{target}'" + else: + sql = f"UPDATE soil SET {soilName} = '{soilInfo[0]},{soilInfo[1]},{soilInfo[2]},{soilInfo[3]},{stealingStatus}' WHERE uid = '{target}'" + + await g_pSqlManager.executeDB(sql) + + if not plant: + return "目标没有作物可以被偷" else: - for item in items: - if '|' in item: - plantName, countStr = item.split('|', 1) - try: - count = int(countStr) - if plantName == name: - sellAmount = min(num, count) - totalSold += sellAmount - remaining = count - sellAmount + # 批量更新用户作物仓库数据 + await g_pSqlManager.updateUserPlantByUid(target, ','.join([f"{k}|{v}" for k, v in plant.items()])) - if remaining > 0: - remainingItems.append(f"{plantName}|{remaining}") + userStealing[1] = int(userStealing[1]) - 1 - num -= sellAmount - if num == 0: - break - except (ValueError, TypeError): - continue + sql = f"UPDATE user SET stealing = {'|'.join(userStealing)} WHERE uid = {uid}" - if num > 0: - return f"出售作物{name}出错:数量不足" - - #计算收益 - try: - plantInfo = g_pJsonManager.m_pPlant['plant'][name] # type: ignore - totalPoint = plantInfo['price'] * totalSold - except KeyError: - return f"出售作物{name}出错:作物不存在" - - #更新剩余作物 - remainingPlant = ','.join(remainingItems) if remainingItems else "" - await g_pSqlManager.updateUserPlantByUid(uid, remainingPlant) - - #更新农场币 - p = await g_pSqlManager.getUserPointByUid(uid) - await g_pSqlManager.updateUserPointByUid(uid, p + totalPoint) - - if name: - return f"成功出售{name},获得农场币:{totalPoint}" - else: - return f"成功出售所有作物,获得农场币:{totalPoint}" + #更新用户每日偷取次数 + await g_pSqlManager.executeDB(sql) + return "\n".join(harvestRecords) g_pFarmManager = CFarmManager() diff --git a/farm/shop.py b/farm/shop.py index 57b8c62..de156d9 100644 --- a/farm/shop.py +++ b/farm/shop.py @@ -92,6 +92,12 @@ class CShopManager: except Exception as e: return "购买出错!请检查需购买的种子名称!" + + level = g_pSqlManager.getUserLevelByUid(uid) + + if level < plantInfo['level']: + return "你的等级不够哦,努努力吧" + userPlants = {} point = await g_pSqlManager.getUserPointByUid(uid) @@ -122,5 +128,81 @@ class CShopManager: return f"成功购买{name},当前仓库数量为:{userPlants[name]},花费{total}农场币, 剩余{point - total}农场币" + @classmethod + async def sellPlantByUid(cls, uid: str, name: str = "", num: int = 1) -> str: + """出售作物 + + Args: + uid (str): 用户Uid + + Returns: + str: + """ + + plant = await g_pSqlManager.getUserPlantByUid(uid) + + if plant == None: + return "你仓库没有可以出售的作物" + + point = 0 + totalSold = 0 + remainingItems = [] + + items = plant.split(',') + if len(name) <= 0: + #出售全部 + for item in items: + if '|' in item: + plant_name, count_str = item.split('|', 1) + try: + count = int(count_str) + plant_info = g_pJsonManager.m_pPlant['plant'][plant_name] # type: ignore + point += plant_info['price'] * count + except Exception: + continue + + await g_pSqlManager.updateUserPlantByUid(uid, "") # 清空仓库 + else: + for item in items: + if '|' in item: + plantName, countStr = item.split('|', 1) + try: + count = int(countStr) + if plantName == name: + sellAmount = min(num, count) + totalSold += sellAmount + remaining = count - sellAmount + + if remaining > 0: + remainingItems.append(f"{plantName}|{remaining}") + + num -= sellAmount + if num == 0: + break + except (ValueError, TypeError): + continue + + if num > 0: + return f"出售作物{name}出错:数量不足" + + #计算收益 + try: + plantInfo = g_pJsonManager.m_pPlant['plant'][name] # type: ignore + totalPoint = plantInfo['price'] * totalSold + except KeyError: + return f"出售作物{name}出错:作物不存在" + + #更新剩余作物 + remainingPlant = ','.join(remainingItems) if remainingItems else "" + await g_pSqlManager.updateUserPlantByUid(uid, remainingPlant) + + #更新农场币 + p = await g_pSqlManager.getUserPointByUid(uid) + await g_pSqlManager.updateUserPointByUid(uid, p + totalPoint) + + if name: + return f"成功出售{name},获得农场币:{totalPoint}" + else: + return f"成功出售所有作物,获得农场币:{totalPoint}" g_pShopManager = CShopManager()