Skip to content

Commit 8f905aa

Browse files
committed
Setting up crouch cancel command
1 parent 06d6c76 commit 8f905aa

File tree

8 files changed

+381
-237
lines changed

8 files changed

+381
-237
lines changed

package-lock.json

Lines changed: 222 additions & 215 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
},
2727
"homepage": "https://github.com/FightCore/bot-js#readme",
2828
"dependencies": {
29-
"@apollo/client": "^3.10.4",
29+
"@apollo/client": "^3.10.5",
3030
"@datalust/winston-seq": "^2.0.0",
31-
"@elastic/elasticsearch": "^8.13.1",
32-
"axios": "^1.6.8",
33-
"discord.js": "^14.15.2",
31+
"@elastic/elasticsearch": "^8.14.0",
32+
"axios": "^1.7.2",
33+
"discord.js": "^14.15.3",
3434
"dotenv": "^16.4.5",
3535
"inversify": "^6.0.2",
3636
"jaro-winkler-typescript": "^1.0.1",
@@ -39,12 +39,12 @@
3939
},
4040
"devDependencies": {
4141
"@jest/globals": "^29.7.0",
42-
"@types/node": "^16.18.97",
42+
"@types/node": "^16.18.100",
4343
"@typescript-eslint/eslint-plugin": "^6.21.0",
4444
"@typescript-eslint/parser": "^6.21.0",
4545
"eslint": "^8.57.0",
4646
"jest": "^29.7.0",
47-
"ts-jest": "^29.1.2",
47+
"ts-jest": "^29.1.5",
4848
"typescript": "^5.4.5"
4949
}
5050
}

src/assets/framedata.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,111 @@
1-
import { EmbedBuilder } from 'discord.js';
1+
import { Colors, EmbedBuilder } from 'discord.js';
22
import { CrouchCancelCalculator } from '../calculation/crouch-cancel-calculator';
33
import { Character } from '../models/character';
44
import { Move } from '../models/move';
55
import { BaseEmbedCreator } from './base-embed-creator';
66
import { InfoLine } from './formatting/info-line';
7+
import { CharacterEmoji } from '../utils/character-emoji';
8+
import { Loader } from '../data/loader';
79

