@bdsx/economy-shop
Version:
This plugin for BDSX
429 lines (389 loc) • 15.9 kB
text/typescript
import { CustomForm, FormButton, FormLabel, FormSlider, SimpleForm } from "bdsx/bds/form";
import { ServerPlayer } from "bdsx/bds/player";
import { ItemStack } from "bdsx/bds/inventory";
import { EconomyX } from "@bdsx/economy-x";
import { send, sendTranslate } from "./utils/translate";
import * as path from "path";
import * as fs from "fs";
export interface ShopItem {
icon?: string;
path?: "path"|"url";
description?: string;
item: keyof ItemIdMap;
data?: number;
price: number;
}
export interface CompoundShop {
icon?: string;
path?: "path"|"url";
name: string;
description?: string;
category: Record<string, CompoundShop>;
}
const filePath = path.join(__dirname, "..", "shop.json");
let shop: {
shopui: {
title: string;
description: string;
buy_content: string[];
buttons: {
category: string;
item: string;
};
};
category: Record<string, CompoundShop>;
items: Record<string, ShopItem[]>;
} = {
shopui: {
title: "§l§2ShopUI",
description: "",
buy_content: [
"Money: §e%money%",
"Item: §a%item%",
"Price: §e%price%",
],
buttons: {
category: "§l%name%§r\n§8Click for more",
item: "§a%name%§r\n§7Price: §e%price%",
},
},
category: {
blocks: {
icon: "textures/blocks/cobblestone",
path: "path",
name: "§l§aBlocks",
category: {},
},
foods: {
icon: "textures/items/beef_cooked",
path: "path",
name: "§l§6Foods",
category: {},
},
tools: {
icon: "textures/items/diamond_sword",
path: "path",
name: "§l§dTools",
category: {},
},
},
items: {
blocks: [
{
icon: "textures/blocks/grass_side_carried",
path: "path",
item: "minecraft:grass",
price: 1.5,
},
{
icon: "textures/blocks/dirt",
path: "path",
item: "minecraft:dirt",
price: 0.7,
},
{
icon: "textures/blocks/stone",
path: "path",
item: "minecraft:stone",
price: 2,
},
{
icon: "textures/blocks/cobblestone",
path: "path",
item: "minecraft:cobblestone",
price: 1.3,
},
],
foods: [
{
icon: "textures/items/beef_cooked",
path: "path",
item: "minecraft:cooked_beef",
price: 1.8,
},
{
icon: "textures/items/beef_raw",
path: "path",
item: "minecraft:beef",
price: 1.2,
},
],
tools: [
{
icon: "textures/items/iron_sword",
path: "path",
item: "minecraft:iron_sword",
price: 8,
},
{
icon: "textures/items/iron_axe",
path: "path",
item: "minecraft:iron_axe",
price: 8.7,
},
{
icon: "textures/items/iron_pickaxe",
path: "path",
item: "minecraft:iron_pickaxe",
price: 8.7,
},
],
},
};
//Why are there so few items? Because i have very little time and you can customize it
try { shop = require(filePath) } catch(err) {}
export namespace ShopMain {
export function buy(shopItem: ShopItem, amount: number, player: ServerPlayer): boolean {
const xuid = player.getXuid();
if (xuid === "") {
player.sendMessage(send.text(`player.xuid.notfound`));
return false;
}
if (amount < 1) {
player.sendMessage(send.text(`player.invalid.amount`));
return false;
}
const item = ItemStack.constructWith(shopItem.item, amount, shopItem.data);
if (shopItem.price < 0||shopItem.price === 0) {
player.sendMessage(send.text(`success.buy.freeitem`).replace(/%name%/g, item.getCustomName()).replace(/%amount%/g, `${amount}`));
player.addItem(item);
player.sendInventory();
return true;
}
const total = amount*shopItem.price;
if (EconomyX.getMoney(player)-total < 0) {
player.sendMessage(send.text(`player.money.notenough`));
return false;
}
player.sendMessage(send.text(`success.buy.item`).replace(/%name%/g, item.getCustomName()).replace(/%amount%/g, `${amount}`).replace(/%total%/g, `${EconomyX.currency() + total}`));
EconomyX.removeMoney(player, total);
player.addItem(item);
player.sendInventory();
return true;
}
export function getCategories(): string[] {
return Object.keys(shop.category);
}
export function getCompound(category: string): CompoundShop|null {
if (!shop.category.hasOwnProperty(category)) return null;
return shop.category[category];
}
/**@deprecated */
export function getCategoryFromPath(path: string): string[] {return []};
/**@deprecated */
export function getCompoundFromPath(path: string): CompoundShop|null {return null};
export function getItemCategories(): string[] {
return Object.keys(shop.items);
}
export function hasItemCategory(category: string): boolean {
return shop.items.hasOwnProperty(category);
}
export function getItems(category: string): ShopItem[]|undefined {
if (!shop.items.hasOwnProperty(category)) return undefined;
else return shop.items[category];
}
export function getItem(category: string, item: keyof ItemIdMap): ShopItem|null {
if (!shop.items.hasOwnProperty(category)) return null;
const shopItem = shop.items[category].find((v) => item === v.item);
if (!shopItem) return null;
return shopItem;
}
export function createItemCategory(category: string, items: ShopItem[] = [], message: boolean = false, actor?: ServerPlayer): boolean {
const sendT = new sendTranslate(actor, message);
if (shop.items.hasOwnProperty(category)) {
sendT.error(`category.already`);
return false;
}
else {
sendT.success(send.text(`category.created`).replace(/%category%/g, category));
shop.items[category]=items;
return true;
}
}
export function deleteCategory(category: string, message: boolean = false, actor?: ServerPlayer): boolean {
const sendT = new sendTranslate(actor, message);
if (!shop.items.hasOwnProperty(category)) {
sendT.error(`category.notfound`);
return false;
}
else {
sendT.success(send.text(`category.deleted`).replace(/%category%/g, category));
delete shop.items[category];
return true;
}
}
export function addItem(category: string, item: keyof ItemIdMap, data: number = 0, price: number, description?: string, iconPath?: "path"|"url", icon?: string, message: boolean = false, actor?: ServerPlayer): boolean {
const sendT = new sendTranslate(actor, message);
if (!shop.items.hasOwnProperty(category)) {
sendT.error(`category.notfound`);
return false;
}
if (shop.items[category].find((v) => item === v.item)) {
sendT.error(`item.already`);
return false;
}
if (price < 0) {
sendT.error(`item.invalid.price`);
return false;
}
sendT.success(send.text(`item.added`).replace(/%item%/g, item).replace(/%category%/g, category).replace(/%price%/g, `${EconomyX.currency()}${price}`));
shop.items[category].push({
icon: icon,
path: iconPath,
description: description,
item: item,
data: data,
price: price,
});
return true;
}
export function removeItem(category: string, item: keyof ItemIdMap, message: boolean = false, actor?: ServerPlayer): boolean {
const sendT = new sendTranslate(actor, message);
if (!shop.items.hasOwnProperty(category)) {
sendT.error(`category.notfound`);
return false;
}
if (!shop.items[category].find((v) => item === v.item)) {
sendT.error(`item.notfound`);
return false;
}
sendT.success(send.text(`item.removed`).replace(/%item%/g, item).replace(/%category%/g, category));
shop.items[category]=shop.items[category].filter((v) => item !== v.item);
return true;
}
export function setItem(category: string, item: keyof ItemIdMap, newItem: keyof ItemIdMap, data?: number, message: boolean = false, actor?: ServerPlayer): boolean {
if (!shop.items.hasOwnProperty(category)) {
send.error(`category.notfound`);
return false;
}
const shopItem = shop.items[category].find((v) => item === v.item);
if (!shopItem) {
send.error(`item.notfound`);
return false;
}
if (item === newItem && shopItem.data === data) {
send.error(`item.same`);
return false;
}
send.success(send.text(`item.seted`).replace(/%olditem%/g, item).replace(/%olddata%/g, `${shopItem.data ?? 0}`).replace(/%item%/g, newItem).replace(/%data%/g, `${data ?? 0}`).replace(/%category%/g, category));
const index = shop.items[category].indexOf(shopItem);
shop.items[category][index]={
icon: shopItem.icon,
path: shopItem.path,
description: shopItem.description,
item: newItem,
data: data ?? shopItem.data,
price: shopItem.price,
};
return true;
}
export function getPrice(category: string, item: keyof ItemIdMap): number|null {
if (!shop.items.hasOwnProperty(category)) return null;
const shopItem = shop.items[category].find((v) => item === v.item);
if (!shopItem) return null;
if (shopItem.price < 0) return 0;
return shopItem.price;
}
export function setPrice(category: string, item: keyof ItemIdMap, price: number, message: boolean = false, actor?: ServerPlayer): boolean {
const sendT = new sendTranslate(actor, message);
if (shop.items.hasOwnProperty(category)) {
sendT.error(`category.notfound`);
return false;
}
if (price < 0) {
sendT.error(`item.invalid.price`);
return false;
}
let shopItem = shop.items[category].find((v) => item === v.item);
if (!shopItem) {
sendT.error(`item.notfound`);
return false;
}
sendT.success(send.text(`item.setprice`).replace(/%item%/g, item).replace(/%price%/g, `${EconomyX.currency()}${price}`));
shopItem.price=price;
return true;
}
export function save(message: boolean = false): void {
fs.writeFile(filePath, JSON.stringify(shop, null, 2), "utf8", (err) => {
if (message) {
if (err) {
send.error(`shop.json ${err}`);
throw err;
}
else send.success(`shop.json Saved!`);
}
});
}
}
export namespace ShopForm {
export function getItemButtons(items: ShopItem[]): FormButton[] {
let buttons: FormButton[] = [];
for (const [i, button] of items.entries()) {
const item = ItemStack.constructWith(button.item, undefined, button.data);
const _button = new FormButton(shop.shopui.buttons.item.replace("%name%", item.getCustomName()).replace("%price%", `${EconomyX.currency()}${button.price}`), button.path, button.icon);
buttons.push(_button);
}
return buttons;
}
export function getCategoryButtons(categories: CompoundShop[]): FormButton[] {
let buttons: FormButton[] = [];
for (const [i, category] of categories.entries()) {
const button = new FormButton(shop.shopui.buttons.category.replace("%name%", category.name), category.path, category.icon);
buttons.push(button);
}
return buttons;
}
export function main(player: ServerPlayer): void {
let categories: CompoundShop[] = [];
ShopMain.getCategories().forEach((v) => {
const category = ShopMain.getCompound(v);
if (!category) return;
categories.push(category);
});
const buttons = getCategoryButtons(categories);
const form = new SimpleForm(shop.shopui.title, shop.shopui.description, buttons);
form.sendTo(player.getNetworkIdentifier(), (f) => {
const r = f.response;
if (r === null) return;
categoriesForm(ShopMain.getCategories()[r], categories[r], player);
});
}
export function categoriesForm(category: string, compound: CompoundShop, player: ServerPlayer): void {
let compounds: CompoundShop[] = [];
let buttons: FormButton[] = [];
const categories = Object.entries(compound.category);
const items = ShopMain.getItems(category);
if (!items) return;
categories.forEach((v) => { compounds.push(v[1]) });
const formCategories = getCategoryButtons(compounds);
const formItems = getItemButtons(items);
formCategories.forEach((v) => { buttons.push(v) });
formItems.forEach((v) => { buttons.push(v) });
const form = new SimpleForm(compound.name, compound.description, buttons);
form.sendTo(player.getNetworkIdentifier(), (f) => {
const r = f.response;
if (r === null) return;
if (r < formCategories.length) {
categoriesForm(categories[r][0], categories[r][1], player);
return;
}
if (r > (formCategories.length-1)) {
const i = r-formCategories.length;
buyForm(items[i], player);
return;
}
});
}
export function buyForm(shopItem: ShopItem, player: ServerPlayer): void {
const display = ItemStack.constructWith(shopItem.item, undefined, shopItem.data);
const form = new CustomForm(display.getCustomName());
let content: string = shop.shopui.buy_content.map((v) => v+"\n").toString().replace(/,/g, "§r").replace(/%player%/g, player.getName()).replace(/%money%/g, EconomyX.currency()+EconomyX.getMoney(player)).replace(/%item%/g, display.getCustomName()).replace(/%price%/g, EconomyX.currency()+shopItem.price);
form.addComponent(new FormLabel(content));
form.addComponent(new FormSlider(`Amount`, 1, 64));
form.sendTo(player.getNetworkIdentifier(), (f) => {
const r = f.response;
if (r === null) return;
ShopMain.buy(shopItem, r[1], player);
});
}
}