Skip to content

Commit a437f01

Browse files
committed
Add talent material calculator
1 parent 61b11ef commit a437f01

File tree

3 files changed

+148
-13
lines changed

3 files changed

+148
-13
lines changed

src/commands/characters/books.ts

Lines changed: 143 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,69 @@ import { CommandInteraction, Message } from "discord.js"
33
import Command from "../../utils/Command"
44
import client from "../../main"
55
import { sendMessage } from "../../utils/Utils"
6-
import { CommandSource, SendMessage } from "../../utils/Types"
6+
import { CommandSource, Cost, SendMessage } from "../../utils/Types"
7+
import config from "../../data/config.json"
78

89
export default class Books extends Command {
910
constructor(name: string) {
1011
super({
1112
name,
1213
category: "Character",
13-
help: "List talent book days.",
14-
usage: "books",
14+
help: `List talent book days or calculate amount needed.
15+
16+
Amounts need to be without extras from constellations`,
17+
usage: "books (list) | books calc <A/B/C> <X/Y/Z>",
1518
aliases: ["talent", "talents", "talentbook", "tb", "t", "b"],
16-
options: []
19+
options: [{
20+
name: "list",
21+
description: "List book days",
22+
type: "SUB_COMMAND",
23+
}, {
24+
name: "calc",
25+
description: "Check how many books you need to go from A/B/C to X/Y/Z",
26+
type: "SUB_COMMAND",
27+
options: [{
28+
name: "current",
29+
description: "Current talent levels (Excluding extra from constellations)",
30+
type: "STRING",
31+
required: true
32+
}, {
33+
name: "target",
34+
description: "Target talent levels (Excluding extra from constellations)",
35+
type: "STRING",
36+
required: true
37+
}]
38+
}, ]
1739
})
1840
}
1941

2042
async runInteraction(source: CommandInteraction): Promise<SendMessage | undefined> {
21-
return this.run(source)
43+
const { options } = source
44+
const sub = options.getSubcommand()
2245

46+
if (sub == "list")
47+
return this.runList(source)
48+
else if (sub == "calc")
49+
return this.runCalc(source, options.getString("current", true), options.getString("target", true))
50+
else
51+
return sendMessage(source, `Unknown subcommand ${sub}`)
2352
}
24-
async runMessage(source: Message): Promise<SendMessage | undefined> {
25-
return this.run(source)
53+
async runMessage(source: Message|CommandInteraction, args: string[]): Promise<SendMessage | undefined> {
54+
const sub = args[0]?.toLowerCase() ?? "list"
55+
args.shift()
56+
57+
if (["list", "l"].includes(sub)) {
58+
return this.runList(source)
59+
} else if (["calc", "amount"].includes(sub)) {
60+
if (args.length < 2) return this.sendHelp(source)
61+
62+
return this.runCalc(source, args[0], args[1])
63+
} else {
64+
return sendMessage(source, `Unknown subcommand \`${sub}\``)
65+
}
2666
}
2767

28-
async run(source: CommandSource): Promise<SendMessage | undefined> {
68+
async runList(source: CommandSource): Promise<SendMessage | undefined> {
2969
const { data } = client
3070
const { materials } = data
3171

@@ -43,6 +83,100 @@ export default class Books extends Command {
4383

4484
return sendMessage(source, `**Talent Books**:
4585
${days.map(({ days, books }) => `**${days}**: ${books.map(book => `${data.emoji(book)} ${book.split(" ").pop()}`).join(" / ")}`).join("\n")}
46-
**Sunday**: All books are available`)
86+
**Sunday**: All books are available
87+
88+
Calculate how much you need with \`${config.prefix}b calc <current> <target>\` (Example: \`${config.prefix}b calc 4/6/6 9/9/9\`)`)
89+
}
90+
91+
async runCalc(source: CommandSource, current: string, target: string): Promise<SendMessage | undefined> {
92+
const currents = current.split("/").map(x => parseInt(x))
93+
const targets = target.split("/").map(x => parseInt(x))
94+
95+
const { talentCosts }= client.data.costTemplates
96+
const maxLevel = talentCosts.length + 1
97+
98+
if (currents.some(x => isNaN(x)))
99+
return sendMessage(source, `Invalid current levels \`${current}\` (not a number)`, undefined, true)
100+
if (targets.some(x => isNaN(x)))
101+
return sendMessage(source, `Invalid target levels \`${target}\` (not a number)`, undefined, true)
102+
103+
if (currents.some(x => x < 1))
104+
return sendMessage(source, `Invalid current levels \`${current}\` (too low)`, undefined, true)
105+
if (targets.some(x => x < 1))
106+
return sendMessage(source, `Invalid target levels \`${target}\` (too low)`, undefined, true)
107+
108+
if (currents.some(x => x > maxLevel))
109+
return sendMessage(source, `Invalid current levels \`${current}\` (too big)`, undefined, true)
110+
if (targets.some(x => x > maxLevel))
111+
return sendMessage(source, `Invalid target levels \`${target}\` (too big)`, undefined, true)
112+
113+
if (currents.length != targets.length)
114+
return sendMessage(source, `Amount of levels don't match \`${current}\` -> \`${target}\``, undefined, true)
115+
116+
const names: Record<string, { emoji: string, text: string }> = {
117+
"Teachings of <Book>": {
118+
emoji: "Teachings of Diligence",
119+
text: "Teachings of <Book>"
120+
},
121+
"Guide to <Book>": {
122+
emoji: "Guide to Diligence",
123+
text: "Guide to <Book>"
124+
},
125+
"Philosophies of <Book>": {
126+
emoji: "Philosophies of Diligence",
127+
text: "Philosophies of <Book>"
128+
},
129+
"<EnemyDropTier1>": {
130+
emoji: "Whopperflower Nectar",
131+
text: "Enemy Drop Tier 1"
132+
},
133+
"<EnemyDropTier2>": {
134+
emoji: "Whopperflower Nectar",
135+
text: "Enemy Drop Tier 2"
136+
},
137+
"<EnemyDropTier3>": {
138+
emoji: "Energy Nectar",
139+
text: "Enemy Drop Tier 3"
140+
},
141+
"<BossMat>": {
142+
emoji: "Shard of a Foul Legacy",
143+
text: "Weekly Boss Material"
144+
},
145+
"Crown of Insight": {
146+
emoji: "Crown of Insight",
147+
text: "Crown of Insight"
148+
}
149+
}
150+
151+
const totalCosts: Cost = {
152+
mora: 0,
153+
items: Object.keys(names).map(name => ({ name, count: 0 })),
154+
}
155+
156+
for (const i in currents) {
157+
const current = currents[i]
158+
const target = targets[i]
159+
160+
if (target <= current) currents[i] = target
161+
else
162+
for (let j = current; j < target; j++) {
163+
const costs = talentCosts[j-1]
164+
totalCosts.mora = (totalCosts.mora ?? 0) + (costs.mora ?? 0)
165+
166+
for (const item of costs.items) {
167+
const found = totalCosts.items.find(i => i.name == item.name)
168+
if (found)
169+
found.count = found.count + item.count
170+
else
171+
totalCosts.items.push(item)
172+
}
173+
}
174+
}
175+
176+
177+
return sendMessage(source, `Materials needed to go from talent levels \`${currents.join("/")}\` to \`${targets.join("/")}\`
178+
179+
${totalCosts.items.filter(i => i.count > 0).map(i => `${client.data.emoji(names[i.name]?.emoji ?? i.name, false)} ${names[i.name]?.text ?? i.name}: **${i.count}**`).join("\n")}
180+
${client.data.emoji("Mora", true)}: **${totalCosts.mora?.toLocaleString()}**`)
47181
}
48182
}

src/commands/meta/help.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ ${Object.entries(categorized)
125125
${items.sort((a, b) => a.localeCompare(b)).map(cmd => `${config.prefix}${cmd}`).join(", ")}`)
126126
.join("\n")}
127127
128-
*Some commands are also available on the website <${client.data.baseURL}>
128+
*Some commands are also available on the website <${client.data.baseURL}>*
129129
*Make sure to check out \`${config.prefix}help <command name>\` for more information about a specific command, you might find some useful shortcuts/tips (like command aliases/how most search commands support fuzzy search).*
130130
*Any problems/suggestions? Check out \`${config.prefix}about\`.*${missingPerms.length > 0 ? `
131131

src/utils/DataManager.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export default class DataManager {
6060
readonly abyssFloors: Record<number, AbyssFloor> = abyssFloors
6161

6262
readonly paimonsBargains: PaimonShop[] = paimonShop
63-
private readonly costTemplates: Record<string, Cost[]> = costTemplates
63+
readonly costTemplates: Record<string, Cost[]> = costTemplates
6464

6565
readonly enemies: Record<string, Enemy> = enemyData
6666

@@ -115,12 +115,13 @@ export default class DataManager {
115115
}
116116
}
117117

118-
emoji(type: string | undefined, includeName = false): string {
118+
emoji(type: string | undefined, includeName?: boolean): string {
119119
if (!type)
120120
return type ?? "Unknown"
121121

122122
const found = this.emojis[type as BotEmoji]
123-
if (!found) return type
123+
if (!found && includeName == undefined) return type
124+
if (!found && includeName == false) return ""
124125
if (includeName) return `${found} ${type}`
125126
return found
126127
}

0 commit comments

Comments
 (0)