forked from Mystifi/Kobold-Librarian
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquills.js
174 lines (160 loc) · 6.67 KB
/
quills.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
* quills.js: Core functionality of the Scribe Shop
*
* Handles creating the webserver routes for the Scribe Shop, as well as managing quills, the virtual
* currency used by the bot.
*/
const client = require('./client');
const config = require('./config');
const utils = require('./utils');
const server = require('./server');
const storage = require('./storage');
class Quills {
constructor() {
this.data = storage.getJSON('quills');
this.shop = new Map();
server.addRoute(`/shop.html`, (req, res) => {
let queryData = utils.parseQueryString(req.url);
let userid;
let account;
if (queryData.token) {
const tokenData = server.getAccessToken(queryData.token);
if (!tokenData || tokenData.permission !== 'shop') return res.end(`Invalid or expired token provided. Please re-use the '${config.commandToken}shop' command to get a new, valid token.`);
userid = tokenData.user;
if (req.method === "POST" && req.body) {
try {
for (const key in req.body) {
let amount = parseInt(req.body[key]);
if (!isNaN(amount) && amount > 0) {
client.sendPM(userid, this.purchase(userid, key, amount));
}
}
} catch (e) {
client.sendPM(userid, e);
}
}
account = this.getAccount(userid);
}
let output = `<h2>Got some spare quills? This is where you can spend them!</h2>`;
if (userid) {
output += `<p>Greetings, ${userid}. You currently have <strong>${account.balance} quill${utils.plural(account.balance)}</strong> to spend.</p>\
<p>To purchase items, type the amount you wish to buy in the box below the item description, and press the Purchase button when you're done.</p>`;
} else {
output += `<p>Purchasing items in the shop can be done by using the '${config.commandToken}shop' command in PM with the bot. This will send you a personalized URL allowing you to purchase items in the shop.</p>`;
}
output += `<h3>Items:</h3><form method="POST">`;
let entries = [...this.shop.entries()];
entries = entries.sort((a, b) => a[1].price - b[1].price);
for (let [itemId, item] of entries) {
output += `<p><h4>${item.name}</h4>\
<p>Price: ${item.price} quills</p>\
<p>Description: <em>${item.description}</em></p>\
${item.uses > 0 ? `<p>Number of uses: ${item.uses}</p>`: ''}`;
if (userid) {
if (account.inventory[itemId]) {
if (item.unique) {
output += `<p><strong><small>You already own this.</small></strong></p>`;
continue;
} else {
if (item.uses) {
output += `<p>Uses left: ${account.inventory[itemId].uses}</p>`;
} else {
output += `<p>Owned: ${account.inventory[itemId].amount}</p>`;
}
}
}
output += `<input type="number" name="${itemId}" placeholder="0"/>`;
}
}
if (userid) output += `<p><input type="submit" value="Purchase"></p>`;
output += `</form>`;
return res.end(utils.wrapHTML('Scribe Shop', output));
});
}
addShopItem(id, name, price, description, uses, unique) {
if (this.shop.has(id)) return utils.errorMsg(`'${id}' is already a shop item.`);
this.shop.set(id, {name, price, description, uses, unique});
}
getAccount(userid) {
if (!(userid in this.data)) this.data[userid] = {balance: 0, totalEarned: 0, inventory: {}};
return this.data[userid];
}
getTop(limit) {
return Object.entries(this.data).sort((a, b) => b[1].totalEarned - a[1].totalEarned).slice(0, limit);
}
addQuills(userid, amount) {
let account = this.getAccount(userid);
let balance = account.balance += amount;
account.totalEarned += amount;
storage.exportJSON('quills');
return balance;
}
removeQuills(userid, amount) {
let account = this.getAccount(userid);
if (account.balance - amount < 0) amount = account.balance;
let balance = account.balance -= amount;
storage.exportJSON('quills');
return balance;
}
useItem(userid, itemId) {
let item = this.getAccount(userid).inventory[itemId];
if (item) {
if (item.uses && --item.uses) return item.uses;
delete this.getAccount(userid).inventory[itemId];
storage.exportJSON('quills');
return 0;
}
return -1;
}
purchase(userid, itemId, amount = 1) {
if (!(this.shop.has(itemId))) throw(`The item "${itemId}" doesn't exist.`);
let account = this.getAccount(userid);
let item = this.shop.get(itemId);
if (('unique' in item) && account.inventory[itemId]) throw(`You don't need to buy another ${item.name}.`);
let limited = item.uses;
if (limited) {
// Count how many more copies a user needs. If the user already has the item, then find
// the number of copies they need to return to the maximum number of uses; otherwise, just
// default to the max number of uses.
amount = itemId in account.inventory ? (item.uses - account.inventory[itemId].uses) : item.uses;
}
if (amount <= 0) throw(limited ? `You have the maximum amount of usages for a ${item.name} (${item.uses}).` : "You can't purchase zero (or less) of something...");
// If the item has a limited number of uses, then we don't multiply the price by the number
// of copies of the item.
let price = item.price * (limited ? 1 : amount);
let exceeding = price > account.balance;
if (exceeding) {
// See if we can purchase a fewer amount of the item by decrementing the amount
// by one each pass. We don't do this if the item is limited because a person,
// when purchasing an item with uses, cannot end up purchasing less than the maximum
// number of usages. (That would be scamming them.)
while (!limited && exceeding && amount > 0) {
amount--;
price = item.price * amount;
exceeding = price > account.balance;
}
if (exceeding) {
throw(`You don't have enough money to purchase any ${item.name}s.`);
} else {
throw(`You only have enough money to purchase ${amount} ${item.name}${utils.plural(amount)} for ${price} quills.`);
}
}
let balance = this.removeQuills(userid, price);
if (!(itemId in account.inventory)) account.inventory[itemId] = {};
let purchased = account.inventory[itemId];
let itemMessage = '';
if (!(limited || item.unique)) {
// If an item does not have a limited amount of uses, then a user can purchase
// more than one of the item.
if (!('amount' in purchased)) purchased.amount = 0;
purchased.amount += amount;
itemMessage = `You now have ${purchased.amount} ${item.name}${utils.plural(purchased.amount)}.`;
} else if (item.uses) {
purchased.uses = item.uses;
itemMessage = `You have ${item.uses} available use${utils.plural(item.uses)} for your ${item.name}.`;
}
storage.exportJSON('quills');
return `Successfully purchased ${amount} ${item.name}${utils.plural(amount)} for ${price} quills. ${itemMessage} New balance: ${balance}`;
}
}
module.exports = new Quills();