11class SpellCompendium {
2- static ftag_desc ( functional_tags , tag ) {
3- return functional_tags [
4- Object . keys ( functional_tags ) . find ( f_tag => tag . includes ( f_tag ) )
2+ static UI = {
3+ LeftDiv : document . getElementById ( 'compendium_left' ) ,
4+ RightDiv : document . getElementById ( 'compendium_right' ) ,
5+ SchoolList : document . getElementById ( 'left_school_tags' ) ,
6+ TagList : document . getElementById ( 'left_regular_tags' ) ,
7+ ForbiddenList : document . getElementById ( 'left_forbidden_tags' ) ,
8+ } ;
9+
10+ static TagDescriptions = {
11+ Functional : {
12+ Cantrip : 'When cast, this spell is treated as a tier 1 spell in all regards, including MP cost.' ,
13+ Concentration : 'You need to concentrate on this spell. Taking damage forces you to make a Constitution saving throw against DC 10 or half the damage done, whichever is higher. On a failure, the spell ends. When you cast a spell with Concentration while you are concentrating on a different spell, the first spell ends. You lose concentration if you are at 0 hit points.' ,
14+ Delayed : 'You can pay for this spell\'s AP cost over multiple turns. While you have at least 1 AP set towards the spell, you are concentrating on the spell.' ,
15+ Forbidden : 'You can\'t learn this spell normally. You need a general talent that automatically unlocks these spells for you once taken.' ,
16+ Mastery : 'If you have all the tags for this spell, reduce the MP cost of the spell by two tiers.' ,
17+ Potent : 'You can cast this spell at a higher tier for an increased effect.' ,
18+ Sign : 'This spell creates a field around you that does not move. It ends if you leave the field or cast another Sign spell.' ,
19+ Ritual : 'This spell takes too much time to cast during combat.' ,
20+ Silent : 'You do not need to speak to cast this spell.' ,
21+ Still : 'You do not need to move to cast this spell.' ,
22+ Deprecated : 'This spell is considered for removal. Please do not select this spell during playtesting.' ,
23+ } ,
24+ School : {
25+ Conjuration : '' ,
26+ Evocation : '' ,
27+ Transmutation : '' ,
28+ Necromancy : '' ,
29+ Abjuration : '' ,
30+ Enchantment : '' ,
31+ Illusion : '' ,
32+ Divination : '' ,
33+ Forbidden : '' ,
34+ }
35+ } ;
36+
37+ static TagCounts = {
38+ Regular : { } ,
39+ Functional : { } ,
40+ School : { } ,
41+ Forbidden : { } ,
42+ } ;
43+ static {
44+ SpellDatabase . forEach ( ( spell ) => {
45+ spell . tags . forEach ( ( tag ) => {
46+ if ( tag . includes ( 'Forbidden' ) ) {
47+ SpellCompendium . TagCounts . Forbidden [ tag ] ??= 0 ;
48+ SpellCompendium . TagCounts . Forbidden [ tag ] ++ ;
49+ } else if ( tag in SpellCompendium . TagDescriptions . Functional ) {
50+ SpellCompendium . TagCounts . Functional [ tag ] ??= 0 ;
51+ SpellCompendium . TagCounts . Functional [ tag ] ++ ;
52+ } else if ( tag in SpellCompendium . TagDescriptions . School ) {
53+ SpellCompendium . TagCounts . School [ tag ] ??= 0 ;
54+ SpellCompendium . TagCounts . School [ tag ] ++ ;
55+ } else {
56+ SpellCompendium . TagCounts . Regular [ tag ] ??= 0 ;
57+ SpellCompendium . TagCounts . Regular [ tag ] ++ ;
58+ }
59+ } )
60+ } ) ;
61+ }
62+
63+ static tagSelection = new Set ( ) ;
64+ static tierSelection = new Set ( ) ;
65+
66+ static tagDescription ( tag ) {
67+ return SpellCompendium . TagDescriptions . Functional [
68+ Object . keys ( SpellCompendium . TagDescriptions . Functional ) . find ( fTag => tag . includes ( fTag ) )
569 ] ;
670 }
771
872 // Generate full-sized spell description
9- static spellCard ( spellData , functional_tags ) {
73+ static spellCard ( spell ) {
1074 const card = document . createElement ( 'table' ) ;
1175 const cardBody = card . appendChild ( document . createElement ( 'tbody' ) ) ;
1276 card . className = 'spell' ;
13-
77+
1478 const spellName = cardBody . appendChild ( document . createElement ( 'tr' ) ) . appendChild ( document . createElement ( 'td' ) ) ;
1579 spellName . className = 'spellname' ;
1680 spellName . colSpan = 2 ;
17- spellName . innerHTML = spellData . name ;
18-
19- if ( spellData . author ) {
81+ spellName . innerHTML = spell . name ;
82+
83+ if ( spell . author ) {
2084 const author = cardBody . appendChild ( document . createElement ( 'tr' ) ) . appendChild ( document . createElement ( 'td' ) ) ;
2185 author . className = 'spelltier' ;
2286 author . colSpan = 2 ;
23- author . innerHTML = `by ${ spellData . author } ` ;
87+ author . innerHTML = `by ${ spell . author } ` ;
2488 }
25-
89+
2690 const tier = cardBody . appendChild ( document . createElement ( 'tr' ) ) . appendChild ( document . createElement ( 'td' ) ) ;
2791 tier . className = 'spelltier' ;
2892 tier . colSpan = 2 ;
29- tier . innerHTML = `Tier ${ spellData . tier } ` ;
30-
93+ tier . innerHTML = `Tier ${ spell . tier } ` ;
94+
3195 const tagsRow = cardBody . appendChild ( document . createElement ( 'tr' ) ) ;
3296 const tagsH = tagsRow . appendChild ( document . createElement ( 'td' ) ) ;
3397 const tagsD = tagsRow . appendChild ( document . createElement ( 'td' ) ) ;
3498 tagsH . className = 'spellheaders' ;
3599 tagsD . className = 'spelltags' ;
36100 tagsH . textContent = 'Tags:' ;
37- tagsD . innerHTML = spellData . tags
38- . map ( tag => Object . keys ( functional_tags ) . some ( f_tag => tag . includes ( f_tag ) ) ? `<span class='fTag' title='${ SpellCompendium . ftag_desc ( functional_tags , tag ) } '>${ tag } </span>` : tag )
101+ tagsD . innerHTML = spell . tags
102+ . map ( tag => Object . keys ( SpellCompendium . TagDescriptions . Functional ) . some ( fTag => tag . includes ( fTag ) ) ? `<span class='fTag' title='${ SpellCompendium . tagDescription ( tag ) } '>${ tag } </span>` : tag )
39103 . join ( ', ' )
40104 ;
41-
105+
42106 const costRow = cardBody . appendChild ( document . createElement ( 'tr' ) ) ;
43107 const costH = costRow . appendChild ( document . createElement ( 'td' ) ) ;
44108 const costD = costRow . appendChild ( document . createElement ( 'td' ) ) ;
45109 costH . className = 'spellheaders' ;
46110 costD . className = 'spelldata' ;
47111 costH . textContent = 'Cost:' ;
48- costD . innerHTML = spellData . cost ;
49-
112+ costD . innerHTML = spell . cost ;
113+
50114 const rangeRow = cardBody . appendChild ( document . createElement ( 'tr' ) ) ;
51115 const rangeH = rangeRow . appendChild ( document . createElement ( 'td' ) ) ;
52116 const rangeD = rangeRow . appendChild ( document . createElement ( 'td' ) ) ;
53117 rangeH . className = 'spellheaders' ;
54118 rangeD . className = 'spelldata' ;
55119 rangeH . textContent = 'Range:' ;
56- rangeD . innerHTML = spellData . range ;
57-
120+ rangeD . innerHTML = spell . range ;
121+
58122 const durationRow = cardBody . appendChild ( document . createElement ( 'tr' ) ) ;
59123 const durationH = durationRow . appendChild ( document . createElement ( 'td' ) ) ;
60124 const durationD = durationRow . appendChild ( document . createElement ( 'td' ) ) ;
61125 durationH . className = 'spellheaders' ;
62126 durationD . className = 'spelldata' ;
63127 durationH . textContent = 'Duration:' ;
64- durationD . innerHTML = spellData . duration ;
65-
128+ durationD . innerHTML = spell . duration ;
129+
66130 const desc = cardBody . appendChild ( document . createElement ( 'tr' ) ) . appendChild ( document . createElement ( 'td' ) ) ;
67131 desc . colSpan = 2 ;
68- desc . innerHTML = spellData . desc ;
69-
70- if ( spellData . empower ) {
132+ desc . innerHTML = spell . desc ;
133+
134+ if ( spell . empower ) {
71135 const empowerRow = cardBody . appendChild ( document . createElement ( 'tr' ) ) ;
72136 const empowerH = empowerRow . appendChild ( document . createElement ( 'td' ) ) ;
73137 const empowerD = empowerRow . appendChild ( document . createElement ( 'td' ) ) ;
74138 empowerH . className = 'spellheaders' ;
75139 empowerD . className = 'spelldesc' ;
76140 empowerH . textContent = 'Empower:' ;
77- empowerD . innerHTML = spellData . empower ;
141+ empowerD . innerHTML = spell . empower ;
78142 }
79-
143+
80144 return card ;
81145 }
82146
83147 // Generate spell table entry
84- static spellBrief ( spellData , functional_tags ) {
148+ static spellBrief ( spell ) {
85149 const brief = document . createElement ( 'tr' ) ;
86- brief . id = `spell_${ spellData . name . replaceAll ( ' ' , '_' ) } ` ;
87-
150+ brief . id = `spell_${ spell . name . replaceAll ( ' ' , '_' ) } ` ;
151+
88152 [
89- spellData . name ,
90- spellData . tier ,
91- spellData . range ,
92- spellData . duration ,
93- spellData . tags
94- . map ( tag => Object . keys ( functional_tags ) . some ( f_tag => tag . includes ( f_tag ) ) ? `<span class='fTag' title='${ SpellCompendium . ftag_desc ( functional_tags , tag ) } '>${ tag } </span>` : tag )
153+ spell . name ,
154+ spell . tier ,
155+ spell . range ,
156+ spell . duration ,
157+ spell . tags
158+ . map ( tag => Object . keys ( SpellCompendium . TagDescriptions . Functional ) . some ( fTag => tag . includes ( fTag ) ) ? `<span class='fTag' title='${ SpellCompendium . tagDescription ( tag ) } '>${ tag } </span>` : tag )
95159 . join ( ', ' )
96160 ] . forEach ( data => {
97161 const td = brief . appendChild ( document . createElement ( 'td' ) ) ;
98162 td . className = 'spelldata' ;
99163 td . innerHTML = data ;
100164 } ) ;
101-
165+
102166 brief . onclick = function ( ) {
103- const card = SpellCompendium . spellCard ( spellData , functional_tags ) ;
167+ const card = SpellCompendium . spellCard ( spell , SpellCompendium . TagDescriptions . Functional ) ;
104168 const compendiumRight = document . getElementById ( 'compendium_right' ) ;
105169 compendiumRight . replaceChild ( card , compendiumRight . firstElementChild ) ;
106170 } ;
107-
171+
108172 return brief ;
109173 }
110174
111175 // Generate spell table
112- static generate_brief_spell_table ( SpellDatabase , tag_select , tier_select , functional_tags ) {
176+ static generateSpellTable ( ) {
113177 const oldTable = document . querySelector ( '#spelltable' ) ;
114178 const newTable = oldTable . cloneNode ( false ) ;
115179
116180 SpellDatabase . forEach ( spell => {
117- if ( tag_select . size > 0 && ! spell . tags . some ( tag => tag_select . has ( tag ) ) ) return ;
118- if ( tier_select . size > 0 && ! tier_select . has ( spell . tier ) ) return ;
119- newTable . appendChild ( SpellCompendium . spellBrief ( spell , functional_tags ) ) ;
181+ if ( SpellCompendium . tagSelection . size > 0 && ! spell . tags . some ( tag => SpellCompendium . tagSelection . has ( tag ) ) ) return ;
182+ if ( SpellCompendium . tierSelection . size > 0 && ! SpellCompendium . tierSelection . has ( spell . tier ) ) return ;
183+ newTable . appendChild ( SpellCompendium . spellBrief ( spell , SpellCompendium . TagDescriptions . Functional ) ) ;
120184 } ) ;
121185
122186 oldTable . parentNode . replaceChild ( newTable , oldTable ) ;
@@ -137,11 +201,11 @@ class SpellCompendium {
137201 } else {
138202 confirm ( "No spell has been selected!" ) ;
139203 }
140-
204+
141205 }
142206
143- static tag_buttons ( tag_list , tag_set , container , render_callback ) {
144- Object . entries ( tag_list ) . sort ( ( a , b ) => {
207+ static tagButtons ( tags , container ) {
208+ Object . entries ( tags ) . sort ( ( a , b ) => {
145209 if ( a [ 1 ] == b [ 1 ] ) {
146210 return ( a [ 0 ] == b [ 0 ] ) ? 0 : ( a [ 0 ] > b [ 0 ] ) ? 1 : - 1 ;
147211 } else {
@@ -151,7 +215,7 @@ class SpellCompendium {
151215 const div = container . appendChild ( document . createElement ( 'button' ) ) ;
152216 const img = div . appendChild ( document . createElement ( 'img' ) ) ;
153217 const text = div . appendChild ( document . createElement ( 'div' ) ) ;
154-
218+
155219 img . width = 14 ;
156220 img . style . paddingRight = '2px' ;
157221
@@ -168,94 +232,48 @@ class SpellCompendium {
168232 switch ( S ) {
169233 case 0 :
170234 div . value = S + 1 ;
171- tag_set . add ( tag ) ;
235+ SpellCompendium . tagSelection . add ( tag ) ;
172236 break ;
173237 case 1 :
174238 div . value = 0 ;
175- tag_set . delete ( tag ) ;
239+ SpellCompendium . tagSelection . delete ( tag ) ;
176240 break ;
177241 }
178- render_callback ( ) ;
242+ SpellCompendium . generateSpellTable ( ) ;
179243 }
180244 } ) ;
181245 }
182246
183247 static render ( ) {
184- const compendiumLeft = document . getElementById ( 'compendium_left' ) ;
185- const compendiumRight = document . getElementById ( 'compendium_right' ) ;
186- const compendiumSchoolList = document . getElementById ( 'left_school_tags' ) ;
187- const compendiumTagList = document . getElementById ( 'left_regular_tags' ) ;
188-
189- const tag_list = { } ;
190- const functional_tag_list = { } ;
191- const school_tag_list = { } ;
192-
193- const functional_tags = {
194- Cantrip : 'When cast, this spell is treated as a tier 1 spell in all regards, including MP cost.' ,
195- Concentration : 'You need to concentrate on this spell. Taking damage forces you to make a Constitution saving throw against DC 10 or half the damage done, whichever is higher. On a failure, the spell ends. When you cast a spell with Concentration while you are concentrating on a different spell, the first spell ends. You lose concentration if you are at 0 hit points.' ,
196- Delayed : 'You can pay for this spell's AP cost over multiple turns. While you have at least 1 AP set towards the spell, you are concentrating on the spell.' ,
197- Forbidden : 'You can't learn this spell normally. You need a general talent that automatically unlocks these spells for you once taken.' ,
198- Mastery : 'If you have all the tags for this spell, reduce the MP cost of the spell by two tiers.' ,
199- Potent : 'You can cast this spell at a higher tier for an increased effect.' ,
200- Sign : 'This spell creates a field around you that does not move. It ends if you leave the field or cast another Sign spell.' ,
201- Ritual : 'This spell takes too much time to cast during combat.' ,
202- Silent : 'You do not need to speak to cast this spell.' ,
203- Still : 'You do not need to move to cast this spell.' ,
204- Deprecated : 'This spell is considered for removal. Please do not select this spell during playtesting.' ,
205- } ;
206- const school_tags = [ 'Conjuration' , 'Evocation' , 'Transmutation' , 'Necromancy' , 'Abjuration' , 'Enchantment' , 'Illusion' , 'Divination' , 'Forbidden' ] ;
207-
208- SpellDatabase . forEach ( spell =>
209- spell . tags . forEach ( tag => {
210- if ( tag . includes ( 'Forbidden' ) ) {
211- if ( ! tag_list [ tag ] ) tag_list [ tag ] = 1 ;
212- else tag_list [ tag ] += 1 ;
213- } else if ( Object . keys ( functional_tags ) . includes ( tag ) ) {
214- if ( ! functional_tag_list [ tag ] ) functional_tag_list [ tag ] = 1 ;
215- else functional_tag_list [ tag ] += 1 ;
216- } else if ( school_tags . includes ( tag ) ) {
217- if ( ! school_tag_list [ tag ] ) school_tag_list [ tag ] = 1 ;
218- else school_tag_list [ tag ] += 1 ;
219- } else {
220- if ( ! tag_list [ tag ] ) tag_list [ tag ] = 1 ;
221- else tag_list [ tag ] += 1 ;
222- }
223- } )
224- ) ;
225-
226- const tag_select = new Set ( ) ;
227- const tier_select = new Set ( ) ;
228- const gen_spelltable = ( ) => SpellCompendium . generate_brief_spell_table ( SpellDatabase , tag_select , tier_select , functional_tags ) ;
229-
230248 // TAGS
231- SpellCompendium . tag_buttons ( school_tag_list , tag_select , compendiumSchoolList , gen_spelltable ) ;
232- SpellCompendium . tag_buttons ( tag_list , tag_select , compendiumTagList , gen_spelltable ) ;
233-
249+ SpellCompendium . tagButtons ( SpellCompendium . TagCounts . School , SpellCompendium . UI . SchoolList ) ;
250+ SpellCompendium . tagButtons ( SpellCompendium . TagCounts . Regular , SpellCompendium . UI . TagList ) ;
251+
234252 // TIERS
235253 for ( let i = 1 ; i <= 9 ; i ++ ) {
236- const tier_button = document . querySelector ( `#tier${ i } ` ) ;
237- tier_button . dataset . i = i ;
254+ const tierButton = document . querySelector ( `#tier${ i } ` ) ;
255+ tierButton . dataset . i = i ;
238256 const tier = i ;
239- tier_button . onclick = function ( ) {
240- const S = parseInt ( tier_button . value ) ;
257+ tierButton . onclick = function ( ) {
258+ const S = parseInt ( tierButton . value ) ;
241259 switch ( S ) {
242260 case 0 :
243- tier_button . value = S + 1 ;
244- tier_select . add ( tier ) ;
261+ tierButton . value = S + 1 ;
262+ SpellCompendium . tierSelection . add ( tier ) ;
245263 break ;
246264 case 1 :
247- tier_button . value = 0 ;
248- tier_select . delete ( tier ) ;
265+ tierButton . value = 0 ;
266+ SpellCompendium . tierSelection . delete ( tier ) ;
249267 break ;
250268 }
251- gen_spelltable ( ) ;
269+ SpellCompendium . generateSpellTable ( ) ;
252270 }
253271 }
254272
255- compendiumRight . appendChild ( SpellCompendium . spellCard ( SpellDatabase [ 0 ] , functional_tags ) ) ;
256- gen_spelltable ( ) ;
257-
258- const downloadButton = compendiumRight
273+ SpellCompendium . UI . RightDiv . appendChild ( SpellCompendium . spellCard ( SpellDatabase [ 0 ] , SpellCompendium . TagDescriptions . Functional ) ) ;
274+ SpellCompendium . generateSpellTable ( ) ;
275+
276+ const downloadButton = SpellCompendium . UI . RightDiv
259277 . appendChild ( document . createElement ( 'center' ) )
260278 . appendChild ( document . createElement ( 'button' ) ) ;
261279 downloadButton . textContent = "SAVE (.png)" ;
0 commit comments