Path: blob/master/RSDKv5/RSDK/Core/Legacy/v4/RetroEnginev4.cpp
1167 views
#include "RetroEnginev4.hpp"12bool32 RSDK::Legacy::v4::LoadGameConfig(const char *filepath)3{4char strBuffer[0x40];5StrCopy(gameVerInfo.gameTitle, "Retro-Engine"); // this is the default window name67globalVariablesCount = 0;8#if RETRO_USE_MOD_LOADER9modSettings.playerCount = 0;10#endif1112FileInfo info;13InitFileInfo(&info);1415bool32 loaded = LoadFile(&info, filepath, FMODE_RB);16if (loaded) {17ReadString(&info, gameVerInfo.gameTitle);18ReadString(&info, gameVerInfo.gameSubtitle);1920uint8 buf[3];21for (int32 c = 0; c < 0x60; ++c) {22ReadBytes(&info, buf, 3);23SetPaletteEntry(-1, c, buf[0], buf[1], buf[2]);24}2526// Read Obect Names27uint8 objectCount = ReadInt8(&info);28for (int32 o = 0; o < objectCount; ++o) {29ReadString(&info, strBuffer);30}3132// Read Script Paths33for (int32 s = 0; s < objectCount; ++s) {34ReadString(&info, strBuffer);35}3637globalVariablesCount = ReadInt8(&info);38for (int32 v = 0; v < globalVariablesCount; ++v) {39// Read Variable Name40ReadString(&info, globalVariables[v].name);4142// Read Variable Value43globalVariables[v].value = ReadInt8(&info) << 0;44globalVariables[v].value |= ReadInt8(&info) << 8;45globalVariables[v].value |= ReadInt8(&info) << 16;46globalVariables[v].value |= ReadInt8(&info) << 24;47}4849// Read SFX50globalSFXCount = ReadInt8(&info);51for (int32 s = 0; s < globalSFXCount; ++s) { // Sfx Names52ReadString(&info, strBuffer);53SetSfxName(strBuffer, s);54}5556for (int32 s = 0; s < globalSFXCount; ++s) { // Sfx Paths57ReadString(&info, strBuffer);58RSDK::Legacy::LoadSfx(strBuffer, s, SCOPE_GLOBAL);59}6061// Read Player Names62uint8 plrCount = ReadInt8(&info);63for (uint8 p = 0; p < plrCount; ++p) {64ReadString(&info, strBuffer);6566#if RETRO_USE_MOD_LOADER67// needed for PlayerName[] stuff in scripts68StrCopy(modSettings.playerNames[p], strBuffer);69modSettings.playerCount++;70#endif71}7273// Read ahead and get scene count74int32 storedPos = info.readPos;7576int32 totalSceneCount = 0;77sceneInfo.categoryCount = STAGELIST_MAX;78for (uint8 c = 0; c < sceneInfo.categoryCount; ++c) {79int32 count = ReadInt8(&info);80for (int32 s = 0; s < count; ++s) {81ReadString(&info, strBuffer);82ReadString(&info, strBuffer);83ReadString(&info, strBuffer);84ReadInt8(&info);85}8687totalSceneCount += count;88}8990if (!totalSceneCount)91totalSceneCount = 1;9293int32 startScene = 0;94#if !RETRO_USE_ORIGINAL_CODE95if (strlen(currentSceneFolder) && strlen(currentSceneID)) {96#if RETRO_USE_MOD_LOADER97listData.resize(totalSceneCount + 1);98sceneInfo.listData = listData.data();99#else100AllocateStorage((void **)&sceneInfo.listData, sizeof(SceneListEntry) * (totalSceneCount + 1), DATASET_STG, false);101#endif102SceneListEntry *scene = &sceneInfo.listData[totalSceneCount];103strcpy(scene->name, "_RSDK_SCENE");104strcpy(scene->folder, currentSceneFolder);105strcpy(scene->id, currentSceneID);106scene->filter = sceneInfo.filter;107GEN_HASH_MD5(scene->name, scene->hash);108109// Override existing values110sceneInfo.activeCategory = 0;111startScene = totalSceneCount;112currentSceneFolder[0] = 0;113currentSceneID[0] = 0;114}115else {116#endif117118#if RETRO_USE_MOD_LOADER119listData.resize(totalSceneCount);120sceneInfo.listData = listData.data();121#else122AllocateStorage((void **)&sceneInfo.listData, sizeof(SceneListEntry) * totalSceneCount, DATASET_STG, false);123#endif //! RETRO_USE_MOD_LOADER124125#if !RETRO_USE_ORIGINAL_CODE126}127#endif128129AllocateStorage((void **)&sceneInfo.listCategory, sizeof(SceneListInfo) * sceneInfo.categoryCount, DATASET_STG, true);130131char categoryNames[STAGELIST_MAX][0x20] = {132"Presentation",133"Regular",134"Special",135"Bonus",136};137138// Jump back and properly load scene info139Seek_Set(&info, storedPos);140141int32 sceneID = 0;142for (uint8 c = 0; c < sceneInfo.categoryCount; ++c) {143SceneListInfo *category = &sceneInfo.listCategory[c];144StrCopy(category->name, categoryNames[c]);145GEN_HASH_MD5(category->name, category->hash);146147category->sceneOffsetStart = sceneID;148category->sceneCount = ReadInt8(&info);149for (int32 s = 0; s < category->sceneCount; ++s) {150SceneListEntry *scene = &sceneInfo.listData[sceneID + s];151152ReadString(&info, scene->folder);153154ReadString(&info, scene->id);155156ReadString(&info, scene->name);157GEN_HASH_MD5(scene->name, scene->hash);158159// highlighted (doesn't care)160ReadInt8(&info);161}162163category->sceneOffsetEnd = category->sceneOffsetStart + category->sceneCount - 1;164sceneID += category->sceneCount;165}166167CloseFile(&info);168169sceneInfo.listPos = startScene;170171#if RETRO_USE_MOD_LOADER172v4::LoadGameXML();173SetGlobalVariableByName("options.devMenuFlag", engine.devMenu ? 1 : 0);174SetGlobalVariableByName("engine.standalone", 0);175#endif176177SetGlobalVariableByName("game.hasPlusDLC", !RSDK_AUTOBUILD);178179usingBytecode = false;180InitFileInfo(&info);181if (useDataPack && LoadFile(&info, "Bytecode/GlobalCode.bin", FMODE_RB)) {182usingBytecode = true;183CloseFile(&info);184}185}186187// These need to be set every time its reloaded188nativeFunctionCount = 0;189190nativeFunctionCount = 0;191AddNativeFunction("SetAchievement", SetAchievement);192AddNativeFunction("SetLeaderboard", SetLeaderboard);193AddNativeFunction("HapticEffect", HapticEffect);194195// AddNativeFunction("Connect2PVS", Connect2PVS);196// AddNativeFunction("Disconnect2PVS", Disconnect2PVS);197// AddNativeFunction("SendEntity", SendEntity);198// AddNativeFunction("SendValue", SendValue);199// AddNativeFunction("ReceiveEntity", ReceiveEntity);200// AddNativeFunction("ReceiveValue", ReceiveValue);201// AddNativeFunction("TransmitGlobal", TransmitGlobal);202// AddNativeFunction("ShowPromoPopup", ShowPromoPopup);203204AddNativeFunction("NotifyCallback", NotifyCallback);205206#if RETRO_USE_MOD_LOADER207AddNativeFunction("ExitGame", ExitGame);208AddNativeFunction("FileExists", FileExists);209AddNativeFunction("OpenModMenu", OpenModMenu); // Opens the dev menu-based mod menu incase you cant be bothered or smth210AddNativeFunction("AddAchievement", AddGameAchievement);211AddNativeFunction("SetAchievementDescription", SetAchievementDescription);212AddNativeFunction("ClearAchievements", ClearAchievements);213AddNativeFunction("GetAchievementCount", GetAchievementCount);214AddNativeFunction("GetAchievement", GetAchievement);215AddNativeFunction("GetAchievementName", GetAchievementName);216AddNativeFunction("GetAchievementDescription", GetAchievementDescription);217AddNativeFunction("GetScreenWidth", GetScreenWidth);218AddNativeFunction("SetScreenWidth", SetScreenWidth);219AddNativeFunction("GetWindowScale", GetWindowScale);220AddNativeFunction("SetWindowScale", SetWindowScale);221AddNativeFunction("GetWindowScaleMode", GetWindowScaleMode);222AddNativeFunction("SetWindowScaleMode", SetWindowScaleMode);223AddNativeFunction("GetWindowFullScreen", GetWindowFullScreen);224AddNativeFunction("SetWindowFullScreen", SetWindowFullScreen);225AddNativeFunction("GetWindowBorderless", GetWindowBorderless);226AddNativeFunction("SetWindowBorderless", SetWindowBorderless);227AddNativeFunction("GetWindowVSync", GetWindowVSync);228AddNativeFunction("SetWindowVSync", SetWindowVSync);229AddNativeFunction("ApplyWindowChanges", ApplyWindowChanges); // Refresh window after changing window options230AddNativeFunction("GetModCount", GetModCount);231AddNativeFunction("GetModName", GetModName);232AddNativeFunction("GetModDescription", GetModDescription);233AddNativeFunction("GetModAuthor", GetModAuthor);234AddNativeFunction("GetModVersion", GetModVersion);235AddNativeFunction("GetModActive", GetModActive);236AddNativeFunction("SetModActive", SetModActive);237AddNativeFunction("MoveMod", MoveMod);238AddNativeFunction("RefreshEngine", RefreshEngine); // Reload engine after changing mod status239#endif240241return loaded;242}243244void RSDK::Legacy::v4::ProcessEngine()245{246switch (gameMode) {247case ENGINE_DEVMENU:248ProcessInput();249currentScreen = &screens[0];250251if (devMenu.state)252devMenu.state();253break;254255case ENGINE_MAINGAME: ProcessStage(); break;256257case ENGINE_INITDEVMENU:258LoadGameConfig("Data/Game/GameConfig.bin");259InitFirstStage();260ResetCurrentStageFolder();261break;262263case ENGINE_WAIT:264break;265// case ENGINE_RESETGAME: break;266267case ENGINE_SCRIPTERROR: {268currentScreen = screens;269FillScreen(0x000000, 0x10, 0x10, 0x10);270271int32 yOff = DevOutput_GetStringYSize(scriptErrorMessage);272DrawDevString(scriptErrorMessage, 8, currentScreen->center.y - (yOff >> 1) + 8, 0, 0xF0F0F0);273274ProcessInput();275if (controller[CONT_ANY].keyStart.press || controller[CONT_ANY].keyA.press) {276OpenDevMenu();277}278else if (controller[CONT_ANY].keyB.press) {279ResetCurrentStageFolder();280sceneInfo.activeCategory = 0;281gameMode = ENGINE_MAINGAME;282stageMode = STAGEMODE_LOAD;283sceneInfo.listPos = 0;284}285else if (controller[CONT_ANY].keyC.press) {286ResetCurrentStageFolder();287#if RETRO_USE_MOD_LOADER288RefreshModFolders();289#endif290gameMode = ENGINE_MAINGAME;291stageMode = STAGEMODE_LOAD;292}293break;294}295296case ENGINE_INITPAUSE:297case ENGINE_EXITPAUSE: gameMode = ENGINE_MAINGAME; break;298299case ENGINE_ENDGAME:300case ENGINE_RESETGAME:301sceneInfo.activeCategory = 0;302sceneInfo.listPos = 0;303gameMode = ENGINE_MAINGAME;304stageMode = STAGEMODE_LOAD;305break;306307default: break;308}309}310311#if RETRO_USE_MOD_LOADER312void RSDK::Legacy::v4::LoadGameXML(bool pal)313{314FileInfo info;315SortMods();316for (int32 m = 0; m < modList.size(); ++m) {317if (!modList[m].active)318break;319SetActiveMod(m);320InitFileInfo(&info);321if (LoadFile(&info, "Data/Game/Game.xml", FMODE_RB)) {322tinyxml2::XMLDocument *doc = new tinyxml2::XMLDocument;323324char *xmlData = new char[info.fileSize + 1];325ReadBytes(&info, xmlData, info.fileSize);326xmlData[info.fileSize] = 0;327CloseFile(&info);328329doc->Parse(xmlData);330const tinyxml2::XMLElement *gameElement = doc->FirstChildElement("game"); // gameElement is nullptr if parse failure331332if (gameElement) {333if (pal)334LoadXMLPalettes(gameElement);335else {336LoadXMLWindowText(gameElement);337LoadXMLVariables(gameElement);338LoadXMLObjects(gameElement);339LoadXMLSoundFX(gameElement);340LoadXMLPlayers(gameElement);341LoadXMLStages(gameElement);342}343}344else {345PrintLog(PRINT_NORMAL, "[MOD] Failed to parse Game.xml file for mod %s", modList[m].id.c_str());346}347348delete[] xmlData;349delete doc;350}351}352SetActiveMod(-1);353}354355void RSDK::Legacy::v4::LoadXMLWindowText(const tinyxml2::XMLElement *gameElement)356{357const tinyxml2::XMLElement *titleElement = gameElement->FirstChildElement("title");358if (titleElement) {359const tinyxml2::XMLAttribute *nameAttr = titleElement->FindAttribute("name");360if (nameAttr)361StrCopy(gameVerInfo.gameTitle, nameAttr->Value());362}363}364365void RSDK::Legacy::v4::LoadXMLVariables(const tinyxml2::XMLElement *gameElement)366{367const tinyxml2::XMLElement *variablesElement = gameElement->FirstChildElement("variables");368if (variablesElement) {369for (const tinyxml2::XMLElement *varElement = variablesElement->FirstChildElement("variable"); varElement;370varElement = varElement->NextSiblingElement("variable")) {371const tinyxml2::XMLAttribute *nameAttr = varElement->FindAttribute("name");372const char *varName = "unknownVariable";373if (nameAttr)374varName = nameAttr->Value();375376const tinyxml2::XMLAttribute *valAttr = varElement->FindAttribute("value");377int32 varValue = 0;378if (valAttr)379varValue = valAttr->IntValue();380381if (globalVariablesCount >= LEGACY_GLOBALVAR_COUNT)382PrintLog(PRINT_ERROR, "[MOD] ERROR: Failed to add global variable '%s' (max limit reached)", varName);383else if (GetGlobalVariableID(varName) == 0xFF) {384StrCopy(globalVariables[globalVariablesCount].name, varName);385globalVariables[globalVariablesCount].value = varValue;386globalVariablesCount++;387}388}389}390}391392void RSDK::Legacy::v4::LoadXMLPalettes(const tinyxml2::XMLElement *gameElement)393{394const tinyxml2::XMLElement *paletteElement = gameElement->FirstChildElement("palette");395if (paletteElement) {396for (const tinyxml2::XMLElement *clrElement = paletteElement->FirstChildElement("color"); clrElement;397clrElement = clrElement->NextSiblingElement("color")) {398const tinyxml2::XMLAttribute *bankAttr = clrElement->FindAttribute("bank");399int32 clrBank = 0;400if (bankAttr)401clrBank = bankAttr->IntValue();402403const tinyxml2::XMLAttribute *indAttr = clrElement->FindAttribute("index");404int32 clrInd = 0;405if (indAttr)406clrInd = indAttr->IntValue();407408const tinyxml2::XMLAttribute *rAttr = clrElement->FindAttribute("r");409int32 clrR = 0;410if (rAttr)411clrR = rAttr->IntValue();412413const tinyxml2::XMLAttribute *gAttr = clrElement->FindAttribute("g");414int32 clrG = 0;415if (gAttr)416clrG = gAttr->IntValue();417418const tinyxml2::XMLAttribute *bAttr = clrElement->FindAttribute("b");419int32 clrB = 0;420if (bAttr)421clrB = bAttr->IntValue();422423SetPaletteEntry(clrBank, clrInd, clrR, clrG, clrB);424}425426for (const tinyxml2::XMLElement *clrsElement = paletteElement->FirstChildElement("colors"); clrsElement;427clrsElement = clrsElement->NextSiblingElement("colors")) {428const tinyxml2::XMLAttribute *bankAttr = clrsElement->FindAttribute("bank");429int32 bank = 0;430if (bankAttr)431bank = bankAttr->IntValue();432433const tinyxml2::XMLAttribute *indAttr = clrsElement->FindAttribute("start");434int32 index = 0;435if (indAttr)436index = indAttr->IntValue();437438std::string text = clrsElement->GetText();439// working: AABBFF #FFaaFF (12, 32, 34) (145 53 234)440std::regex search(R"((?:#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2}))|(?:\((\d+),?\s*(\d+),?\s*(\d+)\)))",441std::regex_constants::icase | std::regex_constants::ECMAScript);442std::smatch match;443while (std::regex_search(text, match, search)) {444int32 r, g, b;445int32 base, start;446if (match[1].matched) {447// we have hex448base = 16;449start = 1;450}451else {452// triplet453base = 10;454start = 4;455}456457r = std::stoi(match[start + 0].str(), nullptr, base);458g = std::stoi(match[start + 1].str(), nullptr, base);459b = std::stoi(match[start + 2].str(), nullptr, base);460461SetPaletteEntry(bank, index++, r, g, b);462text = match.suffix();463}464}465}466}467468void RSDK::Legacy::v4::LoadXMLObjects(const tinyxml2::XMLElement *gameElement)469{470modObjCount = 0;471472const tinyxml2::XMLElement *objectsElement = gameElement->FirstChildElement("objects");473if (objectsElement) {474for (const tinyxml2::XMLElement *objElement = objectsElement->FirstChildElement("object"); objElement;475objElement = objElement->NextSiblingElement("object")) {476const tinyxml2::XMLAttribute *nameAttr = objElement->FindAttribute("name");477const char *objName = "unknownObject";478if (nameAttr)479objName = nameAttr->Value();480481const tinyxml2::XMLAttribute *scrAttr = objElement->FindAttribute("script");482const char *objScript = "unknownObject.txt";483if (scrAttr)484objScript = scrAttr->Value();485486uint8 flags = 0;487488// forces the object to be loaded, this means the object doesn't have to be and *SHOULD NOT* be in the stage object list489// if it is, it'll cause issues!!!!490const tinyxml2::XMLAttribute *loadAttr = objElement->FindAttribute("forceLoad");491int32 objForceLoad = false;492if (loadAttr)493objForceLoad = loadAttr->BoolValue();494495flags |= (objForceLoad & 1);496497StrCopy(modTypeNames[modObjCount], objName);498StrCopy(modScriptPaths[modObjCount], objScript);499modScriptFlags[modObjCount] = flags;500modObjCount++;501}502}503}504505void RSDK::Legacy::v4::LoadXMLSoundFX(const tinyxml2::XMLElement *gameElement)506{507const tinyxml2::XMLElement *soundsElement = gameElement->FirstChildElement("sounds");508if (soundsElement) {509for (const tinyxml2::XMLElement *sfxElement = soundsElement->FirstChildElement("soundfx"); sfxElement;510sfxElement = sfxElement->NextSiblingElement("soundfx")) {511const tinyxml2::XMLAttribute *nameAttr = sfxElement->FindAttribute("name");512const char *sfxName = "unknownSFX";513if (nameAttr)514sfxName = nameAttr->Value();515516const tinyxml2::XMLAttribute *valAttr = sfxElement->FindAttribute("path");517const char *sfxPath = "unknownSFX.wav";518if (valAttr)519sfxPath = valAttr->Value();520521SetSfxName(sfxName, globalSFXCount);522523RSDK::Legacy::LoadSfx((char *)sfxPath, globalSFXCount, SCOPE_GLOBAL);524globalSFXCount++;525}526}527}528529void RSDK::Legacy::v4::LoadXMLPlayers(const tinyxml2::XMLElement *gameElement)530{531const tinyxml2::XMLElement *playersElement = gameElement->FirstChildElement("players");532if (playersElement) {533for (const tinyxml2::XMLElement *plrElement = playersElement->FirstChildElement("player"); plrElement;534plrElement = plrElement->NextSiblingElement("player")) {535const tinyxml2::XMLAttribute *nameAttr = plrElement->FindAttribute("name");536const char *plrName = "unknownPlayer";537if (nameAttr)538plrName = nameAttr->Value();539540StrCopy(modSettings.playerNames[modSettings.playerCount++], plrName);541}542}543}544545void RSDK::Legacy::v4::LoadXMLStages(const tinyxml2::XMLElement *gameElement)546{547const char *elementNames[] = { "presentationStages", "regularStages", "bonusStages", "specialStages" };548549for (int32 l = 0; l < sceneInfo.categoryCount; ++l) {550const tinyxml2::XMLElement *listElement = gameElement->FirstChildElement(elementNames[l]);551SceneListInfo *list = &sceneInfo.listCategory[l];552if (listElement) {553for (const tinyxml2::XMLElement *stgElement = listElement->FirstChildElement("stage"); stgElement;554stgElement = stgElement->NextSiblingElement("stage")) {555const tinyxml2::XMLAttribute *nameAttr = stgElement->FindAttribute("name");556const char *stgName = "unknownStage";557if (nameAttr)558stgName = nameAttr->Value();559560const tinyxml2::XMLAttribute *folderAttr = stgElement->FindAttribute("folder");561const char *stgFolder = "unknownStageFolder";562if (folderAttr)563stgFolder = folderAttr->Value();564565const tinyxml2::XMLAttribute *idAttr = stgElement->FindAttribute("id");566const char *stgID = "unknownStageID";567if (idAttr)568stgID = idAttr->Value();569570listData.emplace(listData.begin() + list->sceneOffsetEnd);571SceneListEntry *scene = &listData[list->sceneOffsetEnd];572573sprintf_s(scene->name, sizeof(scene->name), "%s", stgName);574GEN_HASH_MD5(scene->name, scene->hash);575sprintf_s(scene->folder, sizeof(scene->folder), "%s", stgFolder);576sprintf_s(scene->id, sizeof(scene->id), "%s", stgID);577578scene->filter = 0xFF;579580list->sceneCount++;581list->sceneOffsetEnd++;582for (int32 c = l + 1; c < sceneInfo.categoryCount; ++c) sceneInfo.listCategory[c].sceneOffsetStart++;583}584}585}586sceneInfo.listData = listData.data();587}588589#endif590591592