810
export class CrouchCancelEmbedCreator extends BaseEmbedCreator {
9-
public static create(character: Character, move: Move, target: Character | undefined): EmbedBuilder[] {
11+
public static create(character: Character, move: Move, target: Character | undefined, dataLoader: Loader): EmbedBuilder[] {
1012
const embedCreator = this.baseEmbed();
1113

12-
const hitboxMap = new Map<string, string>();
13-
if (target) {
14-
embedCreator.setTitle(`${character.name} - ${move.name} vs ${target.name}`);
14+
if (move.gifUrl) {
15+
embedCreator.setImage(move.gifUrl);
1516
} else {
16-
embedCreator.setTitle(`${character.name} - ${move.name}`);
17+
embedCreator.addFields({
18+
name: 'No GIF available',
19+
value: 'There is no GIF available for this move. Visit https://www.fightcore.gg to help us out.',
20+
});
21+
}
22+
embedCreator.setURL(
23+
`https://fightcore.gg/characters/${character.fightCoreId}/${character.normalizedName}/moves/${move.id}/${move.normalizedName}/?utm_source=fightcore_bot`
24+
);
25+
26+
if (target) {
27+
return this.createForTarget(character, move, target, embedCreator);
1728
}
29+
30+
return this.createForAll(character, move, embedCreator, dataLoader);
31+
}
32+
33+
private static createForTarget(
34+
character: Character,
35+
move: Move,
36+
target: Character,
37+
embedBuilder: EmbedBuilder
38+
): EmbedBuilder[] {
39+
const hitboxMap = new Map<string, string>();
40+
const characterEmote = CharacterEmoji.getEmoteId(character.normalizedName);
41+
const targetEmote = CharacterEmoji.getEmoteId(target.normalizedName);
42+
embedBuilder.setTitle(`${characterEmote} ${character.name} - ${move.name} vs ${target.name} ${targetEmote} `);
1843
for (const hitbox of move.hitboxes) {
19-
const crouchCancelPercentage = CrouchCancelCalculator.calculateCrouchCancel(hitbox, target!).toFixed(2);
20-
hitboxMap.set(hitbox.name, crouchCancelPercentage);
44+
if (hitbox.angle > 179 && hitbox.angle != 361) {
45+
hitboxMap.set(hitbox.name, `Can not be CCed due to angle being higher than 179 (${hitbox.angle})`);
46+
} else if (hitbox.angle === 0) {
47+
hitboxMap.set(hitbox.name, `Can not be CCed due to angle being 0`);
48+
} else {
49+
const crouchCancelPercentage = CrouchCancelCalculator.calculateCrouchCancel(hitbox, target).toFixed(2);
50+
hitboxMap.set(hitbox.name, crouchCancelPercentage);
51+
}
2152
}
2253
let result = 'Crouch cancel breaks at the following percentages for each hitbox.\n';
2354
for (const keyValuePair of hitboxMap) {
2455
result += InfoLine.createLineWithTitle(keyValuePair[0], keyValuePair[1]) + '\n';
2556
}
26-
embedCreator.setDescription(result);
57+
embedBuilder.addFields({ name: 'Crouch Cancel Percentage', value: result });
58+
return [embedBuilder];
59+
}
60+
61+
private static createForAll(character: Character, move: Move, embedBuilder: EmbedBuilder, dataLoader: Loader): EmbedBuilder[] {
62+
const characterEmote = CharacterEmoji.getEmoteId(character.normalizedName);
63+
embedBuilder.setTitle(`${characterEmote} ${character.name} - ${move.name}`);
64+
65+
for (const hitbox of move.hitboxes) {
66+
if (hitbox.angle > 179 && hitbox.angle != 361) {
67+
embedBuilder.addFields({
68+
name: hitbox.name,
69+
value: `Can not be CCed due to angle being higher than 179 (${hitbox.angle})`,
70+
});
71+
continue;
72+
} else if (hitbox.angle === 0) {
73+
embedBuilder.addFields({ name: hitbox.name, value: `Can not be CCed due to angle being 0` });
74+
continue;
75+
}
76+
77+
const hitboxMap = new Map<Character, string>();
78+
for (const target of dataLoader.data) {
79+
const crouchCancelPercentage = CrouchCancelCalculator.calculateCrouchCancel(hitbox, target).toFixed(2);
80+
hitboxMap.set(target, crouchCancelPercentage);
81+
}
2782

28-
return [embedCreator];
83+
let fieldText = '';
84+
let iterator = 0;
85+
for (const keyValuePair of hitboxMap) {
86+
const emote = CharacterEmoji.getEmoteId(keyValuePair[0].normalizedName);
87+
fieldText += `${emote} ${keyValuePair[1]}% `;
88+
iterator++;
89+
if (iterator === 4) {
90+
iterator = 0;
91+
fieldText += '\n';
92+
}
93+
}
94+
95+
embedBuilder.addFields({ name: hitbox.name, value: fieldText });
96+
}
97+
if (embedBuilder.length >= 6000) {
98+
const errorEmbed = this.baseEmbed();
99+
errorEmbed.setColor(Colors.DarkRed);
100+
errorEmbed.setTitle(embedBuilder.data.title!);
101+
errorEmbed.addFields({
102+
name: 'Too many hitboxes',
103+
value: `This move has too many hitboxes to be displayed on Discord, either supply a target character or visit our [website](${embedBuilder
104+
.data.url!})`,
105+
});
106+
107+
return [errorEmbed];
108+
}
109+
return [embedBuilder];
29110
}
30111
}

src/embeds/move-embed-creator.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,21 @@ export class MoveEmbedCreator extends BaseEmbedCreator {
9898

9999
const moveEmbed = this.baseEmbed()
100100
.setTitle(`${this.character.name} - ${this.move.name}`)
101-
.setURL(this.move.source)
101+
.setURL(
102+
`https://fightcore.gg/characters/${this.character.normalizedName}/moves/${this.move.normalizedName}?referer=fightcore_bot`
103+
)
102104
.setColor(this.embedColor)
103-
.setImage(`https://i.fightcore.gg/melee/moves/${this.character.normalizedName}/${this.move.normalizedName}.gif`)
104105
.addFields(moveEmbedFields);
105106

107+
if (this.move.gifUrl) {
108+
moveEmbed.setImage(this.move.gifUrl);
109+
} else {
110+
moveEmbed.addFields({
111+
name: 'No GIF available',
112+
value: 'There is no GIF available for this move. Visit https://www.fightcore.gg to help us out.',
113+
});
114+
}
115+
106116
// Return the embed inside of an array.
107117
// Multiple embeds could be created and returned but this is not needed for this use case.
108118
return [moveEmbed];

src/interactions/command-interaction-handler.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,16 @@ import { SearchResultType } from '../models/search/search-result-type';
1111
import { MessageCleaner } from '../utils/message-cleaner';
1212
import { BaseInteractionHandler } from './base-interaction-handler';
1313
import { CrouchCancelEmbedCreator } from '../embeds/crouch-cancel-embed-creator';
14+
import { Loader } from '../data/loader';
1415

1516
@injectable()
1617
export class CommandInteractionHandler extends BaseInteractionHandler {
17-
constructor(search: Search, @inject(Symbols.Logger) logger: Logger, failureStore: FailureStore) {
18+
constructor(
19+
search: Search,
20+
@inject(Symbols.Logger) logger: Logger,
21+
failureStore: FailureStore,
22+
@inject(Loader) private loader: Loader
23+
) {
1824
super(search, logger, failureStore);
1925
}
2026
async handle(interaction: CommandInteraction): Promise<void> {
@@ -37,15 +43,15 @@ export class CommandInteractionHandler extends BaseInteractionHandler {
3743
return;
3844
}
3945

40-
const target = interaction.options.get('target', true).value;
46+
const target = interaction.options.get('target', false)?.value;
4147
const targetCharacter = this.search.searchCharacter([target as string]);
4248

4349
if (target && !targetCharacter) {
4450
await this.sendNoMoveFoundErrorToInteraction(interaction, `${target} `, new SearchResult(SearchResultType.NotFound));
4551
return;
4652
}
4753

48-
const embeds = CrouchCancelEmbedCreator.create(searchResult.character, searchResult.move, targetCharacter);
54+
const embeds = CrouchCancelEmbedCreator.create(searchResult.character, searchResult.move, targetCharacter, this.loader);
4955
await interaction.reply({
5056
embeds: embeds,
5157
});

src/models/move.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ export interface Move {
1919
percent?: string;
2020
source: string;
2121
landingFallSpecialLag: number;
22+
gifUrl: string;
2223
}

src/utils/character-emoji.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export class CharacterEmoji {
2+
static getEmoteId(normalizedName: string): string | undefined {
3+
const emotes = [
4+
{ id: '1253321851405467710', name: 'bowser' },
5+
{ id: '1253321852504510464', name: 'captainfalcon' },
6+
{ id: '1253321853536047225', name: 'donkeykong' },
7+
{ id: '1253321854924357674', name: 'drmario' },
8+
{ id: '1253321856753209426', name: 'falco' },
9+
{ id: '1253321858057769111', name: 'fwireframe' },
10+
{ id: '1253321859181842442', name: 'fox' },
11+
{ id: '1253321860721016832', name: 'ganondorf' },
12+
{ id: '1253321863988383764', name: 'jigglypuff' },
13+
{ id: '1253321866840510555', name: 'link' },
14+
{ id: '1253321868946182164', name: 'luigi' },
15+
{ id: '1253321872628514868', name: 'marth' },
16+
{ id: '1253321876722421882', name: 'mrgame&watch' },
17+
{ id: '1253321880006299699', name: 'peach' },
18+
{ id: '1253321883663859722', name: 'pikachu' },
19+
{ id: '1253321888068010064', name: 'samus' },
20+
{ id: '1253321891884695675', name: 'yoshi' },
21+
{ id: '1253321895458111568', name: 'zelda' },
22+
{ id: '1253322051796598797', name: 'iceclimbers' },
23+
{ id: '1253322053424124065', name: 'kirby' },
24+
{ id: '1253322054523162634', name: 'mario' },
25+
{ id: '1253322178330628148', name: 'mewtwo' },
26+
{ id: '1253322179169353809', name: 'ness' },
27+
{ id: '1253322180473786561', name: 'pichu' },
28+
{ id: '1253322182118080512', name: 'roy' },
29+
{ id: '1253322183569178705', name: 'sheik' },
30+
{ id: '1253322184290467861', name: 'younglink' },
31+
];
32+
const id = emotes.find((emote) => emote.name === normalizedName)?.id;
33+
if (id) {
34+
return `<:a:${id}>`;
35+
}
36+
37+
return undefined;
38+
}
39+
}

0 commit comments

Comments
 (0)