diff --git a/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.h b/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.h index 82e3cb530..7656b5700 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.h +++ b/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.h @@ -24,4 +24,5 @@ namespace TFE_DarkForces void agentMenu_createNewAgent(); void agentMenu_setAgentName(const char* name); void agentMenu_resetState(); + void setPalette(); } diff --git a/TheForceEngine/TFE_DarkForces/automap.cpp b/TheForceEngine/TFE_DarkForces/automap.cpp index 62a05b8c8..169e88336 100644 --- a/TheForceEngine/TFE_DarkForces/automap.cpp +++ b/TheForceEngine/TFE_DarkForces/automap.cpp @@ -2,38 +2,24 @@ #include "player.h" #include "hud.h" #include +#include #include #include #include #include #include #include +#include #include #include +#include #include +#include using namespace TFE_Jedi; namespace TFE_DarkForces { - enum MapWallColor - { - WCOLOR_INVISIBLE = 0, - WCOLOR_NORMAL = 10, - WCOLOR_LEDGE = 12, - WCOLOR_GRAYED_OUT = 13, - WCOLOR_DOOR = 19, - }; - - enum MapObjectColor - { - MOBJCOLOR_DEFAULT = 19, - MOBJCOLOR_PROJ = 6, - MOBJCOLOR_CORPSE = 48, - MOBJCOLOR_LANDMINE = 1, - MOBJCOLOR_PICKUP = 152, - MOBJCOLOR_SCENERY = 21, - }; enum MapConstants { @@ -112,7 +98,7 @@ namespace TFE_DarkForces SERIALIZE(SaveVersionInit, s_mapZ0, 0); SERIALIZE(SaveVersionInit, s_mapZ1, 0); SERIALIZE(SaveVersionInit, s_mapLayer, 0); - } + } // _computeScreenBounds() and computeScaledScreenBounds() in the original source: // computeScaledScreenBounds() calls _computeScreenBounds() - so merged here. @@ -291,7 +277,7 @@ namespace TFE_DarkForces case MAP_INCR_SECTOR_MODE: { s_mapShowSectorMode++; - if (s_mapShowSectorMode >= 3) + if (s_mapShowSectorMode >= 4) { s_mapShowSectorMode = 0; } @@ -489,32 +475,90 @@ namespace TFE_DarkForces automap_drawLine(x0, z0, x1, z1, color); } + // Note it assumes the wall adjoins a door sector + u8 getDoorKeyColor(RWall* wall) + { + KeyItem key = (KeyItem)sector_getKey(wall->sector); + if (key == KEY_NONE) + { + key = (KeyItem)sector_getKey(wall->nextSector); + } + switch (key) + { + case KEY_YELLOW: + return TFE_Settings::getMapColorByName("Yellow Key Wall")->colorMapIndex; + case KEY_RED: + return TFE_Settings::getMapColorByName("Red Key Wall")->colorMapIndex; + case KEY_BLUE: + return TFE_Settings::getMapColorByName("Blue Key Wall")->colorMapIndex; + default: + return TFE_Settings::getMapColorByName("Door or Elevator Wall")->colorMapIndex; + } + } + u8 automap_getWallColor(RWall* wall) { u8 color; + // Default thickness - GPU only + setLineThickness(1.5f); + if (wall->flags1 & WF1_HIDE_ON_MAP) { - color = WCOLOR_INVISIBLE; + color = TFE_Settings::getMapColorByName("Invisible Wall")->colorMapIndex; } else if (wall->flags1 & WF1_SHOW_AS_LEDGE_ON_MAP) { - color = WCOLOR_LEDGE; + color = TFE_Settings::getMapColorByName("Ledge Wall")->colorMapIndex; } else if (wall->flags1 & WF1_SHOW_AS_DOOR_ON_MAP) { - color = WCOLOR_DOOR; + color = TFE_Settings::getMapColorByName("Door or Elevator Wall")->colorMapIndex; + } + else if (wall->flags1 & WF1_SHOW_NORMAL_ON_MAP) + { + color = TFE_Settings::getMapColorByName("Normal Wall")->colorMapIndex; + } + else if (TFE_Settings::getGameSettings()->df_showKeyColors && (sector_getKey(wall->sector) || (wall->nextSector && sector_getKey(wall->nextSector)))) + { + setLineThickness(2.0f); + color = getDoorKeyColor(wall); } - else if ((wall->flags1 & WF1_SHOW_NORMAL_ON_MAP) || !wall->nextSector) + else if (TFE_Settings::getGameSettings()->df_showMapSecrets && isSecretSector(wall->sector) || wall->nextSector && isSecretSector(wall->nextSector)) { - color = WCOLOR_NORMAL; + + // If Secret is discovered color it as such. Do not show nextsector secrets if they are not on your current layer. + if (wall->sector->secretDiscovered || (wall->nextSector && wall->nextSector->secretDiscovered && wall->nextSector->layer == s_mapLayer)) + { + + color = TFE_Settings::getMapColorByName("Secret Wall")->colorMapIndex; + } + // If you have map reveal show the secret as not found. Do not show adjoined walls that don't match the current layer. + else if (s_mapShowSectorMode != 0 && isSecretSector(wall->sector) && wall->sector->layer == s_mapLayer + && !(wall->nextSector && wall->nextSector->layer != s_mapLayer)) + { + color = TFE_Settings::getMapColorByName("Secret Not Found Wall")->colorMapIndex; + } + // Show it as a normal sector if no cheats and you didn't discover it. + else + { + color = TFE_Settings::getMapColorByName("Normal Wall")->colorMapIndex; + } + } + else if (s_mapShowSectorMode == 3 && !wall->seen) + { + color = TFE_Settings::getMapColorByName("Undiscovered Wall")->colorMapIndex; + } + else if (!wall->nextSector) + { + color = TFE_Settings::getMapColorByName("Normal Wall")->colorMapIndex; } else if (sector_isDoor(wall->sector) || sector_isDoor(wall->nextSector)) { - color = WCOLOR_DOOR; + color = TFE_Settings::getMapColorByName("Door or Elevator Wall")->colorMapIndex; } else if (s_mapShowSectorMode == 2) { - color = WCOLOR_GRAYED_OUT; + color = TFE_Settings::getMapColorByName("Grayed Out Wall")->colorMapIndex; } else { @@ -525,11 +569,11 @@ namespace TFE_DarkForces fixed16_16 floorDelta = TFE_Jedi::abs(curFloorHeight - nextFloorHeight); if (floorDelta >= 0x4000) // 0.25 units { - color = WCOLOR_LEDGE; + color = TFE_Settings::getMapColorByName("Ledge Wall")->colorMapIndex; } else { - color = WCOLOR_INVISIBLE; + color = TFE_Settings::getMapColorByName("Invisible Wall")->colorMapIndex; } } @@ -552,7 +596,7 @@ namespace TFE_DarkForces } u8 color = automap_getWallColor(wall); - if (color != WCOLOR_INVISIBLE) + if (color != TFE_Settings::getMapColorByName("Invisible Wall")->colorMapIndex) { automap_drawWall(wall, color); } @@ -579,28 +623,34 @@ namespace TFE_DarkForces void automap_drawObject(SecObject* obj) { - u8 color = MOBJCOLOR_DEFAULT; + + if (!TFE_Settings::getGameSettings()->df_showMapObjects) + { + return; + } + + u8 color = TFE_Settings::getMapColorByName("Default Object")->colorMapIndex; if (obj->flags & OBJ_FLAG_NEEDS_TRANSFORM) { if (obj->entityFlags & ETFLAG_PROJECTILE) { - color = MOBJCOLOR_PROJ; + color = TFE_Settings::getMapColorByName("Projectile Object")->colorMapIndex; } else if (obj->entityFlags & ETFLAG_CORPSE) { - color = MOBJCOLOR_CORPSE; + color = TFE_Settings::getMapColorByName("Corpse Object")->colorMapIndex; } else if (obj->entityFlags & ETFLAG_LANDMINE) { - color = MOBJCOLOR_LANDMINE; + color = TFE_Settings::getMapColorByName("Landmine Object")->colorMapIndex; } else if (obj->entityFlags & ETFLAG_PICKUP) { - color = MOBJCOLOR_PICKUP; + color = TFE_Settings::getMapColorByName("Pickup Object")->colorMapIndex; } else if (obj->entityFlags & ETFLAG_SCENERY) { - color = MOBJCOLOR_SCENERY; + color = TFE_Settings::getMapColorByName("Scenery Object")->colorMapIndex; } ObjectType type = obj->type; diff --git a/TheForceEngine/TFE_DarkForces/automap.h b/TheForceEngine/TFE_DarkForces/automap.h index 5af5449b5..c61a68db2 100644 --- a/TheForceEngine/TFE_DarkForces/automap.h +++ b/TheForceEngine/TFE_DarkForces/automap.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace TFE_DarkForces { diff --git a/TheForceEngine/TFE_DarkForces/player.cpp b/TheForceEngine/TFE_DarkForces/player.cpp index d45fe8de2..e5a6fefe6 100644 --- a/TheForceEngine/TFE_DarkForces/player.cpp +++ b/TheForceEngine/TFE_DarkForces/player.cpp @@ -2324,13 +2324,15 @@ namespace TFE_DarkForces } } - if (newSector->flags1 & SEC_FLAGS1_SECRET) + if (isSecretSector(newSector) && !newSector->secretDiscovered) { // If enabled, show the secret found message. tfe_showSecretFoundMsg(); + newSector->secretDiscovered = true; // Remove the flag so the secret isn't counted twice. - newSector->flags1 &= ~SEC_FLAGS1_SECRET; + // No Longer needed ? + // newSector->flags1 &= ~SEC_FLAGS1_SECRET; s_secretsFound++; level_updateSecretPercent(); } diff --git a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp index 9212ae21c..b4938f9d7 100644 --- a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp +++ b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp @@ -2,6 +2,7 @@ #include "console.h" #include "profilerView.h" #include "modLoader.h" +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -32,15 +34,18 @@ #include #include // Game +#include #include #include #include #include +#include #include #include #include #include #include +#include #include using namespace TFE_Input; @@ -186,6 +191,58 @@ namespace TFE_FrontEndUI "True Color", // COLORMODE_TRUE_COLOR }; + // This is temporary until we can select GPU cololrs for everything. + // We'll use the first 24 colors + static const char* c_hudMapColorNames[] = + { + "Black", + "White", + "Light gray", + "Sky blue", + "Medium light blue", + "Mid blue", + "Bright red", + "Deep red", + "Dark burgundy", + "Very dark red", + "Neon green", + "Lime green", + "Forest green", + "Dark green", + "Dark teal", + "Bright blue", + "Medium blue", + "Royal blue", + "Navy blue", + "Yellow", + "Golden yellow", + "Orange", + "Dark orange", + "Reddish brown", + }; + + const int numColors = sizeof(c_hudMapColorNames) / sizeof(c_hudMapColorNames[0]); + + static const char* c_hudMapColors[] = + { + "Normal Wall", + "Ledge Wall", + "Grayed Out Wall", + "Door or Elevator Wall", + "Undiscovered Wall", + "Secret Wall", + "Secret Not Found Wall", + "Red Key Wall", + "Blue Key Wall", + "Yellow Key Wall", + "Default Object", + "Projectile Object", + "Corpse Object", + "Landmine Object", + "Pickup Object", + "Scenery Object", + }; + typedef void(*MenuItemSelected)(); static s32 s_resIndex = 0; @@ -194,6 +251,11 @@ namespace TFE_FrontEndUI static char* s_manualDisplayStr = nullptr; static char* s_creditsDisplayStr = nullptr; + static s32 s_mapColorIndex = 0; + static bool s_colorSet = false; + static s32 s_origMapColorIndex = 0; + static s32 s_mapColor = 0; + static AppState s_appState; static AppState s_menuRetState; static ImFont* s_menuFont; @@ -352,6 +414,21 @@ namespace TFE_FrontEndUI { TFE_System::logWrite(LOG_ERROR, "SystemUI", "Cannot load TFE Title: \"UI_Images/Gradient.png\""); } + //colorMap["Normal"] = WCOLOR_NORMAL; + + enum MapWallColor + { + WCOLOR_INVISIBLE = 0, + WCOLOR_NORMAL = 10, + WCOLOR_LEDGE = 12, + WCOLOR_GRAYED_OUT = 13, + WCOLOR_DOOR = 20, + WCOLOR_SECRET = 1, + }; + + /*for (int i = 0; i < numColors; ++i) { + colorMap[c_hudMapColorNames[i]] = c_hudMapColors[i]; + }*/ bool buttonsLoaded = true; buttonsLoaded &= loadGpuImage("UI_Images/TFE_StartNormal.png", &s_buttonNormal[0]); @@ -3256,6 +3333,111 @@ namespace TFE_FrontEndUI ImGui::SetNextItemWidth(128 * s_uiScale); ImGui::InputInt("##HudOffsetYText", &hud->pixelOffset[2], 1, 10); + ImGui::Separator(); + ImGui::LabelText("##", "AutoMap Colors"); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f * s_uiScale); + + TFE_Settings_Game* gameSettings = TFE_Settings::getGameSettings(); + + bool showKeyColors = gameSettings->df_showKeyColors; + if (ImGui::Checkbox("Apply a key color to locked key doors and switches ", &showKeyColors)) + { + gameSettings->df_showKeyColors = showKeyColors; + } + + bool showMapSecrets = gameSettings->df_showMapSecrets; + if (ImGui::Checkbox("Show Secrets on the AutoMap", &showMapSecrets)) + { + gameSettings->df_showMapSecrets = showMapSecrets; + } + + bool showMapObjects = gameSettings->df_showMapObjects; + if (ImGui::Checkbox("Show Objects on the AutoMap", &showMapObjects)) + { + gameSettings->df_showMapObjects = showMapObjects; + } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f * s_uiScale); + ImGui::LabelText("##AutoMapType", "Map Color Type:"); + + ImGui::SetNextItemWidth(160 * s_uiScale); + if (ImGui::Combo("##MapWall", &s_mapColor, c_hudMapColors, IM_ARRAYSIZE(c_hudMapColors), IM_ARRAYSIZE(c_hudMapColors))) + { + s_colorSet = false; + } + + string colorMapTitle = c_hudMapColors[s_mapColor]; + TFE_Settings_Map_Colors * colorStruct = TFE_Settings::getMapColorByName(colorMapTitle); + s_mapColorIndex = colorStruct->colorMapIndex; + + if (!s_colorSet) + { + s_origMapColorIndex = s_mapColorIndex; + s_colorSet = true; + } + + // Get the color RGB + std::tuple rgba = colorStruct->RGBA; + ImU32 imguiColor = IM_COL32(std::get<0>(rgba), std::get<1>(rgba), std::get<2>(rgba), std::get<3>(rgba)); + + + ImGui::LabelText("##AutoMapColor", "Choose your color:"); + ImGui::SetNextItemWidth(160 * s_uiScale); + + // Update the color as you hover over something. + const float max_height = ImGui::GetTextLineHeightWithSpacing() * 25; + ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, max_height)); + + if (ImGui::BeginCombo("##MapColors", c_hudMapColorNames[s_mapColorIndex])) + { + for (int i = 0; i < IM_ARRAYSIZE(c_hudMapColorNames); i++) + { + const bool isSelected = (s_mapColorIndex == i); + if (ImGui::Selectable(c_hudMapColorNames[i], isSelected)) + { + s_origMapColorIndex = i; + } + if (ImGui::IsItemHovered()) + { + s_mapColorIndex = i; + TFE_Settings::setMapColor(colorMapTitle, s_mapColorIndex); + } + } + ImGui::EndCombo(); + } + else + { + TFE_Settings::setMapColor(colorMapTitle, s_origMapColorIndex); + } + + ImGui::SameLine(0.0f, 10.0f * s_uiScale); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImVec2 pos = ImGui::GetCursorScreenPos(); // current position in layout + draw_list->AddRectFilled(pos, + ImVec2(pos.x + 50, pos.y + 50), + imguiColor); + // Reserve space so layout continues below the square + ImGui::Dummy(ImVec2(50, 50)); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f * s_uiScale); + ImGui::Separator(); + ImGui::TextWrapped("Map Colors are saved in the file map_colors.txt"); + + if (ImGui::Button("Reset Colors to Default")) + { + s_colorSet = false; + TFE_Settings::resetMapColorsFromDefault(); + } + + if (ImGui::Button("Open AutoMap Config Folder")) + { + if (!TFE_System::osShellExecute(TFE_Paths::getPath(PATH_USER_DOCUMENTS), NULL, NULL, false)) + { + TFE_System::logWrite(LOG_ERROR, "frontEndUi", "Failed to open the directory: '%s'", s_replayDir); + } + } + // Clamp pixel offsets to avoid fixed-point overflow. const s32 maxOffset = 16383; hud->pixelOffset[0] = clamp(hud->pixelOffset[0], -maxOffset, maxOffset); diff --git a/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp b/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp index f58afbd74..7d5048e0c 100644 --- a/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp +++ b/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp @@ -3835,4 +3835,27 @@ namespace TFE_Jedi } return JFALSE; } + + u8 sector_getKey(RSector * sec) + { + Allocator* links = sec->infLink; + InfLink* link = (InfLink*)allocator_getHead(links); + KeyItem key = KEY_NONE; + while (link) + { + if (link->elev) + { + KeyItem infKey = link->elev->key; + if (infKey == KEY_BLUE || + infKey == KEY_RED || + infKey == KEY_YELLOW) + { + return infKey; + } + } + link = (InfLink*)allocator_getNext(links); + } + if (!link) return 0; + return key; + } } diff --git a/TheForceEngine/TFE_Jedi/InfSystem/infSystem.h b/TheForceEngine/TFE_Jedi/InfSystem/infSystem.h index a3b0b32bd..2d495e055 100644 --- a/TheForceEngine/TFE_Jedi/InfSystem/infSystem.h +++ b/TheForceEngine/TFE_Jedi/InfSystem/infSystem.h @@ -87,4 +87,5 @@ namespace TFE_Jedi void inf_sendLinkMessages(Allocator* infLink, SecObject* entity, u32 evt, MessageType msgType); JBool sector_isDoor(RSector* sector); + u8 sector_getKey(RSector * sec); } diff --git a/TheForceEngine/TFE_Jedi/Level/level.cpp b/TheForceEngine/TFE_Jedi/Level/level.cpp index 2101ef05b..1802ea293 100644 --- a/TheForceEngine/TFE_Jedi/Level/level.cpp +++ b/TheForceEngine/TFE_Jedi/Level/level.cpp @@ -142,6 +142,12 @@ namespace TFE_Jedi { (*sector->floorTex)->flags |= ALWAYS_FULLBRIGHT; } + + // Update secret status for the automap + if (sector->flags1 & SEC_FLAGS1_SECRET) + { + sector->secretSector = JTRUE; + } } // Setup the control sector. diff --git a/TheForceEngine/TFE_Jedi/Level/rsector.cpp b/TheForceEngine/TFE_Jedi/Level/rsector.cpp index 1bcc8d223..7a138e4a3 100644 --- a/TheForceEngine/TFE_Jedi/Level/rsector.cpp +++ b/TheForceEngine/TFE_Jedi/Level/rsector.cpp @@ -1311,4 +1311,10 @@ namespace TFE_Jedi { return (p1.x - p0.x) * (p2.z - p0.z) - (p2.x - p0.x) * (p1.z - p0.z); } + + // Is sector a secret sector? + bool isSecretSector(RSector* sector) + { + return sector->secretSector; + } } // namespace TFE_Jedi \ No newline at end of file diff --git a/TheForceEngine/TFE_Jedi/Level/rsector.h b/TheForceEngine/TFE_Jedi/Level/rsector.h index f99a561cd..a0299e8f5 100644 --- a/TheForceEngine/TFE_Jedi/Level/rsector.h +++ b/TheForceEngine/TFE_Jedi/Level/rsector.h @@ -137,6 +137,11 @@ struct RSector // Added for TFE, to support floating point and GPU sub-renderers. u32 dirtyFlags; u32 searchKey; + + // For visualization on the map + bool secretDiscovered = false; + bool secretSector = false; + }; namespace TFE_Jedi @@ -172,4 +177,6 @@ namespace TFE_Jedi JBool sector_canRotateWalls(RSector* sector, angle14_32 angle, fixed16_16 centerX, fixed16_16 centerZ); void sector_rotateWalls(RSector* sector, fixed16_16 centerX, fixed16_16 centerZ, angle14_32 angle, u32 rotateFlags); void sector_rotateObjects(RSector* sector, angle14_32 deltaAngle, fixed16_16 centerX, fixed16_16 centerZ, u32 flags); + + bool isSecretSector(RSector* sector); } \ No newline at end of file diff --git a/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.cpp b/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.cpp index 2b7aa7507..b669950ed 100644 --- a/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.cpp +++ b/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.cpp @@ -54,6 +54,8 @@ namespace TFE_Jedi static u32 s_scrQuadsWidth; static u32 s_scrQuadsHeight; + float lineThickness = 1.5f; + struct ShaderSettingsSDGPU { bool bloom = false; @@ -315,13 +317,18 @@ namespace TFE_Jedi TFE_RenderShared::lineDraw2d_addLine(1.5f, &vtx[3], colors); } + void setLineThickness(f32 thickness) + { + lineThickness = thickness; + } + void screenGPU_drawLine(ScreenRect* rect, s32 x0, s32 z0, s32 x1, s32 z1, u8 color) { u32 color32 = vfb_getPalette()[color]; u32 colors[] = { color32, color32 }; Vec2f vtx[] = { f32(x0), f32(z0), f32(x1), f32(z1) }; - TFE_RenderShared::lineDraw2d_addLine(1.5f, vtx, colors); + TFE_RenderShared::lineDraw2d_addLine(lineThickness, vtx, colors); } void screenGPU_blitTexture(TextureData* texture, DrawRect* rect, s32 x0, s32 y0, JBool forceTransparency, JBool forceOpaque) diff --git a/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.h b/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.h index b53fdf0b0..87425cdaf 100644 --- a/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.h +++ b/TheForceEngine/TFE_Jedi/Renderer/RClassic_GPU/screenDrawGPU.h @@ -28,6 +28,7 @@ namespace TFE_Jedi void screenGPU_setHudTextureCallbacks(s32 count, TextureListCallback* callbacks, bool forceAllocation = false); void screenGPU_setIndexedColors(u32 count, const Vec4f* colors); + void setLineThickness(f32 thickness); void screenGPU_drawPoint(ScreenRect* rect, s32 x, s32 z, u8 color); void screenGPU_drawLine(ScreenRect* rect, s32 x0, s32 z0, s32 x1, s32 z1, u8 color); diff --git a/TheForceEngine/TFE_Settings/settings.cpp b/TheForceEngine/TFE_Settings/settings.cpp index ae08a57d9..6cd2395f6 100644 --- a/TheForceEngine/TFE_Settings/settings.cpp +++ b/TheForceEngine/TFE_Settings/settings.cpp @@ -82,6 +82,31 @@ namespace TFE_Settings "CVar", }; + // Note I think we can just get rid of the WCOLOR keywords. I left them for the POC. + TFE_Settings_Map_Colors defaultAutoMapColors[] = { + {"WCOLOR_INVISIBLE", "Invisible Wall", 0, {0, 0, 0, 255}}, + {"WCOLOR_NORMAL", "Normal Wall", 10, {0, 252, 0, 255}}, + {"WCOLOR_UNDISCOVERED", "Undiscovered Wall", 1, {252, 252, 252, 255} }, + {"WCOLOR_LEDGE", "Ledge Wall", 12, {0, 152, 0, 255}}, + {"WCOLOR_GRAYED_OUT", "Grayed Out Wall", 13, {0, 92, 0, 255}}, + {"WCOLOR_DOOR", "Door or Elevator Wall", 20, {244, 184, 52, 255}}, + {"WCOLOR_SECRET", "Secret Wall", 22, {216, 88, 12, 255}}, + {"WCOLOR_SECRET_NOT_FOUND", "Secret Not Found Wall", 4, {124, 204, 252, 255}}, + {"KEY_COLOR_RED", "Red Key Wall", 6, {252, 0, 0, 255}}, + {"KEY_COLOR_BLUE", "Blue Key Wall", 17, {0, 16, 188, 255}}, + {"KEY_COLOR_YELLOW", "Yellow Key Wall", 19, {248, 224, 96, 255}}, + {"MOBJCOLOR_DEFAULT", "Default Object", 19, {248, 224, 96, 255}}, + {"MOBJCOLOR_PROJ", "Projectile Object", 6, {252, 0, 0, 255}}, + {"MOBJCOLOR_CORPSE", "Corpse Object", 2, {208, 236, 252, 255}}, + {"MOBJCOLOR_LANDMINE", "Landmine Object", 1, {252, 252, 252, 255}}, + {"MOBJCOLOR_PICKUP", "Pickup Object", 16,{0, 36, 240, 255}}, + {"MOBJCOLOR_SCENERY", "Scenery Object",21, {184, 44, 4, 255}} + }; + + int autoMapColorsLen = sizeof(defaultAutoMapColors) / sizeof(defaultAutoMapColors[0]); + + std::vector autoMapColors; + ////////////////////////////////////////////////////////////////////////////////// // Forward Declarations ////////////////////////////////////////////////////////////////////////////////// @@ -116,7 +141,7 @@ namespace TFE_Settings ////////////////////////////////////////////////////////////////////////////////// // Implementation - ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// bool init(bool& firstRun) { // Clear out game settings. @@ -150,6 +175,7 @@ namespace TFE_Settings { // Write any settings to disk before shutting down. writeToDisk(); + writeRGBAToJSON(); } void autodetectGamePaths() @@ -545,6 +571,9 @@ namespace TFE_Settings writeKeyValue_Bool(settings, "df_enableRecordingAll", s_gameSettings.df_enableRecordingAll); writeKeyValue_Bool(settings, "df_demologging", s_gameSettings.df_demologging); writeKeyValue_Bool(settings, "df_autoNextMission", s_gameSettings.df_autoEndMission); + writeKeyValue_Bool(settings, "df_showKeyColors", s_gameSettings.df_showKeyColors); + writeKeyValue_Bool(settings, "df_showMapSecrets", s_gameSettings.df_showMapSecrets); + writeKeyValue_Bool(settings, "df_showMapObjects", s_gameSettings.df_showMapObjects); } void writePerGameSettings(FileStream& settings) @@ -1206,6 +1235,18 @@ namespace TFE_Settings { s_gameSettings.df_autoEndMission = parseBool(value); } + else if (strcasecmp("df_showKeyColors", key) == 0) + { + s_gameSettings.df_showKeyColors = parseBool(value); + } + else if (strcasecmp("df_showMapSecrets", key) == 0) + { + s_gameSettings.df_showMapSecrets = parseBool(value); + } + else if (strcasecmp("df_showMapObjects", key) == 0) + { + s_gameSettings.df_showMapObjects = parseBool(value); + } } void parseOutlawsSettings(const char* key, const char* value) @@ -1742,4 +1783,173 @@ namespace TFE_Settings } free(data); } + + // Once the GPU PDA is setup we will not need this function + void updateRGBAFromJson(cJSON* array, string RGBName) { + if (cJSON_IsArray(array) && cJSON_GetArraySize(array) == 4) { + cJSON* rItem = cJSON_GetArrayItem(array, 0); + cJSON* gItem = cJSON_GetArrayItem(array, 1); + cJSON* bItem = cJSON_GetArrayItem(array, 2); + cJSON* alpha = cJSON_GetArrayItem(array, 3); + + if (cJSON_IsNumber(rItem) && cJSON_IsNumber(gItem) && cJSON_IsNumber(bItem)) { + + for (int i = 0; i < autoMapColorsLen; i++) + { + if (strcasecmp(autoMapColors[i].name.c_str(), RGBName.c_str()) == 0) + { + tuple key = { rItem->valueint, gItem->valueint, bItem->valueint }; + int RGBidx = rgbToIndexMap.find(key) != rgbToIndexMap.end() ? rgbToIndexMap[key] : -1; + if (RGBidx != -1) + { + autoMapColors[i].RGBA = { rItem->valueint, gItem->valueint, bItem->valueint, alpha->valueint }; + autoMapColors[i].colorMapIndex = RGBidx; + break; + } + else { + TFE_System::logWrite(LOG_ERROR, "Settings", "map_colors.txt color array for %s is invalid", RGBName); + } + } + } + } + TFE_System::logWrite(LOG_ERROR, "Settings", "map_colors.txt color array is invalid"); + } + } + + void writeRGBAToJSON() + { + FileStream file; + char fileName[TFE_MAX_PATH]; + sprintf(fileName, "%smap_colors.txt", TFE_Paths::getPath(PATH_USER_DOCUMENTS)); + FileUtil::fixupPath(fileName); + + int fileHandler = file.open(fileName, Stream::MODE_WRITE); + if (!fileHandler) { + TFE_System::logWrite(LOG_ERROR, "Settings", "Cannot Write %s for new colors", fileName); + return; + } + + TFE_System::logWrite(LOG_MSG, "Settings", "Writing map_colors.txt for new colors"); + + cJSON* root = cJSON_CreateObject(); + for (int i = 0; i < autoMapColorsLen; i++) + { + cJSON* colorArray = cJSON_CreateArray(); + + u8 r = get<0>(autoMapColors[i].RGBA); + u8 g = get<1>(autoMapColors[i].RGBA); + u8 b = get<2>(autoMapColors[i].RGBA); + u8 a = get<3>(autoMapColors[i].RGBA); + + cJSON_AddItemToArray(colorArray, cJSON_CreateNumber(r)); + cJSON_AddItemToArray(colorArray, cJSON_CreateNumber(g)); + cJSON_AddItemToArray(colorArray, cJSON_CreateNumber(b)); + cJSON_AddItemToArray(colorArray, cJSON_CreateNumber(a)); + cJSON_AddItemToObject(root, autoMapColors[i].name.c_str(), colorArray); + } + char* jsonString = cJSON_Print(root); + file.writeBuffer(jsonString, strlen(jsonString)); + free(jsonString); + cJSON_Delete(root); + file.close(); + } + + void resetMapColorsFromDefault() + { + // copy the automap colors from the default one. + autoMapColors.assign(std::begin(defaultAutoMapColors), std::end(defaultAutoMapColors)); + + } + + // Update all the colors from map_colors.txt + void updateWallColorsFromJson() { + + // Populates the color index to RGB map. + for (const auto& pair : rgbToIndexMap) { + indexToRGBMap[pair.second] = pair.first; + } + + resetMapColorsFromDefault(); + defaultAutoMapColors[0].colorMapIndex = 5; + autoMapColors[0].colorMapIndex = 7; + TFE_System::logWrite(LOG_MSG, "Settings", "idx = %d", defaultAutoMapColors[0].colorMapIndex); + + FileStream file; + char fileName[TFE_MAX_PATH]; + sprintf(fileName, "%smap_colors.txt", TFE_Paths::getPath(PATH_USER_DOCUMENTS)); + FileUtil::fixupPath(fileName); + + int fileHandler = file.open(fileName, Stream::MODE_READ); + if (!fileHandler) { return; } + + TFE_System::logWrite(LOG_MSG, "Settings", "Parsing map_colors.txt for new colors"); + + const size_t size = file.getSize(); + char* data = (char*)malloc(size + 1); + if (!data || size == 0) + { + TFE_System::logWrite(LOG_ERROR, "Settings", "map_colors.txt found but is %u bytes in size and cannot be read.", size); + return; + } + file.readBuffer(data, (u32)size); + data[size] = 0; + file.close(); + + cJSON* root = cJSON_Parse(data); + if (root) + { + cJSON* curElem = root->child; + + // Loop through all the color definitions. + for (; curElem; curElem = curElem->next) + { + if (!curElem->string) { continue; } + + updateRGBAFromJson(curElem, curElem->string); + } + } + } + + TFE_Settings_Map_Colors * getMapColorByName(string name) + { + for (int i = 0; i < autoMapColorsLen; i++) + { + if (strcasecmp(autoMapColors[i].description.c_str(), name.c_str()) == 0) + { + return &autoMapColors[i]; + } + } + TFE_System::logWrite(LOG_ERROR, "Settings", "BAD STRING %s", name); + + TFE_Settings_Map_Colors empty; + return ∅ + } + + + TFE_Settings_Map_Colors* getMapColorByCMPIndex(int index) + { + for (int i = 0; i < autoMapColorsLen; i++) + { + if (autoMapColors[i].colorMapIndex == index) + { + return &autoMapColors[i]; + } + } + TFE_Settings_Map_Colors empty; + return ∅ + } + + void setMapColor(string mapTypeColor, int index) + { + for (int i = 0; i < autoMapColorsLen; i++) + { + if (strcasecmp(autoMapColors[i].description.c_str(), mapTypeColor.c_str()) == 0) + { + autoMapColors[i].colorMapIndex = index; + tuple rgb = indexToRGBMap[index]; + autoMapColors[i].RGBA = { get<0>(rgb), get<1>(rgb), get<2>(rgb), 255 }; + break; + } + } + } } diff --git a/TheForceEngine/TFE_Settings/settings.h b/TheForceEngine/TFE_Settings/settings.h index f65d8d1d3..e7b7c9ae5 100644 --- a/TheForceEngine/TFE_Settings/settings.h +++ b/TheForceEngine/TFE_Settings/settings.h @@ -164,6 +164,45 @@ static const char* c_tfePitchLimit[] = "Maximum" }; + +// This mapping will no longer be needed once GPU colors are setup. +static std::map, int> rgbToIndexMap = { + {{0, 0, 0}, 0}, + {{252, 252, 252}, 1}, + {{208, 236, 252}, 2}, + {{168, 220, 252}, 3}, + {{124, 204, 252}, 4}, + {{84, 192, 252}, 5}, + {{252, 0, 0}, 6}, + {{204, 0, 0}, 7}, + {{144, 0, 0}, 8}, + {{68, 0, 0}, 9}, + {{0, 252, 0}, 10}, + {{0, 200, 0}, 11}, + {{0, 152, 0}, 12}, + {{0, 92, 0}, 13}, + {{0, 52, 0}, 14}, + {{0, 88, 252}, 15}, + {{0, 36, 240}, 16}, + {{0, 16, 188}, 17}, + {{0, 4, 140}, 18}, + {{248, 224, 96}, 19}, + {{244, 184, 52}, 20}, + {{244, 136, 12}, 21}, + {{216, 88, 12}, 22}, + {{180, 44, 4}, 23} +}; + +static std::map> indexToRGBMap = {}; + +struct TFE_Settings_Map_Colors +{ + string name; + string description; + u8 colorMapIndex = 0; + std::tuple RGBA = { 0, 0, 0, 0 }; // RGBA +}; + struct TFE_Settings_Hud { // Determines whether the HUD stays the same size on screen regardless of resolution or if it gets smaller with higher resolution. @@ -227,9 +266,12 @@ struct TFE_Settings_Game bool df_enableReplay = false; // Enable replay of gameplay. bool df_showReplayCounter = false; // Show the replay counter on the HUD. bool df_demologging = false; // Log the record/playback logging - bool df_autoEndMission = false; // Automatically skip to the next mission + bool df_autoEndMission = false; // Automatically skip to the next mission s32 df_recordFrameRate = 4; // Recording Framerate value s32 df_playbackFrameRate = 2; // Playback Framerate value + bool df_showKeyColors = true; // Show key colors in the automap. + bool df_showMapSecrets = true; // Show secrets on the automap. + bool df_showMapObjects = true; // Show objects on the automap. PitchLimit df_pitchLimit = PITCH_VANILLA_PLUS; }; @@ -405,6 +447,8 @@ struct TFE_ModSettings namespace TFE_Settings { + extern std::vector autoMapColors; + extern int autoMapColorsLen; bool init(bool& firstRun); void shutdown(); @@ -447,4 +491,10 @@ namespace TFE_Settings void loadCustomModSettings(); void parseIniFile(const char* buffer, size_t len); void writeDarkForcesGameSettings(FileStream& settings); + void updateWallColorsFromJson(); + void writeRGBAToJSON(); + TFE_Settings_Map_Colors * getMapColorByName(string name); + TFE_Settings_Map_Colors * getMapColorByCMPIndex(int index); + void setMapColor(string mapTypeColor, int index); + void resetMapColorsFromDefault(); } diff --git a/TheForceEngine/main.cpp b/TheForceEngine/main.cpp index b06e47ebe..f542d6107 100644 --- a/TheForceEngine/main.cpp +++ b/TheForceEngine/main.cpp @@ -627,6 +627,8 @@ int main(int argc, char* argv[]) TFE_SaveSystem::init(); TFE_A11Y::init(); + TFE_Settings::updateWallColorsFromJson(); + // Uncomment to test memory region allocator. // TFE_Memory::region_test();