From e45fcdfb3edfad6228f45e8ec99ff02a6cb857e5 Mon Sep 17 00:00:00 2001 From: Rosalie Wanders Date: Sat, 1 Jul 2023 01:15:54 +0200 Subject: [PATCH] RMG-Input: add VRU support --- Source/RMG-Input/CMakeLists.txt | 8 + Source/RMG-Input/UserInterface/MainDialog.cpp | 9 +- .../UserInterface/Widget/ControllerWidget.cpp | 3 +- Source/RMG-Input/VRU.cpp | 603 ++++++++++++++ Source/RMG-Input/VRU.hpp | 24 + Source/RMG-Input/VRUwords.cpp | 739 ++++++++++++++++++ Source/RMG-Input/VRUwords.hpp | 24 + Source/RMG-Input/common.hpp | 7 +- Source/RMG-Input/main.cpp | 50 +- 9 files changed, 1456 insertions(+), 11 deletions(-) create mode 100644 Source/RMG-Input/VRU.cpp create mode 100644 Source/RMG-Input/VRU.hpp create mode 100644 Source/RMG-Input/VRUwords.cpp create mode 100644 Source/RMG-Input/VRUwords.hpp diff --git a/Source/RMG-Input/CMakeLists.txt b/Source/RMG-Input/CMakeLists.txt index cd330d24..e691d395 100644 --- a/Source/RMG-Input/CMakeLists.txt +++ b/Source/RMG-Input/CMakeLists.txt @@ -32,6 +32,14 @@ set(RMG_INPUT_SOURCES main.cpp ) +if (VRU) + list(APPEND RMG_INPUT_SOURCES + VRU.cpp + VRUwords.cpp + ) + add_definitions(-DVRU) +endif(VRU) + add_library(RMG-Input SHARED ${RMG_INPUT_SOURCES}) target_link_libraries(RMG-Input RMG-Core ${SDL2_LIBRARIES}) diff --git a/Source/RMG-Input/UserInterface/MainDialog.cpp b/Source/RMG-Input/UserInterface/MainDialog.cpp index f2474a7e..dc2e2199 100644 --- a/Source/RMG-Input/UserInterface/MainDialog.cpp +++ b/Source/RMG-Input/UserInterface/MainDialog.cpp @@ -59,9 +59,12 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romCo // always add keyboard device for (auto& controllerWidget : this->controllerWidgets) { - controllerWidget->AddInputDevice("None", (int)InputDeviceType::None); - controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic); - controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard); +#ifdef VRU + controllerWidget->AddInputDevice("Voice Recognition Unit", (int)InputDeviceType::EmulateVRU); +#endif // VRU + controllerWidget->AddInputDevice("None", (int)InputDeviceType::None); + controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic); + controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard); controllerWidget->SetInitialized(true); } diff --git a/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp b/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp index 5788c57a..b1fa49d7 100644 --- a/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp +++ b/Source/RMG-Input/UserInterface/Widget/ControllerWidget.cpp @@ -623,7 +623,8 @@ void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value) } // set plugged in state - this->setPluggedIn(deviceNum != (int)InputDeviceType::None); + this->setPluggedIn(deviceNum != (int)InputDeviceType::None && + deviceNum != (int)InputDeviceType::EmulateVRU); emit this->CurrentInputDeviceChanged(this, deviceName, deviceNum); } diff --git a/Source/RMG-Input/VRU.cpp b/Source/RMG-Input/VRU.cpp new file mode 100644 index 00000000..194231fc --- /dev/null +++ b/Source/RMG-Input/VRU.cpp @@ -0,0 +1,603 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#define CORE_PLUGIN +#define M64P_PLUGIN_PROTOTYPES 1 + +#include +#include + +#include <../3rdParty/vosk-api/include/vosk_api.h> + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "VRU.hpp" +#include "VRUwords.hpp" + +// +// Local Enums +// + +enum Language +{ + English = 0, + JapaneseOrDemo = 1 +}; + +// +// Local Variables +// + +// vosk-api library variables +// + +typedef VoskModel* (*ptr_vosk_model_new)(const char *); +typedef void (*ptr_vosk_model_free)(VoskModel *); +typedef VoskRecognizer* (*ptr_vosk_recognizer_new_grm)(VoskModel *, float, const char *); +typedef void (*ptr_vosk_recognizer_free)(VoskRecognizer *); +typedef int (*ptr_vosk_recognizer_accept_waveform)(VoskRecognizer *, const char *, int ); +typedef const char * (*ptr_vosk_recognizer_final_result)(VoskRecognizer *); +typedef void (*ptr_vosk_set_log_level)(int); +typedef void (*ptr_vosk_recognizer_set_max_alternatives)(VoskRecognizer *, int); + +static ptr_vosk_model_new l_vosk_model_new = nullptr; +static ptr_vosk_model_free l_vosk_model_free = nullptr; +static ptr_vosk_recognizer_new_grm l_vosk_recognizer_new_grm = nullptr; +static ptr_vosk_recognizer_free l_vosk_recognizer_free = nullptr; +static ptr_vosk_recognizer_accept_waveform l_vosk_recognizer_accept_waveform = nullptr; +static ptr_vosk_recognizer_final_result l_vosk_recognizer_final_result = nullptr; +static ptr_vosk_set_log_level l_vosk_set_log_level = nullptr; +static ptr_vosk_recognizer_set_max_alternatives l_vosk_recognizer_set_max_alternatives = nullptr; + +static osal_dynlib_lib_handle l_VoskLibHandle = nullptr; + +static VoskModel* l_VoskModel = nullptr; +static VoskRecognizer* l_VoskRecognizer = nullptr; + +// VRU implementation variables +// +static bool l_Initialized = false; + +static std::vector l_WordEntries; + +static int l_MicState = 0; +static int l_WordListSize = 0; +static int l_WordListCount = 0; + +static QStringList l_RegisteredWords; +static QList l_RegisteredWordsIndex; + +static SDL_AudioDeviceID l_AudioDevice = 0; +static SDL_AudioSpec l_AudioDeviceSpec; + +// +// Local Functions +// + +static bool hook_vosk(void) +{ + std::string debugMessage; + + std::filesystem::path voskApiPath; + voskApiPath = CoreGetLibraryDirectory(); + voskApiPath += "/libvosk" OSAL_DYNLIB_LIB_EXT_STR; + + l_VoskLibHandle = osal_dynlib_open(voskApiPath); + if (l_VoskLibHandle == nullptr) + { + debugMessage = "VRU: Failed to open library \""; + debugMessage += voskApiPath.string().c_str(); + debugMessage += "\": "; + debugMessage += osal_dynlib_strerror(); + CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage); + return false; + } + + l_vosk_model_new = (ptr_vosk_model_new) osal_dynlib_sym(l_VoskLibHandle, "vosk_model_new"); + l_vosk_model_free = (ptr_vosk_model_free) osal_dynlib_sym(l_VoskLibHandle, "vosk_model_free"); + l_vosk_recognizer_new_grm = (ptr_vosk_recognizer_new_grm) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_new_grm"); + l_vosk_recognizer_free = (ptr_vosk_recognizer_free) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_free"); + l_vosk_recognizer_accept_waveform = (ptr_vosk_recognizer_accept_waveform) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_accept_waveform"); + l_vosk_recognizer_final_result = (ptr_vosk_recognizer_final_result) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_final_result"); + l_vosk_set_log_level = (ptr_vosk_set_log_level) osal_dynlib_sym(l_VoskLibHandle, "vosk_set_log_level"); + l_vosk_recognizer_set_max_alternatives = (ptr_vosk_recognizer_set_max_alternatives) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_set_max_alternatives"); + + if (l_vosk_model_new == nullptr || + l_vosk_model_free == nullptr || + l_vosk_recognizer_new_grm == nullptr || + l_vosk_recognizer_free == nullptr || + l_vosk_recognizer_accept_waveform == nullptr || + l_vosk_recognizer_final_result == nullptr || + l_vosk_set_log_level == nullptr || + l_vosk_recognizer_set_max_alternatives == nullptr) + { + debugMessage = "VRU: Failed to open library: missing functions"; + CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage); + return false; + } + + return true; +} + +static void unhook_vosk(void) +{ + l_vosk_model_new = nullptr; + l_vosk_model_free = nullptr; + l_vosk_recognizer_new_grm = nullptr; + l_vosk_recognizer_free = nullptr; + l_vosk_recognizer_accept_waveform = nullptr; + l_vosk_recognizer_final_result = nullptr; + l_vosk_set_log_level = nullptr; + l_vosk_recognizer_set_max_alternatives = nullptr; + + osal_dynlib_close(l_VoskLibHandle); +} + +static bool setup_vosk_model(void) +{ + std::string debugMessage; + + std::filesystem::path voskModelPath; + voskModelPath = CoreGetSharedDataDirectory(); + voskModelPath += "/vosk-model-small-en-us-0.15.zip"; + + bool missingModelFile = false; + + std::filesystem::path voskModelFiles[] = + { + "vosk-model-small-en-us-0.15/am/final.mdl", + "vosk-model-small-en-us-0.15/conf/mfcc.conf", + "vosk-model-small-en-us-0.15/conf/model.conf", + "vosk-model-small-en-us-0.15/graph/disambig_tid.int", + "vosk-model-small-en-us-0.15/graph/Gr.fst", + "vosk-model-small-en-us-0.15/graph/HCLr.fst", + "vosk-model-small-en-us-0.15/graph/phones/word_boundary.int", + "vosk-model-small-en-us-0.15/ivector/final.dubm", + "vosk-model-small-en-us-0.15/ivector/final.ie", + "vosk-model-small-en-us-0.15/ivector/final.mat", + "vosk-model-small-en-us-0.15/ivector/global_cmvn.stats", + "vosk-model-small-en-us-0.15/ivector/online_cmvn.conf", + "vosk-model-small-en-us-0.15/ivector/splice.conf", + }; + + for (std::filesystem::path& file : voskModelFiles) + { + std::filesystem::path fullFilePath; + fullFilePath = CoreGetUserDataDirectory(); + fullFilePath += "/"; + fullFilePath += file; + + if (!std::filesystem::exists(fullFilePath)) + { + missingModelFile = true; + break; + } + } + + // all required files exist, + // so we don't need to extract the zip again + if (!missingModelFile) + { + return true; + } + + if (!std::filesystem::is_regular_file(voskModelPath)) + { + debugMessage = "VRU: vosk model file \""; + debugMessage += voskModelPath.string().c_str(); + debugMessage += "\" doesn't exist!"; + CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage); + return false; + } + + if (!CoreUnzip(voskModelPath, CoreGetUserDataDirectory())) + { + debugMessage = "VRU: Failed to extract vosk model file \""; + debugMessage += voskModelPath.string().c_str(); + debugMessage += "\": "; + debugMessage += CoreGetError(); + CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage); + return false; + } + + return true; +} + +static bool init_vosk(void) +{ + std::filesystem::path voskModelPath; + voskModelPath = CoreGetUserDataDirectory(); + voskModelPath += "/vosk-model-small-en-us-0.15"; + + l_vosk_set_log_level(-1); + + l_VoskModel = l_vosk_model_new(voskModelPath.string().c_str()); + if (l_VoskModel == nullptr) + { + CoreDebugCallbackMessage(CoreDebugMessageType::Error, "VRU: vosk_model_new failed"); + return false; + } + + return true; +} + +static void quit_vosk(void) +{ + if (l_VoskModel != nullptr) + { + l_vosk_model_free(l_VoskModel); + l_VoskModel = nullptr; + } + + if (l_VoskRecognizer != nullptr) + { + l_vosk_recognizer_free(l_VoskRecognizer); + l_VoskRecognizer = nullptr; + } +} + +static bool init_mic(void) +{ + std::string debugMessage; + SDL_AudioSpec desiredAudioSpec; + + desiredAudioSpec.freq = 44100; + desiredAudioSpec.format = AUDIO_S16SYS; + desiredAudioSpec.channels = 1; + desiredAudioSpec.samples = 1024; + desiredAudioSpec.callback = nullptr; + desiredAudioSpec.userdata = nullptr; + + l_AudioDevice = SDL_OpenAudioDevice(nullptr, 1, &desiredAudioSpec, &l_AudioDeviceSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); + if (l_AudioDevice == 0) + { + debugMessage = "VRU: SDL_OpenAudioDevice Failed: "; + debugMessage += SDL_GetError(); + CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage); + return false; + } + + return true; +} + +static void quit_mic(void) +{ + if (l_AudioDevice != 0) + { + SDL_CloseAudioDevice(l_AudioDevice); + } +} + +static QByteArray words_to_byte_array(uint16_t* words, uint16_t size) +{ + QByteArray byte_array; + + uint8_t* bytes = (uint8_t*)words; + + for (int i = 0; i < (size * 2); i += 2) + { + byte_array.push_back(bytes[i + 1]); + byte_array.push_back(bytes[i]); + } + + return byte_array; +} + +static bool find_word_from_hex(std::string hex, std::string& word) +{ + auto predicate = [hex](const VRUWordEntry& entry) + { + return entry.hex == hex; + }; + + auto iter = std::find_if(l_WordEntries.begin(), l_WordEntries.end(), predicate); + if (iter != l_WordEntries.end()) + { + word = (*iter).words; + } + + return iter != l_WordEntries.end(); +} + +// +// Exported Functions +// + +bool InitVRU(void) +{ + if (l_Initialized) + { + return true; + } + + if (!hook_vosk()) + { + return false; + } + + if (!setup_vosk_model()) + { + return false; + } + + if (!init_vosk()) + { + return false; + } + + if (!init_mic()) + { + return false; + } + + l_MicState = 0; + + if (l_WordEntries.empty()) + { + l_WordEntries = GetVRUWordEntries(); + } + + l_Initialized = true; + return true; +} + +bool IsVRUInit(void) +{ + return l_Initialized; +} + +bool QuitVRU(void) +{ + if (!l_Initialized) + { + return false; + } + + quit_mic(); + quit_vosk(); + unhook_vosk(); + + l_Initialized = false; + return true; +} + +int GetVRUMicState(void) +{ + return l_MicState; +} + +// +// VRU Plugin Functions +// + +EXPORT void CALL SendVRUWord(uint16_t length, uint16_t* word, uint8_t lang) +{ + if (!l_Initialized) + { + return; + } + + QByteArray byte_array = words_to_byte_array(word, length); + std::string debugMessage; + std::string word_str; + + if (find_word_from_hex(byte_array.toHex().toUpper().toStdString(), word_str)) + { // found word + l_RegisteredWords.append(QString::fromStdString(word_str)); + l_RegisteredWordsIndex.append(l_WordListCount); + } + else + { // not found + QStringDecoder utf8_decoder = QStringDecoder(QStringDecoder::Utf8); + QString encoded_string = utf8_decoder.decode(byte_array); + + if (utf8_decoder.hasError()) + { + debugMessage = "VRU: unknown word: "; + debugMessage += encoded_string.toStdString(); + CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage); + } + else + { + l_RegisteredWords.append(encoded_string); + l_RegisteredWordsIndex.append(l_WordListCount); + } + } + + l_WordListCount++; + + // we've reached the end of the list + if (l_WordListCount == l_WordListSize) + { + // needed for vosk-api, see vosk_api.h + l_RegisteredWords.append("[unk]"); + l_RegisteredWordsIndex.append(l_WordListCount); + + QJsonDocument json_document; + json_document.setArray(QJsonArray::fromStringList(l_RegisteredWords)); + + // free existing recognizer if needed + if (l_VoskRecognizer) + { + l_vosk_recognizer_free(l_VoskRecognizer); + l_VoskRecognizer = nullptr; + } + + // try to create a new recognizer + l_VoskRecognizer = l_vosk_recognizer_new_grm(l_VoskModel, (float)l_AudioDeviceSpec.freq, json_document.toJson().constData()); + if (l_VoskRecognizer != nullptr) + { + l_vosk_recognizer_set_max_alternatives(l_VoskRecognizer, 3); + } + } +} + +EXPORT void CALL SetMicState(int state) +{ + if (!l_Initialized) + { + return; + } + + if (state) + { + SDL_ClearQueuedAudio(l_AudioDevice); + SDL_PauseAudioDevice(l_AudioDevice, 0); + } + else + { + SDL_PauseAudioDevice(l_AudioDevice, 1); + } + + l_MicState = state; +} + +EXPORT void CALL ReadVRUResults(uint16_t* error_flags, uint16_t* num_results, uint16_t* mic_level, uint16_t* voice_level, uint16_t* voice_length, uint16_t* matches) +{ + if (!l_Initialized || l_VoskRecognizer == nullptr) + { + return; + } + + // initialize result data + *num_results = 0; + *mic_level = 0xBB8; + *voice_level = 0xBB8; + *voice_length = 0x8004; + for (int i = 0; i < 10; i += 2) + { + matches[i] = 0x7FFF; + matches[i + 1] = 0; + } + + // retrieve audio data from device + SDL_PauseAudioDevice(l_AudioDevice, 1); + + void* audio_buf = nullptr; + uint32_t audio_size = SDL_GetQueuedAudioSize(l_AudioDevice); + + audio_buf = malloc(audio_size); + if (audio_buf == nullptr) + { + *error_flags = 0x8000; + return; + } + + audio_size = SDL_DequeueAudio(l_AudioDevice, audio_buf, audio_size); + + // hand audio data to vosk and retrieve results + int ret = l_vosk_recognizer_accept_waveform(l_VoskRecognizer, (const char*)audio_buf, audio_size); + if (ret == -1) + { + *error_flags = 0x8000; + free(audio_buf); + return; + } + + QJsonDocument json_document = QJsonDocument::fromJson(l_vosk_recognizer_final_result(l_VoskRecognizer)); + + // parse results from vosk + QJsonArray alternatives_array = json_document.object().value("alternatives").toArray(); + + QStringList alternative_words; + QStringList found_words; + std::string debugMessage; + + // parse words + for (int i = 0; i < alternatives_array.size(); i++) + { + QString word = alternatives_array.at(i).toObject().value("text").toString(); + if (!word.isEmpty()) + { + alternative_words.append(word); + } + } + + // check the registered words, + // and see if any matches with the recognized words + for (const QString& word : l_RegisteredWords) + { + if (word != "[unk]" && + !found_words.contains(word) && + alternative_words.filter(word).size() > 0) + { + found_words.append(word); + if (found_words.size() == 5) + { + break; + } + } + } + + // sort found words by length + std::sort(found_words.begin(), found_words.end(), [](QString& a, QString& b) + { + return a.size() > b.size(); + }); + + int matches_index = 0; + for (int i = 0; i < found_words.size(); i++) + { + matches[matches_index++] = l_RegisteredWordsIndex.at(l_RegisteredWords.indexOf(found_words.at(i))); + matches[matches_index++] = i * 256; + debugMessage = "VRU: found match "; + debugMessage += std::to_string(i); + debugMessage += ": "; + debugMessage += found_words.at(i).toStdString(); + CoreDebugCallbackMessage(CoreDebugMessageType::Info, debugMessage); + } + + if (found_words.size() == 0 && alternative_words.size() > 0) + { + // heard something but it didn't match anything + *error_flags = 0x4000; + matches[0] = 0; + found_words.append("0"); + debugMessage = "VRU: heard something but it didn't match anything"; + CoreDebugCallbackMessage(CoreDebugMessageType::Info, debugMessage); + } + + *num_results = found_words.size(); + + free(audio_buf); +} + +EXPORT void CALL ClearVRUWords(uint8_t length) +{ + if (!l_Initialized) + { + return; + } + + l_WordListCount = 0; + l_WordListSize = length; + + l_RegisteredWords.clear(); + l_RegisteredWordsIndex.clear(); + + if (l_VoskRecognizer != nullptr) + { + l_vosk_recognizer_free(l_VoskRecognizer); + l_VoskRecognizer = nullptr; + } +} + +EXPORT void CALL SetVRUWordMask(uint8_t length, uint8_t* mask) +{ +} + diff --git a/Source/RMG-Input/VRU.hpp b/Source/RMG-Input/VRU.hpp new file mode 100644 index 00000000..09fe7d8f --- /dev/null +++ b/Source/RMG-Input/VRU.hpp @@ -0,0 +1,24 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef VRU_HPP +#define VRU_HPP + +// attempts to initialize VRU capabilities +bool InitVRU(void); + +// returns whether VRU has been initialized +bool IsVRUInit(void); + +// attempts to de-initialize VRY capabilities +bool QuitVRU(void); + +int GetVRUMicState(void); + +#endif // VRU_HPP \ No newline at end of file diff --git a/Source/RMG-Input/VRUwords.cpp b/Source/RMG-Input/VRUwords.cpp new file mode 100644 index 00000000..57014e5d --- /dev/null +++ b/Source/RMG-Input/VRUwords.cpp @@ -0,0 +1,739 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "VRUwords.hpp" + +// +// Exported Functions +// + +std::vector GetVRUWordEntries(void) +{ + std::vector entries; + + entries.push_back({"03A50024000303CF00A80003036000EA", "pikachu"}); + entries.push_back({"03A50045000303CF00A80003036000EA", "pikachu" }); + entries.push_back({"03A50024000303C900450003036000EA", "pikachu" }); + entries.push_back({"03A8018F000303CF00A80003036000EA", "pikachu" }); + entries.push_back({"03B101B0000303CF00A80003036000EA", "pikachu" }); + entries.push_back({"03CF00A80003036000EA", "pikachu" }); + entries.push_back({"03A80066000303CF00A80003036000F900EA", "pikachu" }); + entries.push_back({"03A50024000303CF00A80003035D001200F900EA", "pikachu" }); + entries.push_back({"040801740024", "hey" }); + entries.push_back({"03CF00C603360405000F0234", "come here" }); + entries.push_back({"0369004803FC0318018F", "this way" }); + entries.push_back({"039C010B000603900006037B01B0", "good bye" }); + entries.push_back({"039900A80006037B01B0", "good bye" }); + entries.push_back({"03F900090309009F02E2018F000303BD0234", "see you later" }); + entries.push_back({"037B01B00006037B01B0", "bye bye" }); + entries.push_back({"03FC000303C30255000303C6", "start" }); + entries.push_back({"02E2006903FC000303B402E2018F", "lets play" }); + entries.push_back({"040B00C002EB0213", "hello" }); + entries.push_back({"043B0213000303AB00A5034803FC006903FC00A503270024", "open sesame" }); + entries.push_back({"043B0213000303A80063034803FC006903FC00A503270024", "open sesame" }); + entries.push_back({"039F01FE00990318018F", "go away" }); + entries.push_back({"039C010B00060390033302D603390042035A", "good morning" }); + entries.push_back({"039900A5033302D603390042035A", "good morning" }); + entries.push_back({"042F01AD033603FC023A0024", "im sorry" }); + entries.push_back({"042F01AD033603FC012602F10024", "im sorry" }); + entries.push_back({"03FC023A0024", "sorry" }); + entries.push_back({"03FC012602F10024", "sorry" }); + entries.push_back({"042F01B00003036000ED03DB030C00EA", "i choose you" }); + entries.push_back({"04080174030C00EA000303A50024000303CF00A80003036000EA", "hey you pikachu" }); + entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A80003036000EA", "pika pikachu" }); + entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A8000303A50024", "pika pika pi" }); + entries.push_back({"03A50024000303A50024000303CF00A80003036000EA", "pi pikachu" }); + entries.push_back({"03A50024000303A50024000303CF00A8000303A50024", "pi pika pi" }); + entries.push_back({"03A50024000303D8000303CF00C9", "pika" }); + entries.push_back({"03A50024000303CF00A8", "pika" }); + entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A8", "pika pika" }); + entries.push_back({"03A503030024000303CF00A8", "pi ka" }); + entries.push_back({"03A50024000303CF00C9000303CF00C9", "pi ka ka" }); + entries.push_back({"03A50024000303CF00A8000303CF00A8000303A50024", "pi ka ka pi" }); + entries.push_back({"037E02F10042035A036C0087000303C604050297", "bring that here" }); + entries.push_back({"039F0213000603960066000303B70045000303C6", "go get it" }); + entries.push_back({"0393004803E70045000303C6000303C000E703270024", "give it to me" }); + entries.push_back({"0393004203270027036C0087000303C6", "gimme that" }); + entries.push_back({"03F600C603480006038702370402014D000303D8", "thunder shock" }); + entries.push_back({"03F600C603480006038702340006037B020A02EE000303C6", "thunderbolt" }); + entries.push_back({"03F600C60348000603870234", "thunder" }); + entries.push_back({"03F600C6033F0234", "thunder" }); + entries.push_back({"0432009F02E20066000303D8000303C602F10045000303D802F40087000303C6", "electric rat" }); + entries.push_back({"0426001B02E20066000303D8000303C602F10045000303D802F40087000303C6", "electric rat" }); + entries.push_back({"0432009F02E20066000303C602F10045000303D802F40087000303C6", "electric rat" }); + entries.push_back({"042F01A40408018F000303B7030C00EA", "i hate you" }); + entries.push_back({"03A202F4018F000303C600060366014D0006037E", "great job" }); + entries.push_back({"036C0087000303C3031B00AB03DE000603A202F4018F000303C6", "that was great" }); + entries.push_back({"0309023703FC0213000303C9030C00EA000303C6", "you're so cute" }); + entries.push_back({"03BD00A202F1004803ED0045000303D8", "terrific" }); + entries.push_back({"037500C9000303BD023703F002F10024", "butter free" }); + entries.push_back({"043200C603360006037E02F4005D02E500A8", "am brel a" }); + entries.push_back({"037B01CE035A0006037B01CE035A", "boing boing" }); + entries.push_back({"043801290348000303C000ED036C00A5033C0066000303D803FC000303C603FC000303BA018F00060366", "on to the next stage" }); + entries.push_back({"042F0087000303AB009F02EE", "apple" }); + entries.push_back({"043200A8000303AB009F02EE", "apple" }); + entries.push_back({"0426000C0087000303B402EE", "apple" }); + entries.push_back({"03A202F10021033C0087000303AB009F02EE", "green apple" }); + entries.push_back({"0372018F000303D8000303BA0087000303AB009F02EE", "baked apple" }); + entries.push_back({"039F020A02EE0006038700A5033C0087000303AB009F02EE", "golden apple" }); + entries.push_back({"03A5002400030360", "peach" }); + entries.push_back({"03FC000303C602FD012C00060372029D0024", "strawberry" }); + entries.push_back({"03FC000303BD0225012C00060372029D0024", "strawberry" }); + entries.push_back({"02F4008A03DE00060372029D0024", "raspberry" }); + entries.push_back({"02F4008A03FC0006037E02F10024", "raspberry" }); + entries.push_back({"037500A5033C0084033F00A8", "banana" }); + entries.push_back({"036F0042033C0084033F00C9", "banana" }); + entries.push_back({"037500C6033C0084033F00A8", "banana" }); + entries.push_back({"03CC0087000303C6000303BA018602EE", "cat tail" }); + entries.push_back({"032101A702EE00060390040B02340006037E", "wild herb" }); + entries.push_back({"03D502D60348", "corn" }); + entries.push_back({"03B1014D000303B4000303D502D60348", "popcorn" }); + entries.push_back({"03AB00C60336000303B4000303C900420348", "pumpkin" }); + entries.push_back({"03AB00C60336000303C900420348", "pumpkin" }); + entries.push_back({"03AB00C6035A000303CF00A50348", "pumpkin" }); + entries.push_back({"03C00273033F00A8000303B4", "turnip" }); + entries.push_back({"03C0027303390045000303B4", "turnip" }); + entries.push_back({"03CC00870006036F004500060366", "cabbage" }); + entries.push_back({"03CC008102F700A8000303C6", "carrot" }); + entries.push_back({"03CC02A300A8000303C6", "carrot" }); + entries.push_back({"043200C60339030900A50348", "onion" }); + entries.push_back({"043200A5033F00A50348", "onion" }); + entries.push_back({"043501080339030900A50348", "onion" }); + entries.push_back({"03FC031500240006037500C9000303BA018F0006038D0213", "sweet potato" }); + entries.push_back({"03FC03150024000303C6000303AB00A8000303C3016E0006038D0213", "sweet potato" }); + entries.push_back({"03FC03150024000303B4000303BA018F0006038700A8", "sweet potato" }); + entries.push_back({"0411014D000303C603FC03150024000303C6000303AB00C9000303BA018F0006038D0213", "hot sweet potato" }); + entries.push_back({"03FC032A005D02DF002703F002FA00EA000303C6", "smelly fruit" }); + entries.push_back({"03FC000303B70045000303C9002703F002FA00EA000303C6", "sticky fruit" }); + entries.push_back({"02FD021603FC000303BD00A80006039003F002FA00EA000303C6", "roasted fruit" }); + entries.push_back({"0321012302EE033F00A8000303C6", "walnut" }); + entries.push_back({"03D802F40087000303D50321012302EE033F00A8000303C6", "cracked walnut" }); + entries.push_back({"03FC000303B101B0000303C900270402005D02EE", "spiky shell" }); + entries.push_back({"03FC000303B101AD033900270402005D02EE", "spiny shell" }); + entries.push_back({"0360006903FC033F00A8000303C6", "chestnut" }); + entries.push_back({"036F002400030360033F00C9000303C6", "beach nut" }); + entries.push_back({"03D50213000303CF00A5033F00C9000303C6", "coconut" }); + entries.push_back({"042C018F000303D502D60348", "acorn" }); + entries.push_back({"03C3021603FC000303BD00A800060384018F000303D502D60348", "toasted acorn" }); + entries.push_back({"03F002EB01950042034E018F000303D502D60348", "flying acorn" }); + entries.push_back({"042C018F000303D502D60348000303C3014D000303B4", "acorn top" }); + entries.push_back({"036600C603360006037B0216040202FA00E70336", "jumbo mushroom" }); + entries.push_back({"02FD021603FC000303BD00A8000603900006036600A503360006037B0213", "roasted jumbo" }); + entries.push_back({"039002F1002103270027040202FA00E70336", "dreamy mushroom" }); + entries.push_back({"03C602F700CC03F0009F02EE000303C3014D000303B4", "truffle top" }); + entries.push_back({"037E02E800ED040202FA00E70336", "blue mushroom" }); + entries.push_back({"0411014D000303C6040202FA00E70336", "hot mushroom" }); + entries.push_back({"02F4006600060390040202FA00E70336", "red mushroom" }); + entries.push_back({"03FC00C603390027040202FA00E70336", "sunny mushroom" }); + entries.push_back({"032D00CC040202FA00E70336", "mushroom" }); + entries.push_back({"0411014D000303C6032D00CC040202FA00E70336", "hot mushroom" }); + entries.push_back({"02EB01B0000303C60006037500C002EE0006037E", "light bulb" }); + entries.push_back({"02EB01B0000303C600060378010202EE0006037E", "light bulb" }); + entries.push_back({"03CF00C9000303B4000303CC018F000303D8", "cupcake" }); + entries.push_back({"03840174002703DB0024", "daisy" }); + entries.push_back({"03A50045000303C000E70339030900A8", "petunia" }); + entries.push_back({"03C000E102E500A8000303B4", "tulip" }); + entries.push_back({"03C000E102DF0045000303B4", "tulip" }); + entries.push_back({"03840084034800060387009F02EB019B00A50348", "dandelion" }); + entries.push_back({"03840084034800060381001B02EB019B00A50348", "dandelion" }); + entries.push_back({"037E02E800EA00060372005D02EE", "bluebell" }); + entries.push_back({"03FC000303CF00C60348000303D80006037E02EB015003FC00A50336", "skunk blossom" }); + entries.push_back({"03FC00C6034803F002EB01DD0234", "sunflower" }); + entries.push_back({"02DF003C02DF0024", "lily" }); + entries.push_back({"02FD021603DE0006037500C900060390", "rose bud" }); + entries.push_back({"02F400660006039002FD021603DE", "red rose" }); + entries.push_back({"0375009F02E800E70348", "balloon" }); + entries.push_back({"03B10213000303CC018F00060381004803FC000303D8", "poke disc" }); + entries.push_back({"036F0024000303600006037B012302EE", "beach ball" }); + entries.push_back({"0321012C000303BD02190042035A000303CC00840348", "watering can" }); + entries.push_back({"0321012C000303BD02190042035A0006036600C9000603A2", "watering jug" }); + entries.push_back({"0306005D02EB02130006037B012302EE", "yellow ball" }); + entries.push_back({"03600255000303D5020A02EE", "charcoal" }); + entries.push_back({"02DF002703F004110315004803FC009F02EE", "leaf whistle" }); + entries.push_back({"041102520333014A03390045000303CF00A8", "harmonica" }); + entries.push_back({"03C602F700C60336000303A80066", "trumpet" }); + entries.push_back({"03C602FA01080336000303AB00A8000303C6", "trumpet" }); + entries.push_back({"037500A5033C0084033F00A8000303A5000F009F02EE", "banana peel" }); + entries.push_back({"032A018F0006039900AB03F002100348", "megaphone" }); + entries.push_back({"039F020A02EE00060390000303D501CE0348", "gold coin" }); + entries.push_back({"0360014D000303CF009F02E500A8000303C6000303D501CE0348", "chocolate coin" }); + entries.push_back({"0402014D000303D802E500A8000303C6000303D501CE0348", "chocolate coin" }); + entries.push_back({"03F9003C02EE03EA0234000303D501CE0348", "silver coin" }); + entries.push_back({"03D5014D000303AB0234000303D501CE0348", "copper coin" }); + entries.push_back({"02FA00EA0006036F0024", "ruby" }); + entries.push_back({"03FC008A03F001AA0300", "sapphire" }); + entries.push_back({"03FC008A03F0019B0234", "sapphire" }); + entries.push_back({"03C30213000303A8008A03DE", "topaz" }); + entries.push_back({"02F40066000603900333025500060375009F02EE", "red marble" }); + entries.push_back({"037E02E800E70333025500060375009F02EE", "blue marble" }); + entries.push_back({"0306005D02EB02100333025500060375009F02EE", "yellow marble" }); + entries.push_back({"02FA00EA0006036F001E02F10042035A", "ruby ring" }); + entries.push_back({"037B014D00060387009F02EE000303CC0087000303B402F10042035A", "bottle cap ring" }); + entries.push_back({"03B101AA02F700A8000303C603FC02D900060390", "pirate sword" }); + entries.push_back({"03B101AA02F10045000303C603FC02D900060390", "pirate sword" }); + entries.push_back({"03C301D403FC0126030000060390", "toy sword" }); + entries.push_back({"037502340006039003F00069036C0234", "bird feather" }); + entries.push_back({"037B020A02EE000303C6", "bolt" }); + entries.push_back({"032A0087000603A203390045000303C6", "magnet" }); + entries.push_back({"032A018F000603A203390045000303C6", "magnet" }); + entries.push_back({"0333025500060375009F02EE", "marble" }); + entries.push_back({"03D802F4018F000303C6", "crate" }); + entries.push_back({"03D50255000603900006037B02D9000603900006037B014D000303D803FC", "cardboard box" }); + entries.push_back({"03CF00A503360405000F0234", "come here" }); + entries.push_back({"043B021603EA022804050297", "over here" }); + entries.push_back({"040B009F02EB0213", "hello" }); + entries.push_back({"039C010B00060390034501950024000303C6", "good night" }); + entries.push_back({"039900A5034501B0000303C6", "good night" }); + entries.push_back({"03F6018C035A000303C9030C00EA", "thank you" }); + entries.push_back({"038A00ED03FC00C6033603F30042035A", "do something" }); + entries.push_back({"02DF004803FC00A50348000303BD00A503270024", "listen to me" }); + entries.push_back({"03A500090024000303CF00A8", "pi ka" }); + entries.push_back({"039F0213000603930045000303BD00A8000303C6", "go get it" }); + entries.push_back({"036C0087000303C603FC03F001AD0348", "thats fine" }); + entries.push_back({"043B0213000303CC01740024", "ok" }); + entries.push_back({"04020276", "sure" }); + entries.push_back({"02FD01B0000303C6", "right" }); + entries.push_back({"02E2006903FC0006038A00ED036C0087000303C6", "lets do that" }); + entries.push_back({"0345014D000303C6036C0087000303C3031B00C60348", "not that one" }); + entries.push_back({"036C0087000303C603DE02FD0129035A", "thats wrong" }); + entries.push_back({"0372008700060390000303B10213000303CC018C0333014A0348", "bad pokemon" }); + entries.push_back({"038D02100348000303C60006038A00ED036C0087000303C6", "dont do that" }); + entries.push_back({"042900420348000303CF021C0066000303D8000303C6", "incorrect" }); + entries.push_back({"03CF00C9000303BD00A8000303C301F2000303C6", "cut it out" }); + entries.push_back({"03450213", "no" }); + entries.push_back({"0318018F0006038700A80006039F0213", "way to go" }); + entries.push_back({"03F002EB01DD0234", "flower" }); + entries.push_back({"038400840348000303C603FC", "dance" }); + entries.push_back({"03F602FD01F80045000303C6", "throw it" }); + entries.push_back({"03C3015003F90045000303C6", "toss it" }); + entries.push_back({"030C00EA000303CC008403390024000303C6036C0087000303C6", "you can eat that" }); + entries.push_back({"03BA019203FC000303B70045000303C6", "taste it" }); + entries.push_back({"041101F503DB0045000303C6000303BA019203FC000303C6", "hows it taste" }); + entries.push_back({"041101F503DB0045000303C603FC032A005D02EE", "hows it smell" }); + entries.push_back({"041101F503DB0045000303C603FC01EF034800060390", "hows it sound" }); + entries.push_back({"0411031B00A8000303C60006038700AB03DB0045000303C60006038A00EA", "what does it do" }); + entries.push_back({"03B402E201830411031B00A8000303C6", "play what" }); + entries.push_back({"03C602FD01950045000303C6", "try it" }); + entries.push_back({"03B402E201740045000303C6", "play it" }); + entries.push_back({"039002FD014D000303A50045000303C6", "drop it" }); + entries.push_back({"03A80066000303CF00A80003036000EA", "pikachu" }); + entries.push_back({"030C00EA000303CC00840348000303BA019203FC000303B70045000303C6", "you can taste it" }); + entries.push_back({"041101F503DB0045000303C603FC01EF0348", "hows it sound" }); + entries.push_back({"03AE010B000303C6036C0087000303C6000603720087000303D8", "put that back" }); + entries.push_back({"03FC000303BA018003150048036C03270024", "stay with me" }); + entries.push_back({"03FC000303BA01770087000303C6033301A4041101F503FC", "stay at my house" }); + entries.push_back({"03F90009030C00E102E2018F000303BD0234", "see you later" }); + entries.push_back({"03F90009030C00EA", "see you" }); + entries.push_back({"037B01B0", "bye" }); + entries.push_back({"0411031B00A8000303BD0219030900A80006038A00CF0042035A", "what are you doing" }); + entries.push_back({"0411031B00A8000303C603FC00C9000303B4", "whats up" }); + entries.push_back({"0411031B00A8000303C603FC00C9000303B4036C02B8", "whats up there" }); + entries.push_back({"042F0087000303AB009F02EE", "apple" }); + entries.push_back({"033C006903EA0231033301AD034800060390", "never mind" }); + entries.push_back({"039C010B00060390034501B0000303C6", "good night" }); + entries.push_back({"03F60084035A000303C9030C00EA", "thank you" }); + entries.push_back({"04290045000303C603DE02F700C603390042035100990318018F", "its running away" }); + entries.push_back({"03F002EB01DD02340006037500C900060390", "flower bud" }); + entries.push_back({"03BA008700060393030902190045000303C6", "tag you're it" }); + entries.push_back({"039F01FE00BA0318018F", "go away" }); + entries.push_back({"02E8010B000303D5021603EA0237036C02B8", "look over there" }); + entries.push_back({"04290045000303C603FC021603EA0237036C02B8", "its over there" }); + entries.push_back({"02DF003C02DF0024", "lily" }); + entries.push_back({"03FC00C6034803F002EB01DD0234", "sunflower" }); + entries.push_back({"03FC000303CF00C60348000303D80006037E02EB015003FC014A0336", "skunk blossom" }); + entries.push_back({"03FC000303C602FD016E00060372029D0024", "strawberry" }); + entries.push_back({"02F4008A03FC000303B402F10024", "raspberry" }); + entries.push_back({"0438012C0006038100480402", "odd ish" }); + entries.push_back({"03A202E800E70336", "gloom" }); + entries.push_back({"03EA01A702EE000303B402E800E70336", "vile plume" }); + entries.push_back({"042F01AD033603FC02BE0024", "im sorry" }); + entries.push_back({"03FC02BE0024", "sorry" }); + entries.push_back({"03CC0084033F00A50348", "cannon" }); + entries.push_back({"03810045000603930045000303C301F2000303C6", "dig it out" }); + entries.push_back({"03810045000603A2036C017A0234", "dig there" }); + entries.push_back({"03810045000603A2", "dig" }); + entries.push_back({"03AE010202EE", "pull" }); + entries.push_back({"033F00C9000303C6", "nut" }); + entries.push_back({"03780108033C0084033F00C9", "banana" }); + entries.push_back({"03C602F4006903E4023400030360006903FC000303C6", "treasure chest" }); + entries.push_back({"03C602F4006903E40234", "treasure" }); + entries.push_back({"0372029D002400060390000303C602F4006903E40234", "buried treasure" }); + entries.push_back({"0408005D02EB0213", "hello" }); + entries.push_back({"042F01A702E500CC03E7030C00EA", "i love you" }); + entries.push_back({"04080084035701290348", "hang on" }); + entries.push_back({"03C602F40066000603660234", "treasure" }); + entries.push_back({"03960066000303C602EB015003FC000303C6", "get lost" }); + entries.push_back({"03A50024000303CF00BD040B00A8", "pee ka" }); + entries.push_back({"03A500090024000303CF00C9", "pi ka" }); + entries.push_back({"0375009C041101AD034800060381030C00EA", "behind you" }); + entries.push_back({"036F0018041101AD03480006036600EA", "behind you" }); + entries.push_back({"041101EF032A006303390024", "how many" }); + entries.push_back({"041101EF032A0063033900150258036C02B8", "how many are there" }); + entries.push_back({"03B1020A02DF001503180087000603A2", "poly wag" }); + entries.push_back({"03B1014402DF001503180087000603A2", "poly wag" }); + entries.push_back({"03B1020A02DF0015031B022B02EE", "poliwhirl" }); + entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" }); + entries.push_back({"0396008A03FC000303C602DF0024", "ghastly" }); + entries.push_back({"041101290348000303BD0234", "haunt er" }); + entries.push_back({"02FD0129035A", "wrong" }); + entries.push_back({"036C0087000303C603DE02FD0129035A", "thats wrong" }); + entries.push_back({"03D503150045000303C6", "quit" }); + entries.push_back({"03CF00C9000303B700450006038D01F2000303C6", "cut it out" }); + entries.push_back({"03CF00A503270297", "come here" }); + entries.push_back({"03CF00A5033604050297", "come here" }); + entries.push_back({"02E8010B000303D5021603EA022804050297", "look over here" }); + entries.push_back({"02E8010B000303D501F2000303C6", "look out" }); + entries.push_back({"0321012C0003036001F2000303C6", "watch out" }); + entries.push_back({"036C02B8", "there" }); + entries.push_back({"03FC03150042035A034501F2", "swing now" }); + entries.push_back({"03FC03150042035A", "swing" }); + entries.push_back({"039F020D02FD01B0000303C6", "go right" }); + entries.push_back({"02FD01B0000303C6", "right" }); + entries.push_back({"03F00258036C022E02FD01B0000303C6", "farther right" }); + entries.push_back({"039F020A02E2006903F0000303C6", "go left" }); + entries.push_back({"02E2006903F0000303C6", "left" }); + entries.push_back({"03F00258036C022B02E2006903F0000303C6", "farther left" }); + entries.push_back({"03FC000303C3014D000303B4", "stop" }); + entries.push_back({"03FC000303C3014D000303B4034501F2", "stop now" }); + entries.push_back({"03FC000303C3014D000303B4036C02B8", "stop there" }); + entries.push_back({"03FC000303A50042033F00A202FD01EF034800060390", "spin around" }); + entries.push_back({"02FD012903570318018F", "wrong way" }); + entries.push_back({"03BD0231033F00A202FD01EF034800060390", "turn around" }); + entries.push_back({"03720087000303CF00C9000303B4", "back up" }); + entries.push_back({"03C90024000303B40006039F01F80042035A", "keep going" }); + entries.push_back({"03FC000303C602F4018F00060387009C0408006600060390", "straight ahead" }); + entries.push_back({"037500C002EE0006037500AB03FC02D9", "bulb a saur" }); + entries.push_back({"03E70021033F00AB03FC02D9", "venus are" }); + entries.push_back({"03FC02EB0213000303B10213000303D8", "slowpoke" }); + entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" }); + entries.push_back({"03600252032A00840348000603870234", "charmander" }); + entries.push_back({"03C903060087000303BD0234000303A50024", "cater pie" }); + entries.push_back({"02EB014D000303B402F700AB03FC", "lapras" }); + entries.push_back({"02E20087000303B402F700AB03FC", "lapras" }); + entries.push_back({"03C302130006039900A8000303A50024", "togepi" }); + entries.push_back({"03C30213000603930045000303A500090024", "togepi" }); + entries.push_back({"03A500420339030F012C0006038700A8", "pinata" }); + entries.push_back({"03A500210339030F014D000303BD00A8", "pinata" }); + entries.push_back({"02DF004803F900420348000303BD00A503270024", "listen to me" }); + entries.push_back({"03F002FA00EA000303C6", "fruit" }); + entries.push_back({"03450213000303C6000303A8008700060390", "notepad" }); + entries.push_back({"042900420348000603A202F1002400060381000F00A50348000303C603FC", "ingredients" }); + entries.push_back({"02F4006903FC00A8000303A50024", "recipe" }); + entries.push_back({"02F4006903F90045000303A50024", "recipe" }); + entries.push_back({"0411014D000303C603FC03150024000303AB00C9000303BA018F0006038D0213", "hot sweet potato" }); + entries.push_back({"0411014D000303C603FC03150024000303B4000303BA018F0006038D0213", "hot sweet potato" }); + entries.push_back({"03D200E102EE", "cool" }); + entries.push_back({"03F001AD0348", "fine" }); + entries.push_back({"0309023703FC0213000303C9030C00EA000303C6", "youre so cute" }); + entries.push_back({"0393004803E70045000303C6000303C000E703270024", "give it to me" }); + entries.push_back({"0393004203270027036C0087000303C6", "gimme that" }); + entries.push_back({"03F602FD01F80045000303C6", "throw it" }); + entries.push_back({"03FC000303C000EA000303A5004500060390", "stupid" }); + entries.push_back({"02E20066000303C603FC000303B402E2018F", "lets play" }); + entries.push_back({"039C0108033302D603390042035A", "good morning" }); + entries.push_back({"0318018F000303CF00C9000303B4", "wake up" }); + entries.push_back({"03960066000303BD00C9000303B4", "get up" }); + entries.push_back({"04260024000303CF00A5034803DE", "e cans" }); + entries.push_back({"042C0066000303CF00A5034803DE", "e cans" }); + entries.push_back({"037E02F10042034B0045000303C604050297", "bring it here" }); + entries.push_back({"030C00EA000303CF00A503390024000303C6036C0087000303C6", "you can eat that" }); + entries.push_back({"03BA019203FC000303BD00A8000303C6", "taste it" }); + entries.push_back({"04260024000303B70045000303C6", "eat it" }); + entries.push_back({"032A0087000603A2033F00A8000303C6", "magnet" }); + entries.push_back({"03D501CE0348", "coin" }); + entries.push_back({"036600D5009F02EE", "jewel" }); + entries.push_back({"0333025500060375009F02EE", "marble" }); + entries.push_back({"03B101AA02F10045000303C603FC01", "pirate sword" }); + entries.push_back({"039C0108034501B0000303C6", "good night" }); + entries.push_back({"03D50315004803DE000303C301AD0336", "quiz time" }); + entries.push_back({"03B7002703E70024", "tv" }); + entries.push_back({"042F01B0000303D503150045000303C6", "i quit" }); + entries.push_back({"042F01AD03360006038700C60348", "im done" }); + entries.push_back({"030C00EA000303CF00A50348000303B402E2018F", "you can play" }); + entries.push_back({"03150024000303CF00A50348000303B402E2018F", "we can play" }); + entries.push_back({"0372008700060390", "bad" }); + entries.push_back({"0345014D000303C90045000303C3012F03F0", "knock it off" }); + entries.push_back({"03450213000303B402E201740042035A", "no playing" }); + entries.push_back({"03FC000303C3014D000303B4000303B402E201740042035A", "stop playing" }); + entries.push_back({"042F01AD03360345014D000303C6000303B402E201740042035A", "im not playing" }); + entries.push_back({"03D503150045000303C6", "quit" }); + entries.push_back({"03FC000303C3014D000303B4036C0087000303C6", "stop that" }); + entries.push_back({"03D802DF002103390045000303BD00C9000303B4", "clean it up" }); + entries.push_back({"03AE010B000303B70045000303BD00990318018F", "put it away" }); + entries.push_back({"03D802DF0021033F00C9000303B4", "clean up" }); + entries.push_back({"03D802DF00210348036C0087000303BD00C9000303B4", "clean that up" }); + entries.push_back({"03B70048040200EA", "tissue" }); + entries.push_back({"037500C002EE0006037500AB03FC02D9", "bulb a saur" }); + entries.push_back({"042F01B303E7002703FC02D9", "ivy saur" }); + entries.push_back({"042F01B303EA00AB03FC02D9", "ivy saur" }); + entries.push_back({"03E70021033F00AB03FC02D9", "venus are" }); + entries.push_back({"03600252032A00840348000603870234", "char mander" }); + entries.push_back({"036002520327001B02DF0009030900A50348", "char me leon" }); + entries.push_back({"0360025803DE025500060390", "chari z ard" }); + entries.push_back({"0360024000AB03DE025500060390", "chari z ard" }); + entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" }); + entries.push_back({"03210255000303BD0234000303BD009F02EE", "war tor tell" }); + entries.push_back({"03210255000303C302D9000303BD009F02EE", "war tor tell" }); + entries.push_back({"037E02E2008A03FC000303C301D403FC", "blast oise" }); + entries.push_back({"03CC0087000303BD0234000303A50024", "cater pie" }); + entries.push_back({"032A0066000303BD00A8000303B1014D00060390", "meta pod" }); + entries.push_back({"037500C9000303BD023703F002F10024", "butter free" }); + entries.push_back({"0315002400060387009F02EE", "weed el" }); + entries.push_back({"03D2010B000303D200E7033F00A8", "ka kuna" }); + entries.push_back({"03C90045000303D200E7033F00A8", "ka kuna" }); + entries.push_back({"036F00240006039002F1003C02EE", "bee drill" }); + entries.push_back({"036F00240006039002F7009F02EE", "bee drill" }); + entries.push_back({"03A5004500060366014D000303C6", "pid gee ot" }); + entries.push_back({"02F40087000303BD00A8000303BD00A8", "rat tata" }); + entries.push_back({"02F700A8000303BA00870006038700A8", "rat tata" }); + entries.push_back({"02F40087000303BA00870006038700A8", "rat tata" }); + entries.push_back({"02F40087000303B70045000303CC018F000303C6", "rat i cat" }); + entries.push_back({"03FC000303A502880213", "spear ow" }); + entries.push_back({"03ED02880213", "fear ow" }); + entries.push_back({"04260024000303CF00A5034803DE", "e cans" }); + entries.push_back({"042C0066000303CF00A5034803DE", "e cans" }); + entries.push_back({"043802550006037B014D000303D8", "ar bok" }); + entries.push_back({"03A50024000303CF00A80003036000EA", "pikachu" }); + entries.push_back({"02FD01B00003036000EA", "rye chu" }); + entries.push_back({"03FC00840348040202FA00EA", "sand shrew" }); + entries.push_back({"03FC0084034803FC02E2008A0402", "sand slash" }); + entries.push_back({"0339004500060387021F00A5034803ED0021032A018602EE", "ni doran female" }); + entries.push_back({"033900450006038D020D02F700A5034803ED0021032A017A009F02EE", "ni doran female" }); + entries.push_back({"033900450006038702190021033F00A8", "ni door ina" }); + entries.push_back({"033900240006038D0213000303D5031500210348", "nido queen" }); + entries.push_back({"033900450006038D020D02F700A50348032A018602EE", "ni doran male" }); + entries.push_back({"0339004500060387021F00A50348032A017A009F02EE", "ni doran male" }); + entries.push_back({"033900450006038D02BE002103450213", "ni dor ino" }); + entries.push_back({"033900240006038D020D02F1002103450213", "ni dor ino" }); + entries.push_back({"033900240006038D0213000303C90042035A", "ni do king" }); + entries.push_back({"03D802E2006903F0008102F10024", "cle fairy" }); + entries.push_back({"03D802E500AB03F0008102F10024", "cle fairy" }); + entries.push_back({"03D802E2006903F0018F00060375009F02EE", "cle fable" }); + entries.push_back({"03D802E500AB03F0018F00060375009F02EE", "cle fable" }); + entries.push_back({"03EA009F02EE000303A50045000303D803FC", "vol pix" }); + entries.push_back({"034501AD0348000303BA018602EE03DE", "nine tales" }); + entries.push_back({"03630045000603A202DF0024000303AB00CC03F0", "jiggly puff" }); + entries.push_back({"0363004500060399009F02DF0024000303AB00CC03F0", "jiggly puff" }); + entries.push_back({"03150045000603A202DF0024000303BD00CC03F0", "wiggly tuff" }); + entries.push_back({"03DE00EA000603720087000303C6", "zoo bat" }); + entries.push_back({"039F020A02EE000603720087000303C6", "goal bat" }); + entries.push_back({"0438012C0006038100480402", "odd ish" }); + entries.push_back({"03A202E800E70336", "gloom" }); + entries.push_back({"03EA01A702EE000303B402E800E70336", "vile plume" }); + entries.push_back({"03B1024000AB03FC", "paras" }); + entries.push_back({"03A802A300AB03FC", "paras" }); + entries.push_back({"03B1024000AB03FC0066000303D8000303C6", "para sect" }); + entries.push_back({"03A802A300AB03FC0066000303D8000303C6", "para sect" }); + entries.push_back({"03EA006303450210033C0087000303C6", "ven on at" }); + entries.push_back({"03EA0063034502100333012F03F6", "venom oth" }); + entries.push_back({"03810045000603A202E500A8000303C6", "dig let" }); + entries.push_back({"0327001501F503F6", "meow eth" }); + entries.push_back({"03AB023703E400A50348", "persian" }); + entries.push_back({"03FC01B00006038700C9000303D8", "psy duck" }); + entries.push_back({"039C010202EE0006038700C9000303D8", "goal duck" }); + entries.push_back({"032A0084035A000303C90024", "man key" }); + entries.push_back({"03B402FD01AD032A018F000303B4", "prime ape" }); + entries.push_back({"03A202FD020A02EB01B3036C", "growl ith" }); + entries.push_back({"03A202FD01E902DF0048036C", "growl ith" }); + entries.push_back({"04380255000303CC018C034501AD0348", "ar canine" }); + entries.push_back({"04380255000303CF00A5034501AD0348", "ar canine" }); + entries.push_back({"03B1020A02DF001503180087000603A2", "poly wag" }); + entries.push_back({"03B1020A02DF0015031B022B02EE", "poly whirl" }); + entries.push_back({"03B1020A02DF001E02F4008A03F6", "poly wrath" }); + entries.push_back({"03B1014402DF001E02F4008A03F6", "poly wrath" }); + entries.push_back({"042F00870006037E02F700A8", "abra" }); + entries.push_back({"03CF00A80006038400870006037E02F700A8", "ka dab ra" }); + entries.push_back({"042F007E02E500A8000303CF00AB03DE00840336", "ala ka zam" }); + entries.push_back({"032D00A800030360014D000303B4", "ma chop" }); + entries.push_back({"032D00A8000303600213000303D8", "ma choke" }); + entries.push_back({"032D00A80003036000840336000303B4", "ma champ" }); + entries.push_back({"0372005D02EE03FC000303B402FD01F2000303C6", "bell sprout" }); + entries.push_back({"03BA0063033F00A8000303CF00C002EE", "ten ta cool" }); + entries.push_back({"03BA0063033F00A8000303D802FA00E102EE", "ten ta cruel" }); + entries.push_back({"03630009030F02130006038A00EA00060390", "geo dude" }); + entries.push_back({"03A202F4008A03EA009F02E50234", "gravel er" }); + entries.push_back({"03A202F4008A03EA02E50234", "gravel er" }); + entries.push_back({"039F020A02E500A50336", "golem" }); + entries.push_back({"039F014402EE0336", "golem" }); + entries.push_back({"03B1021003390024000303BD00A8", "pony ta" }); + entries.push_back({"03B1021003390024000303C3016E", "pony ta" }); + entries.push_back({"02F40087000303A5004500060384008A0402", "rap e dash" }); + entries.push_back({"03FC02EB0213000303B10213000303D8", "slowpoke" }); + entries.push_back({"03FC02EB02130006037E02FD0213", "slow bro" }); + entries.push_back({"032A0087000603A2033F00A5033301B0000303C6", "mag ne mite" }); + entries.push_back({"032A0087000603A2033F00A8000303C3014A0348", "mag ne ton" }); + entries.push_back({"03F0025803F0006600030360000303C6", "far fetched" }); + entries.push_back({"038D02130006039002F100150213", "dod rio" }); + entries.push_back({"03F9001B02EE", "seel" }); + entries.push_back({"038A00EA0006039F014A035A", "dew gong" }); + entries.push_back({"038A00EA0006039F014A0348", "dew gong" }); + entries.push_back({"03A202FD01AD032D0234", "grim er" }); + entries.push_back({"032D00C9000303D8", "muck" }); + entries.push_back({"0402005D02EE000603870234", "shell der" }); + entries.push_back({"03D802EB01D403FC000303BD0234", "cloy ster" }); + entries.push_back({"0396008A03FC000303C602DF00", "ghastly" }); + entries.push_back({"0396008A03FC02DF0024", "ghastly" }); + entries.push_back({"041101290348000303BD0234", "haunt er" }); + entries.push_back({"03960084035A0006039F0255", "gen gar" }); + entries.push_back({"0396006303480006039F0255", "gen gar" }); + entries.push_back({"0438014A03390045000303D803FC", "on ix" }); + entries.push_back({"039002FD01F503DB0024", "drowsy" }); + entries.push_back({"039002FD021603DB0024", "drowsy" }); + entries.push_back({"04050045000303B403450213", "hip no" }); + entries.push_back({"03D802F400870006036F00", "crabby" }); + entries.push_back({"03C90042035A02E50234", "king ler" }); + entries.push_back({"03EA020A02EE000303C302D90006037E", "volt orb" }); + entries.push_back({"0426001B02E20066000303D8000303C602FD021300060390", "electrode" }); + entries.push_back({"0432009F02E20066000303D8000303C602FD021300060390", "electrode" }); + entries.push_back({"042C0066000603A203DE000303C9030C00EA000303C6", "execute" }); + entries.push_back({"042C0066000603A203DE0066000303C9030C00EA000303C302D9", "executor" }); + entries.push_back({"042C0066000603A203FC00A8000303C9030C00EA000603870234", "executor" }); + entries.push_back({"03C9030C00EA0006037B02100348", "cue bone" }); + entries.push_back({"032A02A9020403180087000303D8", "mar oh wack" }); + entries.push_back({"03330246020403180087000303D8", "mar oh wack" }); + entries.push_back({"04050045000303C603330210034802DF0024", "hit mon lee" }); + entries.push_back({"04050045000303C60333014A034802DF0024", "hit mon lee" }); + entries.push_back({"04050045000303C60333021003480003036000840348", "hit mon chan" }); + entries.push_back({"02DF0045000303C90024000303BD00A5035A", "lick eh tung" }); + entries.push_back({"02DF0045000303C90045000303BD00A5035A", "lick i tung" }); + entries.push_back({"02DF0045000303C90045000303C00108035A", "lick a tung" }); + entries.push_back({"03D5015003ED0042035A", "coughing" }); + entries.push_back({"0315002703DB0042035A", "wheezing" }); + entries.push_back({"02FD01A4041102D60348", "rye horn" }); + entries.push_back({"02FD01B00006038D01290348", "rye don" }); + entries.push_back({"03600084034803F90024", "chance e" }); + entries.push_back({"03BA0084034800060366005D02E500A8", "tangela" }); + entries.push_back({"03BA018C034800060396005D02E500A8", "tangela" }); + entries.push_back({"03CC018C035A0006039900AB03FC000303D5014A0348", "kang as khan" }); + entries.push_back({"041102DC03F90024", "horse sea" }); + entries.push_back({"03F900240006039002F700A8", "sea dra" }); + entries.push_back({"039F020A02EE0006038100210348", "gold een" }); + entries.push_back({"03F90024000303C90042035A", "seeking" }); + entries.push_back({"03FC000303C3023A030C00EA", "starry you" }); + entries.push_back({"03FC000303C3025203270024", "star me" }); + entries.push_back({"0327004803FC000303BD0231033301AD0336", "mister mime" }); + entries.push_back({"03FC01B3036C0234", "sigh ther" }); + entries.push_back({"03630042035A000303D803FC", "jynx" }); + entries.push_back({"0426001B02E20066000303D8000303BD00A80006037500CC03DE", "elect tra buzz" }); + entries.push_back({"0432009F02E20066000303D8000303BD00A80006037500CC03DE", "elect tra buzz" }); + entries.push_back({"032A0087000603A203330255", "mag mar" }); + entries.push_back({"03A50042034803FC0234", "pin sir" }); + entries.push_back({"03C3020D02FD012F03FC", "tar os" }); + entries.push_back({"03C30246021603FC", "tar os" }); + entries.push_back({"032A0087000603630045000303D50255000303B4", "magi karp" }); + entries.push_back({"039602A300A80006038D015003FC", "guy a rad os" }); + entries.push_back({"039602A300A80006038D021603FC", "guy a rad os" }); + entries.push_back({"02EB014D000303B402F700AB03FC", "lap ras" }); + entries.push_back({"02E20087000303B402F700AB03FC", "lap ras" }); + entries.push_back({"03810045000303C30213", "ditto" }); + entries.push_back({"0426002703E70024", "e v" }); + entries.push_back({"03EA018F000303B102BE0015014A0348", "vapor eon" }); + entries.push_back({"03EA00A8000303B102BE000F00A50348", "vapor eon" }); + entries.push_back({"0366020A02EE000303B70015014A0348", "jolt eon" }); + entries.push_back({"03F002E2029D0015014A0348", "flare eon" }); + entries.push_back({"03B1020D02F100240006039F014A0348", "por e gon" }); + entries.push_back({"03B1020D02F100240006039900A50348", "por e gon" }); + entries.push_back({"043B0210032D00C6034501B0000303C6", "oman ite" }); + entries.push_back({"04380129032D00A5034501B0000303C6", "oman ite" }); + entries.push_back({"043B0210032D00CC03FC000303C30255", "oma star" }); + entries.push_back({"04380129032D00AB03FC000303C30255", "oma star" }); + entries.push_back({"03CF00C90006037800EA0006038D0213", "ka boo tow" }); + entries.push_back({"03D5012C0006037800EA000303C3014D000303B403FC", "ka bu tops" }); + entries.push_back({"03D5012C0006037500A8000303C3014D000303B403FC", "ka bu tops" }); + entries.push_back({"03D5012C0006037500A8000303C3015003FC", "ka bu tops" }); + entries.push_back({"042C02A90213000603840087000303D8000303BD00C002EE", "aero dac tell" }); + entries.push_back({"03FC034502D002E20087000303D803FC", "snore lax" }); + entries.push_back({"04380255000303B70045000303D200E703450213", "art eh cuno" }); + entries.push_back({"03DE0087000303B40006038D015003FC", "zap dos" }); + entries.push_back({"03DE0087000303B40006038D021603FC", "zap dos" }); + entries.push_back({"0333020A02EE000303C602F4006903FC", "mol tres" }); + entries.push_back({"039002F700A8000303B7002103390024", "duh rat ini" }); + entries.push_back({"039002F400870006039900A5033C02B8", "dragonair" }); + entries.push_back({"039002F400870006039900A5034501B0000303C6", "dragon ite" }); + entries.push_back({"0327030C00EA000303C000EA", "mew two" }); + entries.push_back({"0327030C00EA", "mew" }); + entries.push_back({"03C3014D000303AB00AB03EA000603630045000603A202DF0024000303AB00AB03F0", "top of jiggly puff" }); + entries.push_back({"03C302130006039900A8000303A50024", "toge pi" }); + entries.push_back({"03C302130006039C010B000303A50024", "toge pi" }); + entries.push_back({"03C30213000603930045000303A500090024", "toge pi" }); + entries.push_back({"03B1014402DF001503180087000603A2", "poly wag" }); + entries.push_back({"03150024000303A50042034800060372005D02EE", "weeping bell" }); + entries.push_back({"03E70045000303D8000303C602F1002400060372005D02EE", "vic tree bell" }); + entries.push_back({"03BA0063033F00A8000303D200E102EE", "ten ta cool" }); + entries.push_back({"038700C9000603A2000303C602F100150213", "dug trio" }); + entries.push_back({"03A50045000603630024", "pid gee" }); + entries.push_back({"038D02130006038A00DB0213", "do duo" }); + entries.push_back({"03A50045000603660213000303C30213", "pid gee otto" }); + entries.push_back({"03CF00C9000303D200E7033F00A8", "ka kuna" }); + entries.push_back({"03BA00630348000303BD00A8000303D200E102EE", "ten ta cool" }); + entries.push_back({"03CC018C035A00060396008A03FC000303D5014A0348", "kang as khan" }); + entries.push_back({"043B0210032D00AB03FC000303C30255", "oma star" }); + entries.push_back({"03CF00A80006037800EA000303C3014D000303B403FC", "ka boo tops" }); + entries.push_back({"036C0087000303C603FC02FD01B0000303C6", "thats right" }); + entries.push_back({"036C0087000303C603FC0006039C010B00060390", "thats good" }); + entries.push_back({"036C0087000303C3031B00C60348", "that one" }); + entries.push_back({"036C008A03FC03F001AD0348", "thats fine" }); + entries.push_back({"036C0087000303C603DE03F001AD0348", "thats fine" }); + entries.push_back({"03CF021C0066000303D8000303C6", "correct" }); + entries.push_back({"03CF00A202F40066000303D8000303C6", "correct" }); + entries.push_back({"036F0042035A0006039F0213", "bingo" }); + entries.push_back({"03D5012302DF0045000303C6", "call it" }); + entries.push_back({"02E2006903FC000303B402E2018F", "lets play" }); + entries.push_back({"02FD0129035A", "wrong" }); + entries.push_back({"0372008700060390000303A50024000303CF00A80003036000EA", "bad pikachu" }); + entries.push_back({"0327004803FC", "miss" }); + entries.push_back({"038D02100348000303C6000303D5012302DF0045000303C6", "dont call it" }); + entries.push_back({"041101F503FC", "house" }); + entries.push_back({"041102100336", "home" }); + entries.push_back({"03EA00A202F1004500060381000F00C60348", "viridian" }); + entries.push_back({"03EA00A202F1004500060381000F00C6034803F002C400AB03FC000303C6", "viridian forest" }); + entries.push_back({"043B0213000303CF0234", "ochre" }); + entries.push_back({"043B0213000303CF0225031E010B0006039003DE", "ochre woods" }); + entries.push_back({"043B0213000303CF023703ED004803FF0042035A0411020A02EE", "ochre fishing hole" }); + entries.push_back({"03FC000303B402F10042035A02DF002703F0", "spring leaf" }); + entries.push_back({"03FC000303B402F10042035A02DF002703F003ED000F00C002EE00060390", "spring leaf field" }); + entries.push_back({"0438014402E500AB03EA01AD0348", "olivine" }); + entries.push_back({"0438014402E500AB03EA01AD034802E2018F000303D8", "olivine lake" }); + entries.push_back({"0438014402E500AB03EA01AD034803ED004803FF0042035A0411020A02EE", "olivine fishing hole" }); + entries.push_back({"03D502130006037B012302EE000303C6", "cobalt" }); + entries.push_back({"03D502130006037B012302EE000303C301A702E500C6034800060390", "cobalt island" }); + entries.push_back({"03D502130006037E03ED004803FF0042035A0411020A02EE", "cobalt fishing hole" }); + entries.push_back({"03D5021603FC000303C6", "coast" }); + entries.push_back({"03D502130006037B012302EE000303C6000303D5021603FC000303C6", "cobalt coast" }); + entries.push_back({"03FC000303A80069040200C002EE000303C602F4018C03390042035A", "special training" }); + entries.push_back({"03BD0231033F00A8000303B4", "turnip" }); + entries.push_back({"03BD02310348000303B4", "turnip" }); + entries.push_back({"03FC03150024000303C6000303AB00A8000303BA018F0006038D0213", "sweet potato" }); + entries.push_back({"0411014D000303C603FC03150024000303C6000303AE010B000303BA018F0006038D0213", "hot sweet potato" }); + entries.push_back({"03D501470300000603900006037B02D9000603900006037B014D000303D803FC", "cardboard box" }); + entries.push_back({"04080084034B00420348036C02B8", "hang in there" }); + entries.push_back({"03AE010202EE", "pull" }); + entries.push_back({"02F1001B02DF0045000303B700420348", "reel it in" }); + entries.push_back({"034501F2", "now" }); + entries.push_back({"03CC00870003035D0045000303C6", "catch it" }); + entries.push_back({"03960066000303B70045000303C6", "get it" }); + entries.push_back({"03AE010202DF0045000303C6", "pull it" }); + entries.push_back({"03AE010202EE04110255000603870234", "pull harder" }); + entries.push_back({"02E20066000303B70045000303C60006039F0213", "let it go" }); + entries.push_back({"02F1003C02DF002703F90045000303C6", "release it" }); + entries.push_back({"02E500C6034800030360", "lunch" }); + entries.push_back({"03FC033C0087000303D8", "snack" }); + entries.push_back({"02E2006903F90024000303C6", "lets eat" }); + entries.push_back({"03CF00C9000303B4000303CC018F000303D8", "cupcake" }); + entries.push_back({"042F019B00C6034800060387023703FC000303BA0084034800060390", "i understand" }); + entries.push_back({"042F01B0000603930045000303B70045000303C6", "i get it" }); + entries.push_back({"0411032101B0", "why" }); + entries.push_back({"041101F2000303CF00C60336", "how come" }); + entries.push_back({"039C010B0006037B01B0", "good bye" }); + entries.push_back({"03BA018F000303D8000303CC02B8", "take care" }); + entries.push_back({"042F019B009F02EE0327004803F9030C00EA", "ill miss you" }); + entries.push_back({"0438016502EE0327004803F9030C00EA", "ill miss you" }); + entries.push_back({"03FC000303C3014D000303B4036C0087000303C6", "stop that" }); + entries.push_back({"03D503150045000303C6", "quit" }); + entries.push_back({"03CF00C9000303B70045000303C301F2000303C6", "cut it out" }); + entries.push_back({"03CF00A503330129034802E20066000303C603DE0006039F0213", "come on lets go" }); + entries.push_back({"02E20066000303C603DE0006039F0213", "lets go" }); + entries.push_back({"031B0225012F03F0", "we re off" }); + entries.push_back({"03BA008700060393030902190045000303C6", "tag youre it" }); + entries.push_back({"03CF00C9000303B70045000303C301F2000303C6", "cut it out" }); + entries.push_back({"0411031B00A8000303C603FC02FD0129035A", "whats wrong" }); + entries.push_back({"0411031B00A8000303B7004803F90045000303C6", "what is it" }); + entries.push_back({"03CF00C603330129034802E20066000303C603DE0006039F0213", "come on lets go" }); + entries.push_back({"031502970006039F01F80042035A034501F2", "were going now" }); + entries.push_back({"02E20066000303C603FC000303600066000303C90045000303C301F2000303C6", "lets check it out" }); + entries.push_back({"03F600C6033F02370402014D000303D8", "thunder shock" }); + entries.push_back({"03F600C6033F02340006037B020A02EE000303C6", "thunderbolt" }); + entries.push_back({"043801290339030300420348", "onion" }); + entries.push_back({"03FC02DF0024000303B4000303C301B0000303C6", "sleep tight" }); + entries.push_back({"03F90009030C00EA000303C000E7033302460213", "see you tomorrow" }); + entries.push_back({"03F90009030C00CF00420348036C00C6033302D603390042035A", "see you in the morning" }); + entries.push_back({"039F0213000303BD00C6033302460213", "go tomorrow" }); + entries.push_back({"02FD014D000303D8", "rock" }); + entries.push_back({"03F9004803DE023703FC", "scissors" }); + entries.push_back({"03A8018F000303AB0234", "paper" }); + entries.push_back({"0381002A000303B10255000303C6", "depart" }); + entries.push_back({"02F10006038100EA03DE00030384002A000303B10255000303C6", "reduced depart" }); + entries.push_back({"03D5012F035D0063034800030381002A000303B10255000303C6", "caution depart" }); + entries.push_back({"02DF03FC03BD023A000603D8000303B700060381002A000303B10255000303C6", "restricted depart" }); + entries.push_back({"03B1008A03FC0042035A", "passing" }); + entries.push_back({"03FC000303C3014D000303AB0042035A", "stopping" }); + entries.push_back({"031E02DC03390042035A", "warning" }); + entries.push_back({"03AB02FA021603F9000900060390", "proceed" }); + entries.push_back({"02F10006038100EA03DE00060390", "reduced" }); + entries.push_back({"03D5012F035D00630348", "caution" }); + entries.push_back({"02DF03FC03BD023A000603D8000303B700060390", "restricted" }); + entries.push_back({"042C0066000603A203FC000303AB021C005A03DE", "express" }); + entries.push_back({"02E50042032A002A000303C6", "limit" }); + entries.push_back({"03450213000602E50042032A002A000303C6", "no limit" }); + entries.push_back({"03B7005A0348", "ten" }); + entries.push_back({"03E7002A03F6000303B700090348", "fifteen" }); + entries.push_back({"03C30318004B0339038A0024", "twenty" }); + entries.push_back({"03C30318004B0339038A002403EA019E03EA", "twenty five" }); + entries.push_back({"036C02AC03BA0027", "thirty" }); + entries.push_back({"036C02AC03BA002703EA019E03EA", "thirty five" }); + entries.push_back({"03EA02D6000603900048", "forty" }); + entries.push_back({"03EA02D600060390004803EA019E03EA", "forty five" }); + entries.push_back({"03F3005A03F0000303B70042", "fifty" }); + entries.push_back({"03F3005A03F0000303B7004203EA019E03EA", "fifty five" }); + entries.push_back({"03F9002A000303D803FC000303C00009", "sixty" }); + entries.push_back({"03F9002A000303D803FC000303C0000903EA019E03EA", "sixty five" }); + entries.push_back({"03FC004B036C00630348000303B70009", "seventy" }); + entries.push_back({"03FC004B036C00630348000303B7000903EA019E03EA", "seventy five" }); + entries.push_back({"042C018C03B70009", "eighty" }); + entries.push_back({"042C018C03B7000903EA019E03EA", "eighty five" }); + entries.push_back({"034501A103480006038A0048", "ninety" }); + entries.push_back({"034501A103480006038A004803EA019E03EA", "ninety five" }); + entries.push_back({"031B00C60348040B00BD0348038702F100060390", "one hundred" }); + entries.push_back({"031B00C60348021303F001AD03E7", "one oh five" }); + entries.push_back({"031B00C60348000303B7005A0348", "one ten" }); + entries.push_back({"031B00C60348000303E7002A03F6000303B700090348", "one fifteen" }); + entries.push_back({"031B00C60348000303C303180348000303B70024", "one twenty" }); + entries.push_back({"031B00C60348000303C303180348000303B7002403EA019E03EA", "one twenty five" }); + entries.push_back({"82B582E382C182CF82C282B582F182B182A4", "depart" }); + entries.push_back({"82B582E382C182CF82C282B082F182BB82AD", "reduced depart" }); + entries.push_back({"82B582E382C182CF82C282BF82E382A482A2", "caution depart" }); + entries.push_back({"82B582E382C182CF82C282AF82A282A982A2", "restricted depart" }); + entries.push_back({"82C282A482A9", "passing" }); + entries.push_back({"82C482A282B582E1", "stopping" }); + entries.push_back({"82AF82A282D982A482A082A9", "warning" }); + entries.push_back({"82B582F182B182A4", "proceed" }); + entries.push_back({"82B082F182BB82AD", "reduced" }); + entries.push_back({"82BF82E382A482A2", "caution" }); + entries.push_back({"82AF82A282A982A2", "restricted" }); + entries.push_back({"82C482A282B5", "stop" }); + entries.push_back({"82B182A482BB82AD", "no limit" }); + entries.push_back({"82B982A282B082F1", "limit" }); + entries.push_back({"82A982A282B682E5", "cancel" }); + entries.push_back({"82B682E382A4", "ten" }); + entries.push_back({"82B682E382A482B2", "fifteen" }); + entries.push_back({"82C982B682E382A4", "twenty" }); + entries.push_back({"82C982B682E382A482B2", "twenty five" }); + entries.push_back({"82B382F182B682E382A4", "thirty" }); + entries.push_back({"82B382F182B682E382A482B2", "thirty five" }); + entries.push_back({"82E682F182B682E382A4", "forty" }); + entries.push_back({"82E682F182B682E382A482B2", "forty five" }); + entries.push_back({"82B282B682E382A4", "fifty" }); + entries.push_back({"82B282B682E382A482B2", "fifty five" }); + entries.push_back({"82EB82AD82B682E382A4", "sixty" }); + entries.push_back({"82EB82AD82B682E382A482B2", "sixty five" }); + entries.push_back({"82C882C882B682E382A4", "seventy" }); + entries.push_back({"82C882C882B682E382A482B2", "seventy five" }); + entries.push_back({"82CD82BF82B682E382A4", "eighty" }); + entries.push_back({"82CD82BF82B682E382A482B2", "eighty five" }); + entries.push_back({"82AB82E382A482B682E382A4", "ninety" }); + entries.push_back({"82AB82E382A482B682E382A482B2", "ninety five" }); + entries.push_back({"82D082E182AD", "one hundred" }); + entries.push_back({"82D082E182AD82B2", "one oh five" }); + entries.push_back({"82D082E182AD82B682E382A4", "one ten" }); + entries.push_back({"82D082E182AD82B682E382A482B2", "one fifteen" }); + entries.push_back({"82D082E182AD82C982B682E382A4", "one twenty" }); + entries.push_back({"82D082E182AD82C982B682E382A482B2", "one twenty five" }); + + return entries; +} diff --git a/Source/RMG-Input/VRUwords.hpp b/Source/RMG-Input/VRUwords.hpp new file mode 100644 index 00000000..6cd30184 --- /dev/null +++ b/Source/RMG-Input/VRUwords.hpp @@ -0,0 +1,24 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef VRU_WORDS_HPP +#define VRU_WORDS_HPP + +#include +#include + +struct VRUWordEntry +{ + std::string hex; + std::string words; +}; + +std::vector GetVRUWordEntries(void); + +#endif // VRU_WORDS_HPP \ No newline at end of file diff --git a/Source/RMG-Input/common.hpp b/Source/RMG-Input/common.hpp index 9196d798..76552ad4 100644 --- a/Source/RMG-Input/common.hpp +++ b/Source/RMG-Input/common.hpp @@ -33,9 +33,10 @@ enum class N64ControllerButton enum class InputDeviceType { - None = -3, - Automatic = -2, - Keyboard = -1 + EmulateVRU = -4, + None = -3, + Automatic = -2, + Keyboard = -1, }; enum class InputType diff --git a/Source/RMG-Input/main.cpp b/Source/RMG-Input/main.cpp index 2e2b5355..d681141d 100644 --- a/Source/RMG-Input/main.cpp +++ b/Source/RMG-Input/main.cpp @@ -15,6 +15,9 @@ #include "Thread/SDLThread.hpp" #include "Utilities/InputDevice.hpp" #include "common.hpp" +#ifdef VRU +#include "VRU.hpp" +#endif // VRU #include @@ -269,6 +272,7 @@ static void apply_controller_profiles(void) { InputProfile* profile = &l_InputProfiles[i]; int plugin = PLUGIN_NONE; + bool emulateVRU = (profile->DeviceNum == (int)InputDeviceType::EmulateVRU); switch (profile->ControllerPak) { @@ -278,7 +282,7 @@ static void apply_controller_profiles(void) case N64ControllerPak::RumblePak: plugin = PLUGIN_RAW; break; - case N64ControllerPak::TransferPak: + case N64ControllerPak::TransferPak: plugin = PLUGIN_TRANSFER_PAK; break; default: @@ -286,10 +290,26 @@ static void apply_controller_profiles(void) break; } +#ifdef VRU + // attempt to try initializing VRU when needed, + // if it fails, unplug the VRU + if (emulateVRU && !IsVRUInit() && !InitVRU()) + { + profile->PluggedIn = false; + } +#else + // always unplug VRU when RMG-Input was built + // without VRU support + if (emulateVRU) + { + profile->PluggedIn = false; + } +#endif // VRU + l_ControlInfo.Controls[i].Present = profile->PluggedIn ? 1 : 0; - l_ControlInfo.Controls[i].Plugin = plugin; + l_ControlInfo.Controls[i].Plugin = emulateVRU ? PLUGIN_NONE : plugin; l_ControlInfo.Controls[i].RawData = 0; - l_ControlInfo.Controls[i].Type = CONT_TYPE_STANDARD; + l_ControlInfo.Controls[i].Type = emulateVRU ? CONT_TYPE_VRU : CONT_TYPE_STANDARD; } } @@ -621,7 +641,7 @@ void sdl_init() { std::filesystem::path gameControllerDbPath; - for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC}) + for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_AUDIO, SDL_INIT_VIDEO, SDL_INIT_HAPTIC}) { if (!SDL_WasInit(subsystem)) { @@ -663,6 +683,8 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Con return M64ERR_SYSTEM_FAIL; } + CoreSetupDebugCallbackMessage(DebugCallback, Context); + sdl_init(); l_SDLThread = new Thread::SDLThread(nullptr); @@ -845,6 +867,23 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys) return; } +#ifdef VRU + // when we're emulating the VRU, + // we need to check the mic state + if (profile->DeviceNum == (int)InputDeviceType::EmulateVRU) + { + if (GetVRUMicState()) + { + Keys->Value = 0x0020; + } + else + { + Keys->Value = 0x0000; + } + return; + } +#endif // VRU + // check if device has been disconnected, // if it has, try to open it again, // only do this every 2 seconds to prevent lag @@ -937,6 +976,9 @@ EXPORT void CALL RomClosed(void) { l_HasControlInfo = false; close_controllers(); +#ifdef VRU + QuitVRU(); +#endif // VRU } EXPORT void CALL SDL_KeyDown(int keymod, int keysym)