@@ -9,6 +9,7 @@ import { Loader } from '../data/loader';
99import { Hitbox } from '../models/hitbox' ;
1010import { versionNumber } from '../meta-data' ;
1111import { getMoveLink } from '../utils/fightcore-link' ;
12+ import { processDuplicateHits , processDuplicateHitboxesForCrouchCancel } from '../utils/hitbox-utils' ;
1213
1314export abstract class KnockbackEmbedCreator extends BaseEmbedCreator {
1415 constructor ( private knockbackTarget : number , private longTerm : string , private shortTerm : string ) {
@@ -40,80 +41,94 @@ export abstract class KnockbackEmbedCreator extends BaseEmbedCreator {
4041 const characterEmote = CharacterEmoji . getEmoteId ( character . normalizedName ) ;
4142 const targetEmote = CharacterEmoji . getEmoteId ( target . normalizedName ) ;
4243 embedBuilder . setTitle ( `${ characterEmote } ${ character . name } - ${ move . name } vs ${ target . name } ${ targetEmote } ` ) ;
43- for ( const hitbox of move . hitboxes . sort ( this . orderHitboxes ) ) {
44- if ( hitbox . angle > 179 && hitbox . angle != 361 ) {
45- hitboxMap . set ( hitbox . name , `Can not be ${ this . shortTerm } due to angle being higher than 179 (${ hitbox . angle } )` ) ;
46- } else if ( hitbox . angle === 0 ) {
47- hitboxMap . set ( hitbox . name , `Can not be ${ this . shortTerm } due to angle being 0` ) ;
48- } else if ( hitbox . setKnockback ) {
49- const canBeCanceled = ! CrouchCancelCalculator . meetsKnockbackTarget ( hitbox , target , this . knockbackTarget ) ;
50- hitboxMap . set ( hitbox . name , `Can ${ canBeCanceled ? 'always' : 'not' } be ${ this . shortTerm } ` ) ;
51- } else {
52- const crouchCancelPercentage = this . getCrouchCancelPercentageOrImpossible ( hitbox , target ) ;
53- hitboxMap . set ( hitbox . name , crouchCancelPercentage ) ;
54- }
44+
45+ const hits = processDuplicateHits ( processDuplicateHitboxesForCrouchCancel ( move . hits ) ) ;
46+ if ( hits . length > 20 ) {
47+ return this . createErrorEmbed ( embedBuilder ) ;
5548 }
49+
5650 let result = `${ this . longTerm } breaks at the following percentages for each hitbox.\n` ;
57- for ( const keyValuePair of hitboxMap ) {
58- result += InfoLine . createLineWithTitle ( keyValuePair [ 0 ] , keyValuePair [ 1 ] ) + '\n' ;
51+ for ( const hit of hits ) {
52+ const name = hit . name ? hit . name : `Frames ${ hit . aggregatedStart } - ${ hit . aggregatedEnd } ` ;
53+
54+ for ( const hitbox of hit . hitboxes . sort ( this . orderHitboxes ) ) {
55+ if ( hitbox . angle > 179 && hitbox . angle != 361 ) {
56+ hitboxMap . set (
57+ name + ' - ' + hitbox . name ,
58+ `Can not be ${ this . shortTerm } due to angle being higher than 179 (${ hitbox . angle } )`
59+ ) ;
60+ } else if ( hitbox . angle === 0 ) {
61+ hitboxMap . set ( name + ' - ' + hitbox . name , `Can not be ${ this . shortTerm } due to angle being 0` ) ;
62+ } else if ( hitbox . setKnockback ) {
63+ const canBeCanceled = ! CrouchCancelCalculator . meetsKnockbackTarget ( hitbox , target , this . knockbackTarget ) ;
64+ hitboxMap . set ( name + ' - ' + hitbox . name , `Can ${ canBeCanceled ? 'always' : 'not' } be ${ this . shortTerm } ` ) ;
65+ } else {
66+ const crouchCancelPercentage = this . getCrouchCancelPercentageOrImpossible ( hitbox , target ) ;
67+ hitboxMap . set ( name + ' - ' + hitbox . name , crouchCancelPercentage ) ;
68+ }
69+ }
70+
71+ for ( const keyValuePair of hitboxMap ) {
72+ result += InfoLine . createLineWithTitle ( keyValuePair [ 0 ] , keyValuePair [ 1 ] ) + '\n' ;
73+ }
5974 }
75+
6076 embedBuilder . addFields ( { name : `${ this . longTerm } percentage` , value : result } ) ;
6177 return [ embedBuilder ] ;
6278 }
6379
6480 private createForAll ( character : Character , move : Move , embedBuilder : EmbedBuilder , dataLoader : Loader ) : EmbedBuilder [ ] {
6581 const characterEmote = CharacterEmoji . getEmoteId ( character . normalizedName ) ;
6682 embedBuilder . setTitle ( `${ characterEmote } ${ character . name } - ${ move . name } ` ) ;
67- for ( const hitbox of move . hitboxes . sort ( this . orderHitboxes ) ) {
68- if ( hitbox . angle > 179 && hitbox . angle != 361 ) {
69- embedBuilder . addFields ( {
70- name : hitbox . name ,
71- value : `Can not be ${ this . shortTerm } due to angle being higher than 179 (${ hitbox . angle } )` ,
72- } ) ;
73- continue ;
74- } else if ( hitbox . angle === 0 ) {
75- embedBuilder . addFields ( { name : hitbox . name , value : `Can not be ${ this . shortTerm } due to angle being 0` } ) ;
76- continue ;
77- } else if ( hitbox . setKnockback ) {
78- this . addSetKnockbackField ( embedBuilder , hitbox , dataLoader ) ;
79- continue ;
80- }
8183
82- const hitboxMap = new Map < Character , string > ( ) ;
83- for ( const target of dataLoader . data
84+ const hits = processDuplicateHits ( processDuplicateHitboxesForCrouchCancel ( move . hits ) ) ;
85+ if ( hits . length > 20 ) {
86+ return this . createErrorEmbed ( embedBuilder ) ;
87+ }
88+ for ( const hit of hits ) {
89+ const hitboxes = hit . hitboxes ;
90+ const characters = dataLoader . data
8491 . filter ( ( character ) => character . characterStatistics . weight > 0 )
85- . sort ( this . orderCharacters ) ) {
86- const crouchCancelPercentage = this . getCrouchCancelPercentageOrImpossible ( hitbox , target ) ;
87- hitboxMap . set ( target , crouchCancelPercentage ) ;
88- }
92+ . sort ( this . orderCharacters ) ;
93+ for ( const hitbox of hitboxes ) {
94+ const name = hit . name ? hit . name : `Frames ${ hit . aggregatedStart } - ${ hit . aggregatedEnd } ` ;
95+
96+ if ( hitbox . angle > 179 && hitbox . angle != 361 ) {
97+ embedBuilder . addFields ( {
98+ name : name + ' - ' + hitbox . name ,
99+ value : `Can not be ${ this . shortTerm } due to angle being higher than 179 (${ hitbox . angle } )` ,
100+ } ) ;
101+ continue ;
102+ } else if ( hitbox . angle === 0 ) {
103+ embedBuilder . addFields ( {
104+ name : name + ' - ' + hitbox . name ,
105+ value : `Can not be ${ this . shortTerm } due to angle being 0` ,
106+ } ) ;
107+ continue ;
108+ } else if ( hitbox . setKnockback ) {
109+ this . addSetKnockbackField ( embedBuilder , hitbox , dataLoader , name ) ;
110+ continue ;
111+ }
89112
90- let fieldText = '' ;
91- let iterator = 0 ;
92- for ( const keyValuePair of hitboxMap ) {
93- const emote = CharacterEmoji . getEmoteId ( keyValuePair [ 0 ] . normalizedName ) ;
94- fieldText += `${ emote } ${ keyValuePair [ 1 ] } ` ;
95- iterator ++ ;
96- if ( iterator === 4 ) {
97- iterator = 0 ;
98- fieldText += '\n' ;
113+ let fieldText = '' ;
114+ let iterator = 0 ;
115+ for ( const character of characters ) {
116+ const emote = CharacterEmoji . getEmoteId ( character . normalizedName ) ;
117+ fieldText += `${ emote } ${ this . getCrouchCancelPercentageOrImpossible ( hitbox , character ) } ` ;
118+ iterator ++ ;
119+ if ( iterator === 4 ) {
120+ iterator = 0 ;
121+ fieldText += '\n' ;
122+ }
99123 }
124+ embedBuilder . addFields ( { name : name + ' - ' + hitbox . name , value : fieldText , inline : false } ) ;
100125 }
101-
102- embedBuilder . addFields ( { name : hitbox . name , value : fieldText } ) ;
103126 }
127+
104128 // Discord has a max length size to the embed.
105129 // With a large amount of hitboxes (like G&W)
106130 if ( embedBuilder . length >= 6000 ) {
107- const errorEmbed = this . baseEmbed ( ) ;
108- errorEmbed . setColor ( Colors . DarkRed ) ;
109- errorEmbed . setTitle ( embedBuilder . data . title ! ) ;
110- errorEmbed . addFields ( {
111- name : 'Too many hitboxes' ,
112- value : `This move has too many hitboxes to be displayed on Discord, either supply a target character or visit our [website](${ embedBuilder
113- . data . url ! } )`,
114- } ) ;
115-
116- return [ errorEmbed ] ;
131+ return this . createErrorEmbed ( embedBuilder ) ;
117132 }
118133 return [ embedBuilder ] ;
119134 }
@@ -135,7 +150,7 @@ export abstract class KnockbackEmbedCreator extends BaseEmbedCreator {
135150 return hitboxOne . name . localeCompare ( hitboxTwo . name , undefined , { numeric : true , sensitivity : 'base' } ) ;
136151 }
137152
138- private addSetKnockbackField ( embedBuilder : EmbedBuilder , hitbox : Hitbox , dataLoader : Loader ) : void {
153+ private addSetKnockbackField ( embedBuilder : EmbedBuilder , hitbox : Hitbox , dataLoader : Loader , hitName : string ) : void {
139154 const succeedsArray : Character [ ] [ ] = [ [ ] , [ ] ] ;
140155 for ( const character of dataLoader . data
141156 . filter ( ( character ) => character . characterStatistics . weight > 0 )
@@ -149,13 +164,13 @@ export abstract class KnockbackEmbedCreator extends BaseEmbedCreator {
149164
150165 if ( succeedsArray [ 0 ] . length == 0 ) {
151166 embedBuilder . addFields ( {
152- name : hitbox . name ,
167+ name : hitName + ' - ' + hitbox . name ,
153168 value : `Can never be ${ this . shortTerm } by all characters.` ,
154169 } ) ;
155170 return ;
156171 } else if ( succeedsArray [ 1 ] . length == 0 ) {
157172 embedBuilder . addFields ( {
158- name : hitbox . name ,
173+ name : hitName + ' - ' + hitbox . name ,
159174 value : `Can always be ${ this . shortTerm } by all characters.` ,
160175 } ) ;
161176 return ;
@@ -169,8 +184,21 @@ export abstract class KnockbackEmbedCreator extends BaseEmbedCreator {
169184 succeedsArray [ 1 ] . map ( ( character ) => CharacterEmoji . getEmoteId ( character . normalizedName ) ) . join ( ' ' ) ;
170185
171186 embedBuilder . addFields ( {
172- name : hitbox . name ,
187+ name : hitName + ' - ' + hitbox . name ,
173188 value : canText + '\n' + canNotText ,
174189 } ) ;
175190 }
191+
192+ private createErrorEmbed ( embedBuilder : EmbedBuilder ) : EmbedBuilder [ ] {
193+ const errorEmbed = this . baseEmbed ( ) ;
194+ errorEmbed . setColor ( Colors . DarkRed ) ;
195+ errorEmbed . setTitle ( embedBuilder . data . title ! ) ;
196+ errorEmbed . addFields ( {
197+ name : 'Too many hitboxes' ,
198+ value : `This move has too many hitboxes to be displayed on Discord, either supply a target character or visit our [website](${ embedBuilder
199+ . data . url ! } )`,
200+ } ) ;
201+
202+ return [ errorEmbed ] ;
203+ }
176204}
0 commit comments