[Bug] Nicknames not properly sanitized (#5537)

* Fix #5082: Nicknames not properly sanitized
When a player changes the name of the pokemon
to one that uses one of the following combination
of letters: "@c{}", "@s{}", "@d{}", "@f{}" and "$"
the game shows the name of the pokemon incorrectly in a battle.
Changes made:
- on message-ui-handler.ts file I updated the "showTextInternal"
function to get the original name of the pokemon
or pokemons (in case it's a double battle) saving it in a list
named "pokename" and change it in the text for their
correspondent placeholder which is saved in the list "repname"
(e.g "#POKEMON1" for the first pokemon and "#POKEMON2" for the
second pokemon). After the text is properly modified because
of the special characters ("@c{}", "@s{}", "@d{}", "@f{}")
the name of the pokemons is replaced to it's original value.
- on message-phase.ts file I updated the "start" function to use a
similar approach but only change the pokemon name to it's original
form after the "pageIndex" (which checks the index of the "$")
is updated, so the text is cut properly.
- on ui.ts file I updated the "showtext" function to use same
approach of the previous files, ensuring that the pokemon names
were only replaced back to their original values after all text
processing on "$" was completed.

* Replace `let` with `const`

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
Matilde Simões 2025-03-19 22:01:33 +00:00 committed by GitHub
parent b2848af899
commit a1a6b0dd5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 41 additions and 10 deletions

View File

@ -28,7 +28,17 @@ export class MessagePhase extends Phase {
super.start();
if (this.text.indexOf("$") > -1) {
const pokename: string[] = [];
const repname = [ "#POKEMON1", "#POKEMON2" ];
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
pokename.push(globalScene.getPlayerField()[p].getNameToRender());
this.text = this.text.split(pokename[p]).join(repname[p]);
}
const pageIndex = this.text.indexOf("$");
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
this.text = this.text.split(repname[p]).join(pokename[p]);
}
if (pageIndex !== -1) {
globalScene.unshiftPhase(
new MessagePhase(
this.text.slice(pageIndex + 1),
@ -40,6 +50,7 @@ export class MessagePhase extends Phase {
);
this.text = this.text.slice(0, pageIndex).trim();
}
}
if (this.speaker) {
globalScene.ui.showDialogue(

View File

@ -76,6 +76,12 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const fadeMap = new Map<number, number>();
const actionPattern = /@(c|d|s|f)\{(.*?)\}/;
let actionMatch: RegExpExecArray | null;
const pokename: string[] = [];
const repname = [ "#POKEMON1", "#POKEMON2" ];
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
pokename.push(globalScene.getPlayerField()[p].getNameToRender());
text = text.split(pokename[p]).join(repname[p]);
}
while ((actionMatch = actionPattern.exec(text))) {
switch (actionMatch[1]) {
case "c":
@ -94,6 +100,9 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
text = text.slice(0, actionMatch.index) + text.slice(actionMatch.index + actionMatch[2].length + 4);
}
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
text = text.split(repname[p]).join(pokename[p]);
}
if (text) {
// Predetermine overflow line breaks to avoid words breaking while displaying
const textWords = text.split(" ");

View File

@ -328,17 +328,28 @@ export default class UI extends Phaser.GameObjects.Container {
prompt?: boolean | null,
promptDelay?: number | null,
): void {
const pokename: string[] = [];
const repname = [ "#POKEMON1", "#POKEMON2" ];
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
pokename.push(globalScene.getPlayerField()[p].getNameToRender());
text = text.split(pokename[p]).join(repname[p]);
}
if (prompt && text.indexOf("$") > -1) {
const messagePages = text.split(/\$/g).map(m => m.trim());
// biome-ignore lint/complexity/useOptionalChain: optional chain would change this to be null instead of undefined.
let showMessageAndCallback = () => callback && callback();
for (let p = messagePages.length - 1; p >= 0; p--) {
const originalFunc = showMessageAndCallback;
messagePages[p] = messagePages[p].split(repname[0]).join(pokename[0]);
messagePages[p] = messagePages[p].split(repname[1]).join(pokename[1]);
showMessageAndCallback = () => this.showText(messagePages[p], null, originalFunc, null, true);
}
showMessageAndCallback();
} else {
const handler = this.getHandler();
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
text = text.split(repname[p]).join(pokename[p]);
}
if (handler instanceof MessageUiHandler) {
(handler as MessageUiHandler).showText(text, delay, callback, callbackDelay, prompt, promptDelay);
} else {