@@ -3,29 +3,69 @@ import { CommandInteraction, Message } from "discord.js"
33import Command from "../../utils/Command"
44import client from "../../main"
55import { 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
89export 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}
0 commit comments