From d155fba9cdf28c1f01fc8565b3355d53a501fa00 Mon Sep 17 00:00:00 2001 From: NIANIANKNIA Date: Thu, 13 Feb 2025 01:45:22 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=95=86=E5=BA=97=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F&&=E9=80=82=E9=85=8D1.21.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- .../NiaServer-Core-BP/manifest.json | 8 +- .../NiaServer-Core-BP/scripts/basic/main.js | 44 +- .../NiaServer-Core-BP/scripts/game/home.js | 2 +- .../NiaServer-Core-BP/scripts/game/shop.js | 570 ++++++++++++------ .../NiaServer-Core-BP/scripts/main.js | 4 +- 6 files changed, 420 insertions(+), 211 deletions(-) diff --git a/README.md b/README.md index d3d69df..e30ec3c 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ ## 写在前面 > [!WARNING] -> 当前服务器addons包仍处于开发状态,暂时没有对其他类型服务器做适配,所以我们并不推荐您直接使用! +> 当前服务器addons包仍处于开发状态,暂时没有对其他类型服务器做适配,所以我们并不推荐您直接使用 +> **我们将在v2.0.0正式版提供可以适配其他服务器的addons包,敬请期待!** > [!TIP] >为了实现更多功能,服务器使用了@minecraft/server-net模块,所以本插件包不能在个人存档中正常运行,只能在BDS上运行! diff --git a/development_behavior_packs/NiaServer-Core-BP/manifest.json b/development_behavior_packs/NiaServer-Core-BP/manifest.json index 26d9fe9..e87e58d 100644 --- a/development_behavior_packs/NiaServer-Core-BP/manifest.json +++ b/development_behavior_packs/NiaServer-Core-BP/manifest.json @@ -4,8 +4,8 @@ "name": "NiaServer-Core-1.5.0 BP", "description": "§bCopyright (C) 2025 Nia-Server\n版本:v1.0.0\n项目地址:https://github.com/Nia-Server/NiaServer-Core", "uuid": "cab0bbe3-eb10-465e-b1de-b09facc076c8", - "version": [ 1, 5, 0 ], - "min_engine_version": [ 1, 21, 50 ] + "version": [ 1, 5, 1 ], + "min_engine_version": [ 1, 21, 60 ] }, "modules": [ { @@ -14,13 +14,13 @@ "description": "gametest module", "uuid": "92cd3fe1-e764-425a-aa40-a7e4d7760922", "entry": "scripts/main.js", - "version": [ 1, 5, 0 ] + "version": [ 1, 5, 1 ] } ], "dependencies": [ { "module_name": "@minecraft/server", - "version": "1.17.0-beta" + "version": "1.18.0-beta" }, { "module_name": "@minecraft/server-ui", diff --git a/development_behavior_packs/NiaServer-Core-BP/scripts/basic/main.js b/development_behavior_packs/NiaServer-Core-BP/scripts/basic/main.js index 5bf8ac0..18cf9f4 100644 --- a/development_behavior_packs/NiaServer-Core-BP/scripts/basic/main.js +++ b/development_behavior_packs/NiaServer-Core-BP/scripts/basic/main.js @@ -39,30 +39,26 @@ world.afterEvents.worldInitialize.subscribe((event) => { system.runInterval(() => { - let TIME = new Date(); - if (TIME.getSeconds() == 0) { //增加在线时间 RunCmd(`scoreboard players add @a time 1`); - } - if (TIME.getMinutes() == 0 && TIME.getSeconds() == 0 ) { - let RN = parseInt(getNumberInNormalDistribution(100,20)) - //防止物价指数出现极端数值 - if (RN <= 20 || RN >= 180) { - RN = 100 - } - RunCmd(`scoreboard players set RN DATA ${RN}`); - RunCmd(`title @a title §c物价指数发生变动!`) - RunCmd(`title @a subtitle §7物价指数由 §l§e${GetScore("DATA","RN") / 100} §r§7变为 §l§e${RN / 100}`) - //自动备份 - if (TIME.getHours() == 16) { - let ScoreBoards = world.scoreboard.getObjectives() - for (let i = 0; i < ScoreBoards.length; i++) { - if (ScoreBoards[i].id.slice(0,2) == "R:") { - RunCmd(`scoreboard objectives remove "${ScoreBoards[i].id}"`) - } - } - Broadcast(`§a 服务器时间已更新!`) - } - } -},40) + // if (TIME.getMinutes() == 0 && TIME.getSeconds() == 0 ) { + // let RN = parseInt(getNumberInNormalDistribution(100,20)) + // //防止物价指数出现极端数值 + // if (RN <= 20 || RN >= 180) { + // RN = 100 + // } + // RunCmd(`scoreboard players set RN DATA ${RN}`); + // RunCmd(`title @a title §c物价指数发生变动!`) + // RunCmd(`title @a subtitle §7物价指数由 §l§e${GetScore("DATA","RN") / 100} §r§7变为 §l§e${RN / 100}`) + // if (TIME.getHours() == 16) { + // let ScoreBoards = world.scoreboard.getObjectives() + // for (let i = 0; i < ScoreBoards.length; i++) { + // if (ScoreBoards[i].id.slice(0,2) == "R:") { + // RunCmd(`scoreboard objectives remove "${ScoreBoards[i].id}"`) + // } + // } + // Broadcast(`§a 服务器时间已更新!`) + // } + // } +},1200) diff --git a/development_behavior_packs/NiaServer-Core-BP/scripts/game/home.js b/development_behavior_packs/NiaServer-Core-BP/scripts/game/home.js index 64a03b0..436555c 100644 --- a/development_behavior_packs/NiaServer-Core-BP/scripts/game/home.js +++ b/development_behavior_packs/NiaServer-Core-BP/scripts/game/home.js @@ -15,7 +15,7 @@ const GUI = { } const HomeMainForm = new ActionFormData() .title("传送点设置") - .body("请选择你要传送的地点\n如果要添加传送点请前往设置页面进行添加") + .body("请选择你要传送的地点") .button("返回上一级菜单","textures/ui/wysiwyg_reset") .button("添加/删除传送点","textures/ui/paste") for (let i = 0; i < player_pos_data.length; i++) { diff --git a/development_behavior_packs/NiaServer-Core-BP/scripts/game/shop.js b/development_behavior_packs/NiaServer-Core-BP/scripts/game/shop.js index 905ab43..5ce7e75 100644 --- a/development_behavior_packs/NiaServer-Core-BP/scripts/game/shop.js +++ b/development_behavior_packs/NiaServer-Core-BP/scripts/game/shop.js @@ -1,17 +1,19 @@ -import { world } from '@minecraft/server'; +import { ItemStack, system, world, ItemComponentTypes,EnchantmentType, EntityComponentTypes } from '@minecraft/server'; import { ActionFormData,ModalFormData,MessageFormData } from '@minecraft/server-ui' -import { Tell,RunCmd,GetScore } from '../API/game.js'; +import { Tell,RunCmd,GetScore, GetTime,GetDate } from '../API/game.js'; import { Main } from './main_menu.js'; import { ExternalFS } from '../API/http.js'; import { log,warn,error } from "../API/logger.js"; import { TitleGUI } from './playertitle.js'; import { cfg } from '../config.js'; +//武器等不可堆叠武器构建判断后期写 const fs = new ExternalFS(); var SellData = []; var RecycleData = []; const MoneyShowName = cfg.MoneyShowName const MoneyScoreboardName = cfg.MoneyScoreboardName +const USE_RN_SYSTEM = true; //商店数据读取 //服务器启动监听&&获得商店数据 @@ -37,12 +39,46 @@ world.afterEvents.worldInitialize.subscribe(() => { }) }) +var basic_RN = 1.0;//基础物价指数 + +var single_RN = { + "mineral": 1.2,//矿物 + "weapon": 1.5,//武器 + "equipment": 1.8,//装备 + "vegetative": 1.0,//植物 + "entity": 1.0,//实体 + "redstone": 1.5,//红石 + "enchanted_book": 2.0,//附魔书 + "block": 1.0,//方块 + "prop": 1.0,//道具 + "default": 1.0//默认 +} + +system.runInterval(() => { + if (world.getDynamicProperty("shop_TIME") == undefined) { + world.setDynamicProperty("shop_TIME",GetDate()); + } + if (world.getDynamicProperty("shop_player_data") == null) { + world.setDynamicProperty("shop_player_data",JSON.stringify({"shop":{},"recycle":{}})); + } + if (world.getDynamicProperty("shop_TIME") != GetDate()) { + world.setDynamicProperty("shop_TIME",GetDate()); + world.setDynamicProperty("shop_player_data",JSON.stringify({"shop":{},"recycle":{}})); + world.sendMessage("§a 服务器商店交易数量限制已重置!") + } +},1200) + const GUI = { ShopMain(player) { const ShopMainForm = new ActionFormData() - .title("§e§l服务器商店") - .body("§l===========================\n§r§e欢迎光临服务器官方商店!\n目前服务器的物价指数为: §6§l" + GetScore("DATA","RN")/100 + "\n§r§e目前您的" + MoneyShowName + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n§r§c请根据自己需求理性购物!\n§r§l===========================") - .button("§c返回上一级") + .title("服务器商店") + .body("§l===========================\n"+ + "§r§e欢迎光临服务器官方商店!\n"+ + "目前服务器的基础物价指数为: §6§l" + basic_RN+ + "\n§r§e目前您的" + MoneyShowName + "余额为: §6§l" + GetScore("money",player.nameTag) +"\n"+ + "§r§c请根据自己需求理性购物!\n"+ + "§r§l===========================") + .button("返回上一级","textures/ui/wysiwyg_reset") .button("查看今日折扣商品\n立即查看现在的折扣商品!") .button("售卖物品商店\n在这里售卖各式各样的物品!") .button("回收物品商店\n在这里回收各式各样的物品!") @@ -70,20 +106,44 @@ const GUI = { }, Discount(player) { + for(let i = 0; i < SellData.length; i++) { + for(let j = 0; j < SellData[i].content.length; j++) { + if(SellData[i].content[j].discount != 1 && SellData[i].content[j].discount_end_time != "-1") { + if (SellData[i].content[j].discount_end_time < GetTime()) { + SellData[i].content[j].discount = 1; + } + } + } + } const DiscountForm = new ActionFormData() DiscountForm.title("今日折扣") - let Str = "§l===========================§r\n§e§l每天各个物品的折扣\n可能根据市场有所变动!\n§r§l===========================§r\n" + let Str = "§l===========================§r\n"+ + "§e§l每天各个物品的折扣\n" + + "可能根据市场有所变动!\n"+ + "§r§l===========================§r\n" let num = 1; for(let i = 0; i < SellData.length; i++) { for(let j = 0; j < SellData[i].content.length; j++) { if(SellData[i].content[j].discount != 1) { - Str = Str + "§r§c"+ num + ".§r§e" + SellData[i].content[j].name + " §6" + SellData[i].content[j].discount * 10 + "§e折 折后价格:§6" + parseInt(SellData[i].content[j].price * SellData[i].content[j].discount * GetScore("DATA","RN") / 100) + "\n§r" + Str = Str + "§r§c"+ + num + ".§r§e" + + SellData[i].content[j].name + " §6" + + SellData[i].content[j].discount * 10 + "§e折 折后价格:§6" + + parseInt( + SellData[i].content[j].price * + SellData[i].content[j].discount * + basic_RN * + single_RN[SellData[i].content[j].item_type] + ) +"\n§r" num++ } } } - DiscountForm.body(Str + "§l===========================\n§c" + "【广告】广告位招商\n详情咨询腐竹!" + "\n§r§l===========================") - DiscountForm.button("§c返回上一级") + DiscountForm.body(Str + + "§l===========================\n§c" + + "【广告】广告位招商\n详情咨询腐竹!" + + "\n§r§l===========================") + DiscountForm.button("返回上一级","textures/ui/wysiwyg_reset") DiscountForm.show(player).then((result) => { if (result.selection == 0) { this.ShopMain(player) @@ -93,14 +153,30 @@ const GUI = { ShopPurchase(player) { //定义商店售卖页面菜单 + for(let i = 0; i < SellData.length; i++) { + for(let j = 0; j < SellData[i].content.length; j++) { + if(SellData[i].content[j].discount != 1 && SellData[i].content[j].discount_end_time != "-1") { + if (SellData[i].content[j].discount_end_time < GetTime()) { + SellData[i].content[j].discount = 1; + } + } + } + } const ShopPurchaseForm = new ActionFormData() - .title("§e§l服务器商店") - .body("§l===========================\n§r§e欢迎光临服务器官方商店!\n目前服务器的物价指数为: §6§l" + GetScore("DATA","RN")/100 + "\n§r§e目前您的" + MoneyShowName + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n§r§c请根据自己需求理性购物!\n§r§l===========================") - .button("§c返回上一级") + .title("服务器商店") + .body("§l===========================\n"+ + "§r§e欢迎光临服务器官方商店!\n"+ + "目前服务器的物价指数为: §6§l" + basic_RN + "\n" + + "§r§e目前您的" + MoneyShowName + + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n" + + "§r§c§l带有◆的商品价格不受物价指数影响" + "\n" + + "§r§l===========================") + .button("返回上一级","textures/ui/wysiwyg_reset") for(let i = 0; i < SellData.length; i++) { ShopPurchaseForm.button(SellData[i].name + "\n" + SellData[i].description,SellData[i].image) } ShopPurchaseForm.show(player).then((response) => { + if (response.canceled) return; if (response.selection == 0) { this.ShopMain(player) } else { @@ -112,17 +188,71 @@ const GUI = { ShopPurchaseSub(player,index1) { //定义商店售卖二级页面 const ShopPurchaseSubForm = new ActionFormData() - .title("§e§l服务器商店") - .body("§l===========================\n§r§e欢迎光临服务器官方商店!\n目前服务器的物价指数为: §6§l" + GetScore("DATA","RN")/100 + "\n§r§e目前您的" + MoneyShowName + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n§r§c请根据自己需求理性购物!\n§r§l===========================") - .button("§c返回上一级") + .title("服务器商店") + .body("§l===========================\n"+ + "§r§e欢迎光临服务器官方商店!\n目前服务器的物价指数为: §6§l" + + basic_RN+ + "\n§r§e目前您的" + + MoneyShowName + + "余额为: §6§l" + + GetScore("money",player.nameTag) + + "\n§r§c§l带有◆的商品价格不受物价指数影响\n"+ + "§r§l===========================") + .button("返回上一级","textures/ui/wysiwyg_reset") for(let i = 0; i < SellData[index1].content.length; i++) { - if (SellData[index1].content[i].discount == 1) { - ShopPurchaseSubForm.button(SellData[index1].content[i].name + "\n价格: §9" + parseInt(SellData[index1].content[i].price * GetScore("DATA","RN") / 100),SellData[index1].content[i].image) + let button_content = ""; + let influence_by_RN = true; + let discount = 1; + let merchandise = SellData[index1].content[i]; + let price = merchandise.price; + //判断type + switch(merchandise.type) { + case "item" || "special_item": + //判断是否有"influence_by_RN"属性 + if (!merchandise.influence_by_RN) { + button_content = "§c◆§r" + influence_by_RN = false; + } + //判断是否有"discount"属性 + if (merchandise.hasOwnProperty("discount") && + merchandise.discount != 1) { + button_content = button_content + "§c[限时优惠]§r" + discount = merchandise.discount; + } + //判断是否有"lim"属性 + if (merchandise.lim) { + button_content = button_content + "§c[单日限购]§r" + } + button_content = button_content + merchandise.name + "\n" + if (merchandise.lim_num) { + button_content = button_content + "限购§9" + merchandise.lim_num + "§r个 " + } else if (merchandise.lim) { + button_content = button_content + "限购§91§r个 " + merchandise.lim_num = 1; + } + + if (influence_by_RN) price = price * basic_RN * single_RN[merchandise.item_type]; + if (discount != 1) { + button_content = button_content + + "原价:§9" + parseInt(price) + + "§r 现价:§9" + parseInt(price * discount) + } else { + button_content = button_content + + "价格:§9" + parseInt(price) + } + break; + default: + button_content = "商店物品类型解析出错\n请联系管理员处理"; + break; + } + if (merchandise.hasOwnProperty("image")) { + ShopPurchaseSubForm.button(button_content,merchandise.image) } else { - ShopPurchaseSubForm.button("§c[限时优惠]§r" + SellData[index1].content[i].name + "\n原价:§9" + parseInt(SellData[index1].content[i].price * GetScore("DATA","RN") / 100) +"§r 现价: §9" + parseInt(SellData[index1].content[i].price * SellData[index1].content[i].discount * GetScore("DATA","RN") / 100),SellData[index1].content[i].image) + ShopPurchaseSubForm.button(button_content) } } ShopPurchaseSubForm.show(player).then((response) => { + if (response.canceled) return; if (response.selection == 0) { this.ShopPurchase(player) } else { @@ -131,67 +261,140 @@ const GUI = { }) }, - ShopBuy(player,index1,index2) { - //定义商店售卖二级页面 + ShopBuy(player, index1, index2) { + const merchandise = SellData[index1].content[index2]; + let influence_by_RN = merchandise.hasOwnProperty("influence_by_RN") ? merchandise.influence_by_RN : true; + let discount = (merchandise.hasOwnProperty("discount") && merchandise.discount !== 1) ? merchandise.discount : 1; + + let price = merchandise.price; + if (influence_by_RN) price *= basic_RN * single_RN[merchandise.item_type]; + price *= discount; + + let can_buy_num = Math.floor(GetScore("money", player.nameTag) / price); + if (merchandise.lim) { + let shopPlayerData = JSON.parse(world.getDynamicProperty("shop_player_data")); + let remaining = merchandise.lim_num; + if (shopPlayerData.shop[player.nameTag]?.[merchandise.type_id]) { + remaining -= shopPlayerData.shop[player.nameTag][merchandise.type_id]; + } + can_buy_num = Math.min(can_buy_num, remaining); + } + const ShopBuyForm = new ModalFormData() - ShopBuyForm.title("§c§l确认购买 " + SellData[index1].content[index2].name + " 的数量") - // ShopBuyForm.slider("请选择你要购买的数量",1,64,1,1); - ShopBuyForm.textField("请输入你要购买的数量","只能输入正整数!","1") + .title(`§c§l购买数量确认: ${merchandise.name}`) + .textField( + `\n§c§l当前最大可购买数量: ${can_buy_num} 个\n\n§r请输入购买数量`, + "只能输入正整数" + ); + ShopBuyForm.show(player).then((result) => { - if(result.canceled) { - this.ShopPurchaseSub(player,index1) + if (result.canceled) { + this.ShopPurchaseSub(player, index1); + return; } - if (parseInt(result.formValues[0]) <= 0 || isNaN(parseInt(Number(result.formValues[0])))) { - player.sendMessage(`§c 错误的数字格式,请重新输入!`) - // Tell(`§c 错误的数字格式,请重新输入!`,player.nameTag) - this.ShopBuy(player,index1,index2) - } else if (parseInt(result.formValues[0]) >= 1025) { - player.sendMessage(`§c 单次购买物品的数量上限是1024,请重新输入!`); - this.ShopBuy(player,index1,index2) - } else { - this.ShopBuySub(player,index1,index2,result.formValues[0]) + const input = parseInt(result.formValues[0]); + if (isNaN(input) || input <= 0) { + player.sendMessage(`§c 错误数字格式,请重新输入!`); + system.runTimeout(() => this.ShopBuy(player, index1, index2), 20); + return; } - }) + if (input > can_buy_num) { + player.sendMessage(`§c 购买数量超过可买上限,原因可能是达到购买上限或${MoneyShowName}不足,请重新输入!`); + system.runTimeout(() => this.ShopBuy(player, index1, index2), 20); + return; + } + if (input > 1024) { + player.sendMessage(`§c 单次购买数量上限是1024,请重新输入!`); + system.runTimeout(() => this.ShopBuy(player, index1, index2), 20); + return; + } + if (player.getComponent(EntityComponentTypes.Inventory).container.emptySlotsCount < input / 64) { + player.sendMessage(`§c 购买失败!您的背包空间不足,请至少清理 ${Math.ceil(input / 64)} 格后再次尝试购买!`); + return; + } + this.ShopBuySub(player, index1, index2, input, price); + }); }, - ShopBuySub(player,i,j,num) { + ShopBuySub(player,i,j,num,price) { const ShopBuySubForm = new MessageFormData() .title("§c§l确认购买 " + SellData[i].content[j].name) .body("§e您确定要以 §l" + - parseInt(SellData[i].content[j].price * SellData[i].content[j].discount * GetScore("DATA","RN") / 100) * num + + price * num + "§r§e "+ MoneyShowName + ",购买 §l" + num + " §r§e个" + SellData[i].content[j].name + "?\n§c§l注意:所有商品一旦售出概不退换!") - .button1("§c§l取消") - .button2("§a§l确定") + .button1("§c§l返回数量确认界面") + .button2("§a§l确定购买商品") ShopBuySubForm.show(player).then((result) => { if (result.canceled) return; - switch(result.selection) { - case 1: - if (GetScore("money",player.nameTag) >= parseInt(SellData[i].content[j].price * SellData[i].content[j].discount * GetScore("DATA","RN") / 100) * num) { - RunCmd(`give "${player.nameTag}" ${SellData[i].content[j].type} ${num} ${SellData[i].content[j].data}`) - RunCmd(`scoreboard players add @a[name="${player.nameTag}"] money -${parseInt(SellData[i].content[j].price * SellData[i].content[j].discount * GetScore("DATA","RN") / 100) * num}`) - player.sendMessage("§a 购买成功!§e您以 §l" + parseInt(SellData[i].content[j].price * SellData[i].content[j].discount * GetScore("DATA","RN") / 100) * num + "§r§e " + MoneyShowName + ",成功购买 §l" + num + " §r§e个" + SellData[i].content[j].name + "!期待您的下次光临!") - } else { - player.sendMessage(`§c 购买失败!余额不足,您的余额为 ${GetScore("money",player.nameTag)} ${MoneyShowName}, - 而本次购买需要 ${parseInt(SellData[i].content[j].price * SellData[i].content[j].discount * GetScore("DATA","RN") / 100) * num} ${MoneyShowName}, - 您还缺少 ${parseInt(SellData[i].content[j].price * SellData[i].content[j].discount * GetScore("DATA","RN") / 100) * num - GetScore("money",player.nameTag)} ${MoneyShowName}, - 请在攒够足够${MoneyShowName}后尝试再次购买!`) - } - break; - case 0: - player.sendMessage("§c 购买失败!原因是您自己取消了本次购买!") - break; + if (result.selection == 1) { + let merchandise = SellData[i].content[j]; + switch(merchandise.type) { + case "item": + let item = new ItemStack(merchandise.type_id); + if (merchandise.hasOwnProperty("lores")) item.setLore(merchandise.lores); + if (merchandise.hasOwnProperty("enchs")) { + merchandise.enchs.forEach(ench => { + item.getComponent(ItemComponentTypes.Enchantable).addEnchantment( + {type: new EnchantmentType(ench.type), level: ench.level} + ); + }); + } + if (merchandise.damage) item.getComponent(ItemComponentTypes.Durability).damage = merchandise.damage; + if (merchandise.name_tag) item.nameTag = merchandise.name_tag; + if (merchandise.lim) { + let shop_player_data = JSON.parse(world.getDynamicProperty("shop_player_data")); + if (!shop_player_data.shop[player.nameTag]) shop_player_data.shop[player.nameTag] = {}; + if (!shop_player_data.shop[player.nameTag][merchandise.type_id]) shop_player_data.shop[player.nameTag][merchandise.type_id] = 0; + shop_player_data.shop[player.nameTag][merchandise.type_id] += num; + world.setDynamicProperty("shop_player_data", JSON.stringify(shop_player_data)); + } + if (num != 1) item.amount = num; + world.scoreboard.getObjective(MoneyScoreboardName).addScore(player, -price * num); + player.getComponent(EntityComponentTypes.Inventory).container.addItem(item); + player.sendMessage(`§a 购买成功!您以§e§l${price * num}§r§a${MoneyShowName},成功购买§e§l${num}§r§a个§e${merchandise.name}§r§a!期待您的下次光临!`); + break; + case "special_item": + if (merchandise.lim) { + let shop_player_data = JSON.parse(world.getDynamicProperty("shop_player_data")); + if (!shop_player_data.shop[player.nameTag]) shop_player_data.shop[player.nameTag] = {}; + if (!shop_player_data.shop[player.nameTag][merchandise.type_id]) shop_player_data.shop[player.nameTag][merchandise.type_id] = 0; + shop_player_data.shop[player.nameTag][merchandise.type_id] += num; + world.setDynamicProperty("shop_player_data", JSON.stringify(shop_player_data)); + } + world.scoreboard.getObjective(MoneyScoreboardName).addScore(player, -price * num); + let cmd = `give "${player.nameTag}" ${merchandise.type_id} ${num}`; + if (merchandise.hasOwnProperty("item_data")) cmd += ` ${merchandise.item_data}`; + if (merchandise.hasOwnProperty("item_data") && + merchandise.hasOwnProperty("item_json")) cmd += ` ${merchandise.item_json}`; + RunCmd(cmd); + player.sendMessage(`§a 购买成功!您以§e§l${price * num}§r§a${MoneyShowName},成功购买§e§l${num}§r§a个§e${merchandise.name}§r§a!期待您的下次光临!`); + break; + default: + player.sendMessage("§c 购买失败!原因是商品类型解析出错,请联系管理员处理!") + break; + } + } else { + this.ShopBuy(player,i,j); } + }) }, + + ///////////////////////////////////////////// ShopRecycle(player) { //定义商店回收页面菜单 const ShopRecycleForm = new ActionFormData() - .title("§e§l回收商店") - .body("§l===========================\n§r§e欢迎光临服务器官方回收商店!\n目前服务器的物价指数为: §6§l" + GetScore("DATA","RN")/100 + "\n§r§e目前您的" + MoneyShowName + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n§r§l===========================") - .button("§c返回上一级") + .title("回收商店") + .body("§l===========================\n"+ + "§r§e欢迎光临服务器官方回收商店!\n"+ + "目前服务器的物价指数为: §6§l" + basic_RN+ "\n" + + "§r§e目前您的" + MoneyShowName + + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n" + + "§r§l===========================") + .button("返回上一级","textures/ui/wysiwyg_reset") for(let i = 0; i < RecycleData.length; i++) { ShopRecycleForm.button(RecycleData[i].name + "\n" + RecycleData[i].description,RecycleData[i].image) } @@ -207,153 +410,162 @@ const GUI = { ShopRecycleSub(player,index1) { //定义商店回收的二级页面 const ShopRecycleSubForm = new ActionFormData() - .title("§e§l回收商店") - .body("§l===========================\n§r§e欢迎光临服务器官方回收商店!\n目前服务器的物价指数为: §6§l" + GetScore("DATA","RN")/100 + "\n§r§e目前您的" + MoneyShowName + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n§r§l===========================") - .button("§c返回上一级") + .title("回收商店") + .body("§l===========================\n"+ + "§r§e欢迎光临服务器官方回收商店!\n"+ + "目前服务器的物价指数为: §6§l" + basic_RN+ + "\n§r§e目前您的" + MoneyShowName + + "余额为: §6§l" + GetScore("money",player.nameTag) + "\n" + + "§r§c§l带有◆的商品价格不受物价指数影响\n"+ + "§r§l===========================") + .button("返回上一级","textures/ui/wysiwyg_reset") + let price = 0; for(let i = 0; i < RecycleData[index1].content.length; i++) { - if (RecycleData[index1].content[i].lim == false) { - ShopRecycleSubForm.button(RecycleData[index1].content[i].name + "\n回收单价: §9" + parseInt(RecycleData[index1].content[i].price * GetScore("DATA","RN") / 100),RecycleData[index1].content[i].image) + let button_content = ""; + let influence_by_RN = true; + let recycle_item = RecycleData[index1].content[i]; + price = recycle_item.price; + //判断type + switch(recycle_item.type) { + case "item": + //判断是否有"influence_by_RN"属性 + if (!recycle_item.influence_by_RN) { + button_content = "§c◆§r" + influence_by_RN = false; + } + //判断是否有"lim"属性 + if (recycle_item.lim) { + button_content = button_content + "§c[单日回收数量限制]§r" + } + button_content = button_content + recycle_item.name + "\n" + if (recycle_item.lim_num) { + button_content = button_content + "单日回收限制§9" + recycle_item.lim_num + "§r个 " + } else if (recycle_item.lim) { + button_content = button_content + "单日回收限制§91§r个 " + recycle_item.lim_num = 1; + } + + if (influence_by_RN) price = price * basic_RN * single_RN[recycle_item.item_type]; + button_content = button_content +"回收单价:§9" + parseInt(price) + break; + default: + button_content = "商店物品类型解析出错\n请联系管理员处理"; + break; + } + if (recycle_item.hasOwnProperty("image")) { + ShopRecycleSubForm.button(button_content,recycle_item.image) } else { - ShopRecycleSubForm.button("§c[单日回收数量限制]§r" + RecycleData[index1].content[i].name + "\n回收单价:§9" + parseInt(RecycleData[index1].content[i].price * GetScore("DATA","RN") / 100) +" §r回收数量限制:§9 " + RecycleData[index1].content[i].limnum,RecycleData[index1].content[i].image) + ShopRecycleSubForm.button(button_content) } } ShopRecycleSubForm.show(player).then((response) => { + if (response.canceled) return; if (response.selection == 0) { this.ShopRecycle(player) } else { - this.ShopSell(player,index1,response.selection - 1) + this.ShopSell(player,index1,response.selection - 1,price) } }) }, - ShopSell(player,index1,index2) { - //回收物品这里有四种情况-没有相关物品-回收数量达到限额-有相关物品但有数量限制-有相关物品但没有数量限制 - //首先判断有没有相关物品 - let ItemNum = 0; - for (let i = 0; i < 36; i++) { - if (player.getComponent("minecraft:inventory").container.getItem(i) != undefined && player.getComponent("minecraft:inventory").container.getItem(i).typeId == RecycleData[index1].content[index2].type && player.getComponent("minecraft:inventory").container.getItem(i).lockMode == "none") { - ItemNum = ItemNum + player.getComponent("minecraft:inventory").container.getItem(i).amount; - } - } - //有物品之后再次判断是否限制数量 - if (ItemNum != 0) { - let HasLim = false; - //限制每日兑换数量 - if (RecycleData[index1].content[index2].lim) { - //限制数量就判断是否达到限额 - let HaveData = false; - let ScoreBoards = world.scoreboard.getObjectives() - //直接遍历所有计分板看玩家有没有创建相关数据 - for (let i = 0; i < ScoreBoards.length; i++) { - if (ScoreBoards[i].id == "R:" + player.nameTag.slice(0,10)) { - //进入到这里就说明玩家有相关计分板 - for (let j = 0; j < ScoreBoards[i].getParticipants().length; j++) { - if (ScoreBoards[i].getParticipants()[j].displayName == RecycleData[index1].content[index2].type.slice(10)) { - if (GetScore(`R:${player.nameTag.slice(0,10)}`,`${ScoreBoards[i].getParticipants()[j].displayName}`) == RecycleData[index1].content[index2].limnum) { - HasLim = true; - } - HaveData = true; - break; - } - } - break; + ShopSell(player,index1,index2,price) { + let recycle_item = RecycleData[index1].content[index2]; + switch(recycle_item.type) { + case "item": + let can_recycle_num = 0; + for (let i = 0; i < 36; i++) { + if (player.getComponent(EntityComponentTypes.Inventory).container.getItem(i) != undefined + && player.getComponent(EntityComponentTypes.Inventory).container.getItem(i).typeId == recycle_item.type_id + && player.getComponent(EntityComponentTypes.Inventory).container.getItem(i).lockMode == "none") { + can_recycle_num = can_recycle_num + player.getComponent(EntityComponentTypes.Inventory).container.getItem(i).amount; } } - //没有数据就创建数据计分板! - if (!HaveData) { - //创建计分板 - if (world.scoreboard.getObjective(`R:${player.nameTag.slice(0,10)}`) == null) { - world.scoreboard.addObjective(`R:${player.nameTag.slice(0,10)}`,`R:${player.nameTag}`); + if (recycle_item.lim) { + let recycle_data = JSON.parse(world.getDynamicProperty("shop_player_data")).recycle; + let remaining = recycle_item.lim_num; + if (recycle_data[player.nameTag]?.[recycle_item.type_id]) { + remaining -= recycle_data[player.nameTag][recycle_item.type_id]; } - //设置分数 - RunCmd(`scoreboard players set ${RecycleData[index1].content[index2].type.slice(10)} R:${player.nameTag.slice(0,10)} 0`) + if (can_recycle_num > remaining) can_recycle_num = remaining; } - } - //没有达到限额&&没有限额 - if (!HasLim) { - const ShopSellForm = new ModalFormData() - ShopSellForm.title("§c§l确认回收 " + RecycleData[index1].content[index2].name + " 的数量") - if (RecycleData[index1].content[index2].lim) { - let CanRecycleNum = RecycleData[index1].content[index2].limnum - GetScore(`R:${player.nameTag.slice(0,10)}`,RecycleData[index1].content[index2].type.slice(10)) - if (ItemNum > CanRecycleNum) { - ShopSellForm.slider("请选择你要回收的数量",1,CanRecycleNum,1,1); - } else { - ShopSellForm.slider("请选择你要回收的数量",1,ItemNum,1,1); - } + if (can_recycle_num != 0) { + const ShopSellForm = new ModalFormData() + .title("§c§l确认回收 " + recycle_item.name + " 的数量") + .textField(`\n§c§l当前最大可回收数量: ${can_recycle_num} 个\n\n§r请输入要回收的数量`, + "只能输入正整数") + .show(player).then((result) => { + if (result.canceled) { + this.ShopRecycleSub(player, index1); + return; + } + const input = parseInt(result.formValues[0]); + if (isNaN(input) || input <= 0) { + player.sendMessage(`§c 错误数字格式,请重新输入!`); + system.runTimeout(() => this.ShopSell(player, index1, index2, price), 20); + return; + } + if (input > can_recycle_num) { + player.sendMessage(`§c 回收数量超过可回收上限,原因可能是达到回收上限或背包中物品数量不够,请重新输入!`); + system.runTimeout(() => this.ShopSell(player, index1, index2, price), 20); + return; + } + this.ShopSellSub(player, index1, index2, input, price); + }) } else { - ShopSellForm.slider("请选择你要回收的数量",1,ItemNum,1,1); + player.sendMessage("§c 回收失败!原因是没有在您的背包中找到相应物品或达到了物品单日回收上限!") + system.runTimeout(() => this.ShopRecycleSub(player, index1), 20); } - ShopSellForm.show(player).then((result) => { - this.ShopSellSub(player,index1,index2,result.formValues[0]) - }) - } else { - //达到限额提示 - const ShopSellLimForm = new MessageFormData() - .title("§c§l回收 " + RecycleData[index1].content[index2].name + " 限额提醒") - .body("§e该物品已达到本日回收最大数量,请明天再次尝试回收哦!") - .button1("§c退出") - .button2("§a返回上一级菜单") - ShopSellLimForm.show(player).then(result => { + break; + default: + player.sendMessage("§c 回收失败!原因是商品类型解析出错,请联系管理员处理!") + break; + } + }, + + //开始发送确认回收的表单 + ShopSellSub(player,index1,index2,num,price) { + let recycle_item = RecycleData[index1].content[index2]; + switch(recycle_item.type) { + case "item": + const ShopSellSubForm = new MessageFormData() + .title("§c§l确认回收 " + recycle_item.name) + .body("§e您确定要以 §l" + price * num + "§r§e " + + MoneyShowName + "的报酬,回收 §l" + num + " §r§e个" + recycle_item.name + "?\n"+ + "§c§l注意:所有商品一旦回收无法逆转!") + .button1("§c§l取消") + .button2("§a§l确定回收") + .show(player).then((result) => { if (result.canceled) return; - switch (result.selection) { + switch(result.selection) { case 1: - this.ShopRecycleSub(player,index1); + //首先进行判断是否有限制,有限制就直接写入相关数据 + if (recycle_item.lim) { + let recycle_data = JSON.parse(world.getDynamicProperty("shop_player_data")).recycle; + if (!recycle_data[player.nameTag]) recycle_data[player.nameTag] = {}; + if (!recycle_data[player.nameTag][recycle_item.type_id]) recycle_data[player.nameTag][recycle_item.type_id] = 0; + recycle_data[player.nameTag][recycle_item.type_id] += num; + world.setDynamicProperty("shop_player_data", JSON.stringify({recycle: recycle_data})); + } + //然后进行扣除物品的操作 + if (recycle_item.item_data) { + RunCmd(`clear @a[name="${player.nameTag}"] ${recycle_item.type_id} ${recycle_item.item_data} ${num}`) + } else { + RunCmd(`clear @a[name="${player.nameTag}"] ${recycle_item.type_id} -1 ${num}`) + } + //最后进行给予货币的操作 + world.scoreboard.getObjective(MoneyScoreboardName).addScore(player, price * num); + player.sendMessage(`§a 回收成功!您以§e§l${price * num}§r§a${MoneyShowName},成功回收§e§l${num}§r§a个§e${recycle_item.name}§r§a!期待您的下次光临!`); break; case 0: - player.sendMessage("§c 回收失败!原因是该物品已达到本日回收最大数量,请明天再次尝试回收哦!") + player.sendMessage("§c 回收失败!原因是您自己取消了本次回收!") break; } }) - } - - } else { - //没有相关物品提醒 - const ShopSellNoItemForm = new MessageFormData() - .title("§c§l回收 " + RecycleData[index1].content[index2].name + " 失败提醒") - .body("§c§l没有在您的背包中找到相应物品!请检查背包后再次尝试!") - .button1("§c退出") - .button2("§a返回上一级菜单") - ShopSellNoItemForm.show(player).then(result => { - if (result.canceled) return; - switch (result.selection) { - case 1: - this.ShopRecycleSub(player,index1); - break; - case 0: - player.sendMessage("§c 回收失败!原因是没有在您的背包中找到相应物品!请检查背包后再次尝试!") - break; - } - }) + break; + default: + player.sendMessage("§c 回收失败!原因是商品类型解析出错,请联系管理员处理!") + break; } - - }, - - //开始发送确认回收的表单 - ShopSellSub(player,index1,index2,num) { - const ShopSellSubForm = new MessageFormData() - .title("§c§l确认回收 " + RecycleData[index1].content[index2].name) - .body("§e您确定要以 §l" + parseInt(RecycleData[index1].content[index2].price * GetScore("DATA","RN") / 100) * num + "§r§e " + MoneyShowName + "的报酬,回收 §l" + num + " §r§e个" + RecycleData[index1].content[index2].name + "?\n§c§l注意:所有商品一旦回收无法逆转!") - .button1("§c§l取消") - .button2("§a§l确定") - ShopSellSubForm.show(player).then((result) => { - switch(result.selection) { - case 1: - //首先进行判断是否有限制,有限制就直接写入相关数据 - if (RecycleData[index1].content[index2].lim) { - // PlayerRecycleData[player.nameTag][RecycleData[index1].content[index2].type] = PlayerRecycleData[player.nameTag][RecycleData[index1].content[index2].type] + num - RunCmd(`scoreboard players set ${RecycleData[index1].content[index2].type.slice(10)} R:${player.nameTag.slice(0,10)} ${GetScore(`R:${player.nameTag.slice(0,10)}`,RecycleData[index1].content[index2].type.slice(10)) + num}`) - } - //然后进行扣除物品的操作 - RunCmd(`clear @a[name="${player.nameTag}"] ${RecycleData[index1].content[index2].type} ${RecycleData[index1].content[index2].data} ${num}`) - //然后执行加钱的操作! - RunCmd(`scoreboard players add @a[name="${player.nameTag}"] money ${parseInt(RecycleData[index1].content[index2].price * GetScore("DATA","RN") / 100) * num}`) - player.sendMessage(`§a 回收成功!您成功回收 §l${num}§r§a 个 §l${RecycleData[index1].content[index2].name}§r§a,并获得了 §l${parseInt(RecycleData[index1].content[index2].price * GetScore("DATA","RN") / 100) * num} §r§a${MoneyShowName}!期待您的下次光临!`) - break; - case 0: - player.sendMessage("§c 回收失败!原因是您自己取消了本次回收!") - break; - } - }) } } diff --git a/development_behavior_packs/NiaServer-Core-BP/scripts/main.js b/development_behavior_packs/NiaServer-Core-BP/scripts/main.js index 588e3b9..7e34de0 100644 --- a/development_behavior_packs/NiaServer-Core-BP/scripts/main.js +++ b/development_behavior_packs/NiaServer-Core-BP/scripts/main.js @@ -49,8 +49,8 @@ import './qqBot/main.js' import { cfg } from './config.js' export const VERSION = "v1.5.1"; -export const BDS_VERSION = "1.21.51.02"; -export const LAST_UPGRATE = "2025/02/09"; +export const BDS_VERSION = "1.21.60.10"; +export const LAST_UPGRATE = "2025/02/12"; export const CODE_BRANCH = "main";