[Accessibility] Tweak Pause menu TTS functions (#3098)

* tweak kaleido tts

* tts announce what items are assigned to buttons; announce page on open
This commit is contained in:
Adam Bird 2023-08-13 11:41:04 -04:00 committed by GitHub
parent 05dde45a75
commit 78790fe8aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 291 additions and 75 deletions

View File

@ -1,24 +1,35 @@
{ {
"health": "health $0", "health": "Health - $0 Hearts",
"magic": "magic $0", "magic": "Magic - $0",
"rupees": "rupees $0", "rupees": "Rupees - $0",
"0": "Deku Stick $0", "floor": "Floor $0",
"1": "Deku Nut $0", "basement": "Basement $0",
"2": "Bomb $0", "item_menu": "Select Item",
"3": "Fairy Bow $0", "map_menu": "Map - $0",
"quest_menu": "Quest Status",
"equip_menu": "Equipment",
"overworld": "Overworld",
"equipped": "$0 - Equipped",
"save_prompt": "Would you like to save?",
"game_saved": "Game saved",
"assigned_to": "Assigned to $0",
"0": "Deku Stick - $0",
"1": "Deku Nut - $0",
"2": "Bomb - $0",
"3": "Fairy Bow - $0",
"4": "Fire Arrow", "4": "Fire Arrow",
"5": "Din's Fire", "5": "Din's Fire",
"6": "Fairy Slingshot $0", "6": "Fairy Slingshot - $0",
"7": "Fairy Ocarina", "7": "Fairy Ocarina",
"8": "Ocarina of Time", "8": "Ocarina of Time",
"9": "Bombchu $0", "9": "Bombchu - $0",
"10": "Hookshot", "10": "Hookshot",
"11": "Longshot", "11": "Longshot",
"12": "Ice Arrow", "12": "Ice Arrow",
"13": "Farore's Wind", "13": "Farore's Wind",
"14": "Boomerang", "14": "Boomerang",
"15": "Lens of Truth", "15": "Lens of Truth",
"16": "Magic Beans $0", "16": "Magic Beans - $0",
"17": "Megaton Hammer", "17": "Megaton Hammer",
"18": "Light Arrow", "18": "Light Arrow",
"19": "Nayru's Love", "19": "Nayru's Love",
@ -115,8 +126,8 @@
"110": "Zora Sapphire", "110": "Zora Sapphire",
"111": "Stone of Agony", "111": "Stone of Agony",
"112": "Gerudo's Card", "112": "Gerudo's Card",
"113": "Skulltula Token $0", "113": "Skulltula Token - $0",
"114": "Heart Container $0", "114": "Piece of Heart - $0",
"115": "Piece of Heart", "115": "Piece of Heart",
"116": "Boss Key", "116": "Boss Key",
"117": "Compass", "117": "Compass",
@ -124,7 +135,7 @@
"119": "Small Key", "119": "Small Key",
"120": "MAGIC SMALL", "120": "MAGIC SMALL",
"121": "MAGIC LARGE", "121": "MAGIC LARGE",
"122": "PIECE OF HEART 2", "122": "Biggoron's Sword",
"123": "INVALID 1", "123": "INVALID 1",
"124": "INVALID 2", "124": "INVALID 2",
"125": "INVALID 3", "125": "INVALID 3",
@ -217,4 +228,4 @@
"311": "Lon Lon Ranch", "311": "Lon Lon Ranch",
"312": "Question Mark", "312": "Question Mark",
"313": "Ganon's Castle" "313": "Ganon's Castle"
} }

View File

@ -1,24 +1,35 @@
{ {
"health": "vie $0", "health": "Vie - $0 Coeurs",
"magic": "magie $0", "magic": "Magie - $0",
"rupees": "rubis $0", "rupees": "Rubis - $0",
"0": "Bâton Mojo $0", "floor": "Étage $0",
"1": "Noix Mojo $0", "basement": "Sous-sol $0",
"2": "Bombes $0", "item_menu": "Inventaire",
"3": "Arc des Fées $0", "map_menu": "Carte - $0",
"quest_menu": "Statut de la quête",
"equip_menu": "Equipment",
"overworld": "Surmonde",
"equipped": "$0 - Équipé",
"save_prompt": "Voulez-vous sauvegarder?",
"game_saved": "Jeu sauvegardé",
"assigned_to": "Assigné au $0",
"0": "Bâton Mojo - $0",
"1": "Noix Mojo - $0",
"2": "Bombes - $0",
"3": "Arc des Fées - $0",
"4": "Flèche de Feu", "4": "Flèche de Feu",
"5": "Feu de Din", "5": "Feu de Din",
"6": "Lance-Pierre des Fées $0", "6": "Lance-Pierre des Fées - $0",
"7": "Ocarina des Fées", "7": "Ocarina des Fées",
"8": "Ocarina of Temps", "8": "Ocarina of Temps",
"9": "Missiles Teigneux $0", "9": "Missiles Teigneux - $0",
"10": "Grappin", "10": "Grappin",
"11": "Super Grappin", "11": "Super Grappin",
"12": "Flèche de Glace", "12": "Flèche de Glace",
"13": "Vent de Farore", "13": "Vent de Farore",
"14": "Boomerang", "14": "Boomerang",
"15": "Monocle de Vérité", "15": "Monocle de Vérité",
"16": "Haricot Magique $0", "16": "Haricot Magique - $0",
"17": "Masse des Titans", "17": "Masse des Titans",
"18": "Flèche de Lumière", "18": "Flèche de Lumière",
"19": "Amour de Nayru", "19": "Amour de Nayru",
@ -115,8 +126,8 @@
"110": "Saphir Zora", "110": "Saphir Zora",
"111": "Pierre de Souffrance", "111": "Pierre de Souffrance",
"112": "Carte Gerudo", "112": "Carte Gerudo",
"113": "Skulltula d'or $0", "113": "Skulltula d'or - $0",
"114": "Coeur d'Énergie $0", "114": "Quart de Coeur - $0",
"115": "Quart de Coeur", "115": "Quart de Coeur",
"116": "Clé d'or", "116": "Clé d'or",
"117": "Boussole", "117": "Boussole",
@ -124,7 +135,7 @@
"119": "Petite Clé", "119": "Petite Clé",
"120": "PETITE BOUTEILLE DE MAGIE", "120": "PETITE BOUTEILLE DE MAGIE",
"121": "GRANDE BOUTEILLE DE MAGIE", "121": "GRANDE BOUTEILLE DE MAGIE",
"122": "QUART DE COEUR 2", "122": "Épée de Biggoron",
"123": "INVALIDE 1", "123": "INVALIDE 1",
"124": "INVALIDE 2", "124": "INVALIDE 2",
"125": "INVALIDE 3", "125": "INVALIDE 3",
@ -217,4 +228,4 @@
"311": "Ranch Lon Lon", "311": "Ranch Lon Lon",
"312": "Point d'interrogation", "312": "Point d'interrogation",
"313": "Château de Ganon" "313": "Château de Ganon"
} }

View File

@ -1,24 +1,35 @@
{ {
"health": "Energie $0", "health": "Energie - $0 Herzen",
"magic": "Magie $0", "magic": "Magie - $0",
"rupees": "Rubine $0", "rupees": "Rubine - $0",
"0": "Deku-Stab $0", "floor": "Etage $0",
"1": "Deku-Nuß $0", "basement": "Keller $0",
"2": "Bombe $0", "item_menu": "Gegenstände",
"3": "Feen-Bogen $0", "map_menu": "Karte - $0",
"quest_menu": "Quest Status",
"equip_menu": "Ausrüstung",
"overworld": "Überwelt",
"equipped": "$0 - Ausgerüstet",
"save_prompt": "Spielstand sichern?",
"game_saved": "Spielstand gesichert",
"assigned_to": "$0 zugeordnet",
"0": "Deku-Stab - $0",
"1": "Deku-Nuß - $0",
"2": "Bombe - $0",
"3": "Feen-Bogen - $0",
"4": "Feuer-Pfeil", "4": "Feuer-Pfeil",
"5": "Dins Feuerinferno", "5": "Dins Feuerinferno",
"6": "Feen-Schleuder $0", "6": "Feen-Schleuder - $0",
"7": "Feen-Okarina", "7": "Feen-Okarina",
"8": "Okarina der Zeit", "8": "Okarina der Zeit",
"9": "Krabbelmine $0", "9": "Krabbelmine - $0",
"10": "Fanghaken", "10": "Fanghaken",
"11": "Enterhaken", "11": "Enterhaken",
"12": "Eis-Pfeil", "12": "Eis-Pfeil",
"13": "Farores Donnersturm", "13": "Farores Donnersturm",
"14": "Bumerang", "14": "Bumerang",
"15": "Auge der Wahrheit", "15": "Auge der Wahrheit",
"16": "Wundererbsen $0", "16": "Wundererbsen - $0",
"17": "Stahlhammer", "17": "Stahlhammer",
"18": "Licht-Pfeil", "18": "Licht-Pfeil",
"19": "Nayrus Umarmung", "19": "Nayrus Umarmung",
@ -115,8 +126,8 @@
"110": "Zora-Saphir", "110": "Zora-Saphir",
"111": "Stein des Wissens", "111": "Stein des Wissens",
"112": "Gerudo-Paß", "112": "Gerudo-Paß",
"113": "Skulltula-Symbol $0", "113": "Skulltula-Symbol - $0",
"114": "Herzcontainer $0", "114": "Herzteil - $0",
"115": "Herzteil", "115": "Herzteil",
"116": "Master-Schlüssel", "116": "Master-Schlüssel",
"117": "Kompaß", "117": "Kompaß",
@ -124,7 +135,7 @@
"119": "Kleiner Schlüssel", "119": "Kleiner Schlüssel",
"120": "MAGIE KLEIN", "120": "MAGIE KLEIN",
"121": "MAGIE GROß", "121": "MAGIE GROß",
"122": "HERZTEIL 2", "122": "Biggoron-Schwert",
"123": "UNGÜLTIG 1", "123": "UNGÜLTIG 1",
"124": "UNGÜLTIG 2", "124": "UNGÜLTIG 2",
"125": "UNGÜLTIG 3", "125": "UNGÜLTIG 3",
@ -217,4 +228,4 @@
"311": "Lon Lon-Farm", "311": "Lon Lon-Farm",
"312": "Fragezeichen", "312": "Fragezeichen",
"313": "Teufelsturm" "313": "Teufelsturm"
} }

View File

@ -14,5 +14,11 @@
"input_button_c_left": "C Left", "input_button_c_left": "C Left",
"input_button_c_right": "C Right", "input_button_c_right": "C Right",
"input_analog_stick": "the Analog Stick", "input_analog_stick": "the Analog Stick",
"input_d_pad": "the D-Pad" "input_d_pad": "the D-Pad",
} "input_d_pad_up": "D-Pad Up",
"input_d_pad_down": "D-Pad Down",
"input_d_pad_left": "D-Pad Left",
"input_d_pad_right": "D-Pad Right",
"yes": "Yes",
"no": "No"
}

