Skip to content

Commit d6e77af

Browse files
npermaJaylyDev
andauthored
ShopUI-WRAPPED (#382)
* Core * Update index.js --------- Co-authored-by: Jayly <[email protected]>
1 parent e027e9a commit d6e77af

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

scripts/shop-wrapped/index.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Script example for ScriptAPI
2+
// Author: Nperma <https://github.com/nperma>
3+
// Project: https://github.com/JaylyDev/ScriptAPI
4+
5+
import { world, system, World, Player, ItemStack } from '@minecraft/server';
6+
import { ActionFormData, ModalFormData, MessageFormData, FormCancelationReason } from '@minecraft/server-ui';
7+
8+
const { setDynamicProperty: SDP, getDynamicProperty: GDP, getDynamicPropertyIds: IDS } = World.prototype,
9+
scb = world.scoreboard;
10+
11+
/** @param {Player} player @param {ActionFormData} form */
12+
async function FORCE_OPEN(player, form) {
13+
while (true) {
14+
let v = await form.show(player);
15+
if (!v || v.cancelationReason !== FormCancelationReason.UserBusy) return v;
16+
}
17+
}
18+
/** @param {Player} player @returns {number} */
19+
function gM(player) {
20+
const ob = scb.getObjective('money') ? scb.getObjective('money') : scb.addObjective('money');
21+
return ob.getScore(player) || 0;
22+
}
23+
24+
/** @param {Player} player @param {number} amount */
25+
function aM(player, amount) {
26+
system.run(() => {
27+
const ob = scb.getObjective('money') ? scb.getObjective('money') : scb.addObjective('money');
28+
ob.setScore(player, gM(player) + amount);
29+
});
30+
}
31+
32+
export class ShopUI {
33+
SHOP;
34+
SHOP_TITLE;
35+
SENDERS;
36+
STRUCTURE;
37+
38+
/** @param {string} title - shop title @param {Array} structure - the shop structure @param {Player | Player[]} ShowFormTo - player's will show this shop form */
39+
constructor(title = 'Shop - UI', structure = [], ShowFormTo = undefined) {
40+
if (!Array.isArray(structure)) throw new TypeError('Structure must be an array!');
41+
this.SENDERS = ShowFormTo;
42+
this.STRUCTURE = structure;
43+
this.SHOP_TITLE = title;
44+
this.SHOP = new ActionFormData().title(title.toString());
45+
this.#defined();
46+
}
47+
48+
#defined() {
49+
if (!this.SENDERS) return;
50+
51+
if (this.SENDERS instanceof Player) {
52+
this.#showCategoryForm(this.SENDERS, this.STRUCTURE, this.SHOP_TITLE);
53+
} else if (Array.isArray(this.SENDERS)) {
54+
for (const sender of this.SENDERS) this.#showCategoryForm(sender, this.STRUCTURE, this.SHOP_TITLE);
55+
}
56+
}
57+
58+
/**
59+
* @param {Player} player
60+
* @param {any[]} categories
61+
* @param {string | import("@minecraft/server").RawMessage} path
62+
*/
63+
async #showCategoryForm(player, categories, path) {
64+
const FORM = new ActionFormData().title(path);
65+
for (const [CATEGORY_NAME, _, CATEGORY_TEXTURE = ''] of categories) FORM.button(CATEGORY_NAME, CATEGORY_TEXTURE);
66+
67+
const FORM_SELECTION = await FORCE_OPEN(player, FORM);
68+
if (FORM_SELECTION.canceled) return;
69+
70+
const selected = categories[FORM_SELECTION.selection];
71+
if (!Array.isArray(selected)) return;
72+
73+
const [CATEGORY_NAME, ITEMS] = selected;
74+
const PATH = `${path}::${CATEGORY_NAME}`.replace(' ', '_');
75+
76+
if (Array.isArray(ITEMS[0])) this.#showCategoryForm(player, ITEMS, PATH);
77+
else this.#showItemForm(player, ITEMS, PATH, CATEGORY_NAME);
78+
}
79+
80+
/**
81+
* @param {Player} player
82+
* @param {any} items
83+
* @param {string} categoryPath
84+
* @param {string | import("@minecraft/server").RawMessage} categoryName
85+
*/
86+
async #showItemForm(player, items, categoryPath, categoryName) {
87+
player.sendMessage(JSON.stringify({ ...arguments }, null, 4));
88+
const item_data = items;
89+
if (typeof item_data === 'object' && !Array.isArray(item_data)) {
90+
const STOCKED_ID = `${categoryPath}::${categoryName}`;
91+
if (!IDS.call(world).find((/** @type {string} */ id) => id === STOCKED_ID)) SDP.call(world, STOCKED_ID, item_data?.stock || 64);
92+
93+
const currentStock = GDP.call(world, STOCKED_ID);
94+
if (currentStock <= 0) return new MessageFormData().title(categoryName).body(`§cStock is empty, please wait for restock.`).button2('Close').show(player);
95+
new ModalFormData()
96+
.title(categoryName)
97+
.slider(`§7${categoryPath.replace(/::/g, '/')}\n§e» Money: §a$${gM(player)}\n§e» Item ID: ${item_data?.item}\n§e» Price per item: §2$${item_data?.price}\n§e» §7Stock: (${currentStock})`, 1, Math.min(item_data?.max, currentStock) || 1, 1)
98+
.show(player)
99+
.then((p) => {
100+
if (p.canceled) return;
101+
102+
/**
103+
* @type {number}
104+
*/
105+
// @ts-ignore
106+
const amount = p.formValues[0];
107+
const totalCost = amount * item_data?.price;
108+
109+
if (gM(player) < totalCost)
110+
return new MessageFormData()
111+
.title(categoryName)
112+
.body(`§cYou don't have enough money!\n§eYou need §a$${totalCost - gM(player)}`)
113+
.button2('Close')
114+
.show(player);
115+
116+
aM(player, -totalCost);
117+
SDP.call(world, STOCKED_ID, currentStock - amount);
118+
player.getComponent('inventory').container.addItem(new ItemStack(item_data?.item, amount));
119+
player.sendMessage(`§aSuccessfully bought ${amount}x ${item_data?.item}`);
120+
});
121+
}
122+
}
123+
}

0 commit comments

Comments
 (0)