View File

@ -14,5 +14,11 @@
"input_button_c_left": "C Gauche", "input_button_c_left": "C Gauche",
"input_button_c_right": "C Droit", "input_button_c_right": "C Droit",
"input_analog_stick": "le Stick Analogique", "input_analog_stick": "le Stick Analogique",
"input_d_pad": "D-Pad" "input_d_pad": "D-Pad",
} "input_d_pad_up": "D-Pad Haut",
"input_d_pad_down": "D-Pad Bas",
"input_d_pad_left": "D-Pad Gauche",
"input_d_pad_right": "D-Pad Droit",
"yes": "Oui",
"no": "Non"
}

View File

@ -14,5 +14,11 @@
"input_button_c_left": "C Links", "input_button_c_left": "C Links",
"input_button_c_right": "C Rechts", "input_button_c_right": "C Rechts",
"input_analog_stick": "den Analog-Stick", "input_analog_stick": "den Analog-Stick",
"input_d_pad": "das Steuerkreuz" "input_d_pad": "das Steuerkreuz",
} "input_d_pad_up": "Steuerkreuz Oben",
"input_d_pad_down": "Steuerkreuz Unten",
"input_d_pad_left": "Steuerkreuz Links",
"input_d_pad_right": "Steuerkreuz Rechts",
"yes": "Ja",
"no": "Nein"
}

View File

@ -12,6 +12,7 @@
#include "soh/Enhancements/boss-rush/BossRush.h" #include "soh/Enhancements/boss-rush/BossRush.h"
extern "C" { extern "C" {
extern MapData* gMapData;
extern SaveContext gSaveContext; extern SaveContext gSaveContext;
extern PlayState* gPlayState; extern PlayState* gPlayState;
} }
@ -190,28 +191,109 @@ void RegisterOnInterfaceUpdateHook() {
void RegisterOnKaleidoscopeUpdateHook() { void RegisterOnKaleidoscopeUpdateHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnKaleidoscopeUpdate>([](int16_t inDungeonScene) { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnKaleidoscopeUpdate>([](int16_t inDungeonScene) {
if (!CVarGetInteger("gA11yTTS", 0)) return; if (!CVarGetInteger("gA11yTTS", 0)) return;
static uint16_t prevCursorIndex = 0; static int16_t prevCursorIndex = 0;
static uint16_t prevCursorSpecialPos = 0; static uint16_t prevCursorSpecialPos = 0;
static uint16_t prevCursorPoint[5] = { 0 }; static uint16_t prevCursorPoint[5] = { 0 };
static int16_t prevPromptChoice = -1;
static int16_t prevSubState = -1;
static int16_t prevState = -1;
PauseContext* pauseCtx = &gPlayState->pauseCtx; PauseContext* pauseCtx = &gPlayState->pauseCtx;
Input* input = &gPlayState->state.input[0]; Input* input = &gPlayState->state.input[0];
if (pauseCtx->state != 6) { // Save game prompt
//reset cursor index to so it is announced when pause is reopened if (pauseCtx->state == 7) {
prevCursorIndex = -1; if (pauseCtx->unk_1EC == 1) {
// prompt
if (prevPromptChoice != pauseCtx->promptChoice) {
auto prompt = GetParameritizedText(pauseCtx->promptChoice == 0 ? "yes" : "no", TEXT_BANK_MISC, nullptr);
if (prevPromptChoice == -1) {
auto translation = GetParameritizedText("save_prompt", TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak((translation + " - " + prompt).c_str(), GetLanguageCode());
} else {
SpeechSynthesizer::Instance->Speak(prompt.c_str(), GetLanguageCode());
}
prevPromptChoice = pauseCtx->promptChoice;
}
} else if (pauseCtx->unk_1EC == 4 && prevSubState != 4) {
// Saved
auto translation = GetParameritizedText("game_saved", TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
}
prevSubState = pauseCtx->unk_1EC;
prevState = pauseCtx->state;
return; return;
} }
// Announce page when
// Kaleido pages are rotating and page halfway rotated
// Or Kaleido was just opened
if ((pauseCtx->unk_1E4 == 1 && pauseCtx->unk_1EA == 32) || (pauseCtx->state == 4 && prevState != 4)) {
uint16_t modeNextPageMap[] = {
PAUSE_MAP, PAUSE_EQUIP, PAUSE_QUEST, PAUSE_ITEM, PAUSE_EQUIP, PAUSE_MAP, PAUSE_ITEM, PAUSE_QUEST,
};
uint16_t nextPage = modeNextPageMap[pauseCtx->mode];
switch (nextPage) {
case PAUSE_ITEM: {
auto translation = GetParameritizedText("item_menu", TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
break;
}
case PAUSE_MAP: {
std::string map;
if (inDungeonScene) {
std::string key = std::to_string(gSaveContext.mapIndex);
map = GetParameritizedText(key, TEXT_BANK_SCENES, nullptr);
} else {
map = GetParameritizedText("overworld", TEXT_BANK_KALEIDO, nullptr);
}
auto translation = GetParameritizedText("map_menu", TEXT_BANK_KALEIDO, map.c_str());
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
break;
}
case PAUSE_QUEST: {
auto translation = GetParameritizedText("quest_menu", TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
break;
}
case PAUSE_EQUIP: {
auto translation = GetParameritizedText("equip_menu", TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
break;
}
}
prevState = pauseCtx->state;
return;
}
prevState = pauseCtx->state;
if (pauseCtx->state != 6) {
// Reset cursor index and values so it is announced when pause is reopened
prevCursorIndex = -1;
prevPromptChoice = -1;
prevSubState = -1;
return;
}
if ((pauseCtx->debugState != 1) && (pauseCtx->debugState != 2)) { if ((pauseCtx->debugState != 1) && (pauseCtx->debugState != 2)) {
char arg[8]; char arg[8];
if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) {
snprintf(arg, sizeof(arg), "%d", gSaveContext.health); // Normalize hearts to fractional count similar to z_lifemeter
int curHeartFraction = gSaveContext.health % 16;
int fullHearts = gSaveContext.health / 16;
float fraction = ceilf((float)curHeartFraction / 5) * 0.25;
float health = (float)fullHearts + fraction;
snprintf(arg, sizeof(arg), "%g", health);
auto translation = GetParameritizedText("health", TEXT_BANK_KALEIDO, arg); auto translation = GetParameritizedText("health", TEXT_BANK_KALEIDO, arg);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
} else if (CHECK_BTN_ALL(input->press.button, BTN_DLEFT)) { } else if (CHECK_BTN_ALL(input->press.button, BTN_DLEFT) && gSaveContext.magicCapacity != 0) {
snprintf(arg, sizeof(arg), "%d", gSaveContext.magic); // Normalize magic to percentage
float magicLevel = ((float)gSaveContext.magic / gSaveContext.magicCapacity) * 100;
snprintf(arg, sizeof(arg), "%.0f%%", magicLevel);
auto translation = GetParameritizedText("magic", TEXT_BANK_KALEIDO, arg); auto translation = GetParameritizedText("magic", TEXT_BANK_KALEIDO, arg);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
} else if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { } else if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) {
@ -235,6 +317,17 @@ void RegisterOnKaleidoscopeUpdateHook() {
if (pauseCtx->cursorSpecialPos > 0) { if (pauseCtx->cursorSpecialPos > 0) {
return; return;
} }
std::string buttonNames[] = {
"input_button_c_left",
"input_button_c_down",
"input_button_c_right",
"input_d_pad_up",
"input_d_pad_down",
"input_d_pad_left",
"input_d_pad_right",
};
int8_t assignedTo = -1;
switch (pauseCtx->pageIndex) { switch (pauseCtx->pageIndex) {
case PAUSE_ITEM: case PAUSE_ITEM:
@ -247,36 +340,71 @@ void RegisterOnKaleidoscopeUpdateHook() {
case ITEM_BOMBCHU: case ITEM_BOMBCHU:
case ITEM_SLINGSHOT: case ITEM_SLINGSHOT:
case ITEM_BOW: case ITEM_BOW:
snprintf(arg, sizeof(arg), "%d", AMMO(pauseCtx->cursorItem[PAUSE_ITEM]));
break;
case ITEM_BEAN: case ITEM_BEAN:
snprintf(arg, sizeof(arg), "%d", 0); snprintf(arg, sizeof(arg), "%d", AMMO(pauseCtx->cursorItem[PAUSE_ITEM]));
break; break;
default: default:
arg[0] = '\0'; arg[0] = '\0';
} }
if (pauseCtx->cursorItem[PAUSE_ITEM] == 999) { if (pauseCtx->cursorItem[PAUSE_ITEM] == PAUSE_ITEM_NONE ||
pauseCtx->cursorItem[PAUSE_ITEM] == ITEM_NONE) {
prevCursorIndex = -1;
return; return;
} }
std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_ITEM]); std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_ITEM]);
auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, arg); std::string itemTranslation = GetParameritizedText(key, TEXT_BANK_KALEIDO, arg);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
// Check if item is assigned to a button
for (size_t i = 0; i < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); i++) {
if (gSaveContext.equips.buttonItems[i + 1] == pauseCtx->cursorItem[PAUSE_ITEM]) {
assignedTo = i;
break;
}
}
if (assignedTo != -1) {
auto button = GetParameritizedText(buttonNames[assignedTo], TEXT_BANK_MISC, nullptr);
auto translation = GetParameritizedText("assigned_to", TEXT_BANK_KALEIDO, button.c_str());
SpeechSynthesizer::Instance->Speak((itemTranslation + " - " + translation).c_str(), GetLanguageCode());
} else {
SpeechSynthesizer::Instance->Speak(itemTranslation.c_str(), GetLanguageCode());
}
break; break;
} }
case PAUSE_MAP: case PAUSE_MAP:
if (inDungeonScene) { if (inDungeonScene) {
// Dungeon map items
if (pauseCtx->cursorItem[PAUSE_MAP] != PAUSE_ITEM_NONE) { if (pauseCtx->cursorItem[PAUSE_MAP] != PAUSE_ITEM_NONE) {
std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_MAP]); std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_MAP]);
auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr); auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
} else {
// Dungeon map floor numbers
char arg[8];
int cursorPoint = pauseCtx->cursorPoint[PAUSE_MAP];
// Cursor is on a dungeon floor position
if (cursorPoint >= 3 && cursorPoint < 11) {
int floorID = gMapData->floorID[gPlayState->interfaceCtx.unk_25A][pauseCtx->dungeonMapSlot - 3];
// Normalize so F1 == 0, and negative numbers are basement levels
int normalizedFloor = (floorID * -1) + 8;
if (normalizedFloor >= 0) {
snprintf(arg, sizeof(arg), "%d", normalizedFloor + 1);
auto translation = GetParameritizedText("floor", TEXT_BANK_KALEIDO, arg);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
} else {
snprintf(arg, sizeof(arg), "%d", normalizedFloor * -1);
auto translation = GetParameritizedText("basement", TEXT_BANK_KALEIDO, arg);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
}
}
} }
} else { } else {
std::string key = std::to_string(0x0100 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]); std::string key = std::to_string(0x0100 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]);
auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr); auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
SPDLOG_INFO("Item: {}", key);
} }
break; break;
case PAUSE_QUEST: case PAUSE_QUEST:
@ -287,16 +415,17 @@ void RegisterOnKaleidoscopeUpdateHook() {
snprintf(arg, sizeof(arg), "%d", gSaveContext.inventory.gsTokens); snprintf(arg, sizeof(arg), "%d", gSaveContext.inventory.gsTokens);
break; break;
case ITEM_HEART_CONTAINER: case ITEM_HEART_CONTAINER:
snprintf(arg, sizeof(arg), "%d", ((gSaveContext.inventory.questItems & 0xF) & 0xF) >> 0x1C); snprintf(arg, sizeof(arg), "%d", (gSaveContext.inventory.questItems & 0xF0000000) >> 0x1C);
break; break;
default: default:
arg[0] = '\0'; arg[0] = '\0';
} }
if (pauseCtx->cursorItem[PAUSE_QUEST] == 999) { if (pauseCtx->cursorItem[PAUSE_QUEST] == PAUSE_ITEM_NONE) {
prevCursorIndex = -1;
return; return;
} }
std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_QUEST]); std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_QUEST]);
auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, arg); auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, arg);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode());
@ -304,15 +433,51 @@ void RegisterOnKaleidoscopeUpdateHook() {
} }
case PAUSE_EQUIP: case PAUSE_EQUIP:
{ {
if (pauseCtx->namedItem == PAUSE_ITEM_NONE) {
prevCursorIndex = -1;
return;
}
std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_EQUIP]); std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_EQUIP]);
auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr); auto itemTranslation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr);
SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); uint8_t checkEquipItem = pauseCtx->namedItem;
// BGS from kaleido reports as ITEM_HEART_PIECE_2 (122)
// remap BGS and broken knife to be the BGS item for the current equip check
if (checkEquipItem == ITEM_HEART_PIECE_2 || checkEquipItem == ITEM_SWORD_KNIFE) {
checkEquipItem = ITEM_SWORD_BGS;
}
// Check if equipment item is currently equipped or assigned to a button
if (checkEquipItem >= ITEM_SWORD_KOKIRI && checkEquipItem <= ITEM_BOOTS_HOVER) {
uint8_t checkEquipType = (checkEquipItem - ITEM_SWORD_KOKIRI) / 3;
uint8_t checkEquipValue = ((checkEquipItem - ITEM_SWORD_KOKIRI) % 3) + 1;
if (CUR_EQUIP_VALUE(checkEquipType) == checkEquipValue) {
itemTranslation = GetParameritizedText("equipped", TEXT_BANK_KALEIDO, itemTranslation.c_str());
}
for (size_t i = 0; i < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); i++) {
if (gSaveContext.equips.buttonItems[i + 1] == checkEquipItem) {
assignedTo = i;
break;
}
}
}
if (assignedTo != -1) {
auto button = GetParameritizedText(buttonNames[assignedTo], TEXT_BANK_MISC, nullptr);
auto translation = GetParameritizedText("assigned_to", TEXT_BANK_KALEIDO, button.c_str());
SpeechSynthesizer::Instance->Speak((itemTranslation + " - " + translation).c_str(), GetLanguageCode());
} else {
SpeechSynthesizer::Instance->Speak(itemTranslation.c_str(), GetLanguageCode());
}
break; break;
} }
default: default:
break; break;
} }
prevCursorIndex = cursorIndex; prevCursorIndex = cursorIndex;
memcpy(prevCursorPoint, pauseCtx->cursorPoint, sizeof(prevCursorPoint)); memcpy(prevCursorPoint, pauseCtx->cursorPoint, sizeof(prevCursorPoint));
}); });