From 0fa486b9f0b871b08da525be062cd7e33dd87419 Mon Sep 17 00:00:00 2001 From: immibis Date: Sat, 18 Nov 2023 19:06:37 +0100 Subject: [PATCH] Add a career mode. The contents of the spaceship are saved on liftoff and restored when loading a level. At the beginning, all levels are unlocked. --- colobot-base/common/event.h | 1 + colobot-base/common/restext.cpp | 2 + colobot-base/common/restext.h | 1 + colobot-base/level/level_category.cpp | 2 + colobot-base/level/level_category.h | 1 + colobot-base/level/robotmain.cpp | 170 ++++++++++++------- colobot-base/level/robotmain.h | 8 +- colobot-base/object/auto/autobase.cpp | 57 ++++++- colobot-base/object/object_manager.h | 8 +- colobot-base/ui/screen/screen_level_list.cpp | 9 +- colobot-base/ui/screen/screen_main_menu.cpp | 13 +- 11 files changed, 199 insertions(+), 73 deletions(-) diff --git a/colobot-base/common/event.h b/colobot-base/common/event.h index 95b462c2..d151f0c8 100644 --- a/colobot-base/common/event.h +++ b/colobot-base/common/event.h @@ -225,6 +225,7 @@ enum EventType EVENT_INTERFACE_SATCOM = 414, EVENT_INTERFACE_PLUS = 415, EVENT_INTERFACE_MODS = 416, + EVENT_INTERFACE_CAREER = 417, EVENT_INTERFACE_CHAP = 420, EVENT_INTERFACE_LIST = 421, diff --git a/colobot-base/common/restext.cpp b/colobot-base/common/restext.cpp index 92301b23..afc85f83 100644 --- a/colobot-base/common/restext.cpp +++ b/colobot-base/common/restext.cpp @@ -79,6 +79,7 @@ void InitializeRestext() stringsText[RT_TITLE_READ] = TR("Load a saved mission"); stringsText[RT_TITLE_PLUS] = TR("Missions+"); stringsText[RT_TITLE_MODS] = TR("Mods"); + stringsText[RT_TITLE_CAREER] = TR("Select destination"); stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:"); stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:"); @@ -190,6 +191,7 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_FREE] = TR("Free game\\Free game without a specific goal"); stringsEvent[EVENT_INTERFACE_CODE_BATTLES] = TR("Code battles\\Program your robot to be the best of them all!"); stringsEvent[EVENT_INTERFACE_USER] = TR("Custom levels\\Levels from mods created by the users"); + stringsEvent[EVENT_INTERFACE_CAREER] = TR("Career mode"); stringsEvent[EVENT_INTERFACE_SATCOM] = TR("SatCom"); stringsEvent[EVENT_INTERFACE_MODS] = TR("Mods\\Mod manager"); stringsEvent[EVENT_INTERFACE_NAME] = TR("Change player\\Change player"); diff --git a/colobot-base/common/restext.h b/colobot-base/common/restext.h index 107e8d66..290e54b3 100644 --- a/colobot-base/common/restext.h +++ b/colobot-base/common/restext.h @@ -73,6 +73,7 @@ enum ResTextType RT_TITLE_USER = 52, RT_TITLE_PLUS = 53, RT_TITLE_MODS = 54, + RT_TITLE_CAREER = 55, RT_PLAY_CHAP_CHAPTERS = 60, RT_PLAY_CHAP_PLANETS = 61, diff --git a/colobot-base/level/level_category.cpp b/colobot-base/level/level_category.cpp index eee644fe..dfb5467b 100644 --- a/colobot-base/level/level_category.cpp +++ b/colobot-base/level/level_category.cpp @@ -22,6 +22,7 @@ #include // NOTE: Because of how save filenames are built, the first letter of category directories MUST be unique!! +// Except career because it is a special case. // TODO: I'm not sure about "challenges" + "custom". It may be messing things up already right now. const std::map CATEGORY_DIR_MAP = { { LevelCategory::Missions, "missions" }, @@ -31,6 +32,7 @@ const std::map CATEGORY_DIR_MAP = { { LevelCategory::CodeBattles, "battles" }, { LevelCategory::GamePlus, "plus" }, { LevelCategory::CustomLevels, "custom" }, + { LevelCategory::CareerMode, "career" }, }; std::string GetLevelCategoryDir(LevelCategory category) diff --git a/colobot-base/level/level_category.h b/colobot-base/level/level_category.h index c6066440..21bfca58 100644 --- a/colobot-base/level/level_category.h +++ b/colobot-base/level/level_category.h @@ -30,6 +30,7 @@ enum class LevelCategory CodeBattles, GamePlus, CustomLevels, + CareerMode, Max, }; diff --git a/colobot-base/level/robotmain.cpp b/colobot-base/level/robotmain.cpp index 81d50adb..d8396a9c 100644 --- a/colobot-base/level/robotmain.cpp +++ b/colobot-base/level/robotmain.cpp @@ -3768,6 +3768,29 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) throw CLevelParserException("Unknown command: '" + line->GetCommand() + "' in " + line->GetLevelFilename() + ":" + StrUtils::ToString(line->GetLineNumber())); } + // Load the spaceship contents + if (m_levelCategory == LevelCategory::CareerMode) { + CObject* base = m_objMan->FindNearest(nullptr, OBJECT_BASE, 10000000.0f); + if(base) { + std::string saveDir = GetPlayerProfile()->GetSaveFile("__spaceship__"); // TODO: change save path? + + for (CObject* obj : m_objMan->GetAllObjects()) + { + if (obj == base) continue; + if (IsObjectBeingTransported(obj)) continue; + + glm::vec3 oPos = obj->GetPosition(); + float dist = Math::DistanceProjected(base->GetPosition(), oPos); + if ( dist < 32.0f ) + { + m_objMan->DeleteObject(obj); + } + } + + IOReadScene(saveDir+"/data.sav", saveDir+"/cbot.run", true, base->GetPosition()); + } + } + // Do this here to prevent the first frame from taking a long time to render m_engine->UpdateGroundSpotTextures(); @@ -4521,7 +4544,7 @@ void CRobotMain::SaveOneScript(CObject *obj) CProgramStorageObject* programStorage = dynamic_cast(obj); - char categoryChar = GetLevelCategoryDir(m_levelCategory)[0]; + char categoryChar = (m_levelCategory == LevelCategory::CareerMode ? 'X' : GetLevelCategoryDir(m_levelCategory)[0]); programStorage->SaveAllUserPrograms(m_playerProfile->GetSaveFile(StrUtils::Format("%c%.3d%.3d", categoryChar, m_levelChap, m_levelRank))); } @@ -4617,7 +4640,7 @@ bool CRobotMain::IOIsBusy() } //! Writes an object into the backup file -void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std::string& programDir, int objRank) +void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std::string& programDir, int objRank, bool directProgramStorageIndex) { line->AddParam("type", std::make_unique(obj->GetType())); line->AddParam("id", std::make_unique(obj->GetID())); @@ -4647,17 +4670,32 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std:: if (obj->Implements(ObjectInterfaceType::ProgramStorage)) { CProgramStorageObject* programStorage = dynamic_cast(obj); - if (programStorage->GetProgramStorageIndex() >= 0) + + // directProgramStorageIndex=false: format for mission save files - pre-existing level objects have a unique index shared between levels, and non-pre-existing objects have 999-objIndex (maximum 999 and the last few may conflict with pre-existing objects) + // directProgramStorageIndex=true: format for career save files, program storage index is just the object rank, and we save it to allow future versions to change the index allocation. + + if (directProgramStorageIndex) { + int oldIndex = programStorage->GetProgramStorageIndex(); + programStorage->SetProgramStorageIndex(objRank); programStorage->SaveAllProgramsForSavedScene(line, programDir); + programStorage->SetProgramStorageIndex(oldIndex); + line->AddParam("programStorageIndex", std::make_unique(objRank)); } else { - // Probably an object created after the scene started, not loaded from level file - // This means it doesn't normally store programs so it doesn't have program storage id assigned - programStorage->SetProgramStorageIndex(999-objRank); // Set something that won't collide with normal programs - programStorage->SaveAllProgramsForSavedScene(line, programDir); - programStorage->SetProgramStorageIndex(-1); // Disable again + if (programStorage->GetProgramStorageIndex() >= 0) + { + programStorage->SaveAllProgramsForSavedScene(line, programDir); + } + else + { + // Probably an object created after the scene started, not loaded from level file + // This means it doesn't normally store programs so it doesn't have program storage id assigned + programStorage->SetProgramStorageIndex(999-objRank); // Set something that won't collide with normal programs + programStorage->SaveAllProgramsForSavedScene(line, programDir); + programStorage->SetProgramStorageIndex(-1); // Disable again + } } if (obj->Implements(ObjectInterfaceType::Programmable)) @@ -4671,6 +4709,39 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std:: } } +void CRobotMain::IOWriteObjectTree(CLevelParser& levelParser, CObject* obj, std::string const& dirname, int& objRank, bool directProgramStorageIndex) +{ + if (obj->GetType() == OBJECT_TOTO) return; + if (IsObjectBeingTransported(obj)) return; + if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*obj).IsDying()) return; + + CLevelParserLineUPtr line; + + if (obj->Implements(ObjectInterfaceType::Slotted)) + { + CSlottedObject* slotted = dynamic_cast(obj); + for (int slot = slotted->GetNumSlots() - 1; slot >= 0; slot--) + { + if (CObject *sub = slotted->GetSlotContainedObject(slot)) + { + if (slot == slotted->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER)) + line = std::make_unique("CreatePower"); + else if (slot == slotted->MapPseudoSlot(CSlottedObject::Pseudoslot::CARRYING)) + line = std::make_unique("CreateFret"); + else + line = std::make_unique("CreateSlotObject"); + line->AddParam("slotNum", std::make_unique(slot)); + IOWriteObject(line.get(), sub, dirname, objRank++, directProgramStorageIndex); + levelParser.AddLine(std::move(line)); + } + } + } + + line = std::make_unique("CreateObject"); + IOWriteObject(line.get(), obj, dirname, objRank++, directProgramStorageIndex); + levelParser.AddLine(std::move(line)); +} + //! Saves the current game bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave) { @@ -4735,33 +4806,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s int objRank = 0; for (CObject* obj : m_objMan->GetAllObjects()) { - if (obj->GetType() == OBJECT_TOTO) continue; - if (IsObjectBeingTransported(obj)) continue; - if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*obj).IsDying()) continue; - - if (obj->Implements(ObjectInterfaceType::Slotted)) - { - CSlottedObject* slotted = dynamic_cast(obj); - for (int slot = slotted->GetNumSlots() - 1; slot >= 0; slot--) - { - if (CObject *sub = slotted->GetSlotContainedObject(slot)) - { - if (slot == slotted->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER)) - line = std::make_unique("CreatePower"); - else if (slot == slotted->MapPseudoSlot(CSlottedObject::Pseudoslot::CARRYING)) - line = std::make_unique("CreateFret"); - else - line = std::make_unique("CreateSlotObject"); - line->AddParam("slotNum", std::make_unique(slot)); - IOWriteObject(line.get(), sub, dirname, objRank++); - levelParser.AddLine(std::move(line)); - } - } - } - - line = std::make_unique("CreateObject"); - IOWriteObject(line.get(), obj, dirname, objRank++); - levelParser.AddLine(std::move(line)); + IOWriteObjectTree(levelParser, obj, dirname, objRank, false); } try { @@ -4834,12 +4879,18 @@ void CRobotMain::IOWriteSceneFinished() } //! Resumes the game -CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank) +CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank, glm::vec3 offsetPosition, bool isSpaceshipSave) { ObjectCreateParams params = CObject::ReadCreateParams(line); params.power = -1.0f; params.id = line->GetParam("id")->AsInt(); + if(isSpaceshipSave) + { + // Ignore object ID in save file. It will conflict with existing objects in the world. Does it matter that the IDs change? + params.id = -1; + } + std::string details = objCounterText; // Object categories may spoil the level a bit, so hide them in release builds @@ -4855,7 +4906,7 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& pro if (obj->Implements(ObjectInterfaceType::Old)) { COldObject* oldObj = dynamic_cast(obj); - oldObj->SetPosition(line->GetParam("pos")->AsPoint() * g_unit); + oldObj->SetPosition(line->GetParam("pos")->AsPoint() * g_unit + offsetPosition); oldObj->SetRotation(line->GetParam("angle")->AsPoint() * Math::DEG_TO_RAD); } @@ -4874,7 +4925,7 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& pro if (obj->Implements(ObjectInterfaceType::ProgramStorage)) { CProgramStorageObject* programStorage = dynamic_cast(obj); - if (!line->GetParam("programStorageIndex")->IsDefined()) // Backwards compatibility + if (!line->GetParam("programStorageIndex")->IsDefined()) // Backwards compatibility, also used for spaceship saves programStorage->SetProgramStorageIndex(objRank); programStorage->LoadAllProgramsForSavedScene(line, programDir); } @@ -4883,7 +4934,7 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& pro } //! Resumes some part of the game -CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) +CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot, bool isSpaceshipSave, glm::vec3 offsetPosition) { std::string dirname = filename.substr(0, filename.find_last_of("/")); @@ -4902,40 +4953,43 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) std::map slots; for (auto& line : levelParser.GetLines()) { - if (line->GetCommand() == "Mission") - m_gameTime = line->GetParam("gametime")->AsFloat(0.0f); - - if (line->GetCommand() == "Map") - m_map->ZoomMap(line->GetParam("zoom")->AsFloat()); - - if (line->GetCommand() == "DoneResearch") - m_researchDone[0] = line->GetParam("bits")->AsInt(); - - if (line->GetCommand() == "BlitzMode") + if (!isSpaceshipSave) { - float sleep = line->GetParam("sleep")->AsFloat(); - float delay = line->GetParam("delay")->AsFloat(); - float magnetic = line->GetParam("magnetic")->AsFloat()*g_unit; - float progress = line->GetParam("progress")->AsFloat(); - m_lightning->SetStatus(sleep, delay, magnetic, progress); + if (line->GetCommand() == "Mission") + m_gameTime = line->GetParam("gametime")->AsFloat(0.0f); + + if (line->GetCommand() == "Map") + m_map->ZoomMap(line->GetParam("zoom")->AsFloat()); + + if (line->GetCommand() == "DoneResearch") + m_researchDone[0] = line->GetParam("bits")->AsInt(); + + if (line->GetCommand() == "BlitzMode") + { + float sleep = line->GetParam("sleep")->AsFloat(); + float delay = line->GetParam("delay")->AsFloat(); + float magnetic = line->GetParam("magnetic")->AsFloat()*g_unit; + float progress = line->GetParam("progress")->AsFloat(); + m_lightning->SetStatus(sleep, delay, magnetic, progress); + } } if (line->GetCommand() == "CreateFret") { - cargo = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects)); + cargo = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects), -1, glm::vec3(0,0,0), isSpaceshipSave); objCounter++; } if (line->GetCommand() == "CreatePower") { - power = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects)); + power = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects), -1, glm::vec3(0,0,0), isSpaceshipSave); objCounter++; } if (line->GetCommand() == "CreateSlotObject") { int slotNum = line->GetParam("slotNum")->AsInt(); - CObject *slotObject = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects)); + CObject *slotObject = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects), -1, offsetPosition, isSpaceshipSave); objCounter++; assert(slots.find(slotNum) == slots.end()); @@ -4944,7 +4998,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) if (line->GetCommand() == "CreateObject") { - CObject* obj = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects), objRank++); + CObject* obj = IOReadObject(line.get(), dirname, StrUtils::ToString(objCounter+1)+" / "+StrUtils::ToString(numObjects), static_cast(objCounter) / static_cast(numObjects), objRank++, offsetPosition, isSpaceshipSave); if (line->GetParam("select")->AsBool(false)) sel = obj; diff --git a/colobot-base/level/robotmain.h b/colobot-base/level/robotmain.h index f80c875e..42ee4842 100644 --- a/colobot-base/level/robotmain.h +++ b/colobot-base/level/robotmain.h @@ -87,6 +87,7 @@ bool IsMainMenuPhase(Phase phase); class CApplication; class CEventQueue; class CSoundInterface; +class CLevelParser; class CLevelParserLine; class CInput; class CObjectManager; @@ -336,9 +337,10 @@ public: bool IOIsBusy(); bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave = false); void IOWriteSceneFinished(); - CObject* IOReadScene(std::string filename, std::string filecbot); - void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank); - CObject* IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank = -1); + CObject* IOReadScene(std::string filename, std::string filecbot, bool isSpaceshipSave = false, glm::vec3 offsetPosition = glm::vec3(0,0,0)); + void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank, bool directProgramStorageIndex); + void IOWriteObjectTree(CLevelParser& levelParser, CObject* obj, std::string const& dirname, int& objRank, bool directProgramStorageIndex); + CObject* IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank = -1, glm::vec3 offsetPosition = glm::vec3(0,0,0), bool isSpaceshipSave = false); //@} int CreateSpot(glm::vec3 pos, Gfx::Color color); diff --git a/colobot-base/object/auto/autobase.cpp b/colobot-base/object/auto/autobase.cpp index e8831222..5475f43d 100644 --- a/colobot-base/object/auto/autobase.cpp +++ b/colobot-base/object/auto/autobase.cpp @@ -20,6 +20,8 @@ #include "object/auto/autobase.h" +#include "common/resources/resourcemanager.h" + #include "graphics/engine/cloud.h" #include "graphics/engine/engine.h" #include "graphics/engine/lightning.h" @@ -27,6 +29,10 @@ #include "graphics/engine/terrain.h" #include "level/robotmain.h" +#include "level/player_profile.h" + +#include "level/parser/parser.h" +#include "level/parser/parserline.h" #include "math/geometry.h" @@ -1369,15 +1375,56 @@ Error CAutoBase::TakeOff(bool printMsg) return err; } - err = m_main->CheckEndMission(false); - if (err != ERR_OK) + // taking off in career mode doesn't have to complete the mission + if (m_main->GetLevelCategory() != LevelCategory::CareerMode) { - if (printMsg) - m_main->DisplayError(err, m_object); - return err; + err = m_main->CheckEndMission(false); + if (err != ERR_OK) + { + if (printMsg) + m_main->DisplayError(err, m_object); + return err; + } } FreezeCargo(true); // freeze whole cargo + + if (m_main->GetLevelCategory() == LevelCategory::CareerMode) + { + // Note: we don't write a cbot.run file - running programs won't remain running when transferred to other worlds. + // We still need a directory per save file, because programs are saved there. + std::string saveDir = m_main->GetPlayerProfile()->GetSaveFile("__spaceship__"); // TODO: change save path? + if (CResourceManager::DirectoryExists(saveDir)) + CResourceManager::RemoveExistingDirectory(saveDir); + CResourceManager::CreateNewDirectory(saveDir); + + CLevelParser levelFile(saveDir+"/data.sav"); + { + CLevelParserLineUPtr line = std::make_unique("SpaceShipSave"); + line->AddParam("version", std::make_unique(1)); + levelFile.AddLine(std::move(line)); + } + int objRank = 0; + for(CObject* obj : m_cargoObjects) + { + glm::vec3 pos = obj->GetPosition(); + obj->SetPosition(pos - m_object->GetPosition()); + m_main->IOWriteObjectTree(levelFile, obj, saveDir, objRank, true); + obj->SetPosition(pos); + } + try + { + levelFile.Save(); + } + catch (CLevelParserException& e) + { + GetLogger()->Error("Failed to save level state - %s\n", e.what()); // TODO add visual error to notify user that save failed + // return to normal gameplay - not tested at all, probably broken + FreezeCargo(false); + return ERR_UNKNOWN; // TODO: proper error code + } + } + m_main->SetMovieLock(true); // blocks everything until the end m_main->DeselectAll(); diff --git a/colobot-base/object/object_manager.h b/colobot-base/object/object_manager.h index 48752590..8f45fe9a 100644 --- a/colobot-base/object/object_manager.h +++ b/colobot-base/object/object_manager.h @@ -211,7 +211,7 @@ public: float angle = 0.0f, float focus = Math::PI*2.0f, float minDist = 0.0f, - float maxDist = 1000.0f, + float maxDist = 10000000.0f, bool furthest = false, RadarFilter filter = FILTER_NONE, bool cbotTypes = false); @@ -222,7 +222,7 @@ public: float angle = 0.0f, float focus = Math::PI*2.0f, float minDist = 0.0f, - float maxDist = 1000.0f, + float maxDist = 10000000.0f, bool furthest = false, RadarFilter filter = FILTER_NONE, bool cbotTypes = false); @@ -233,7 +233,7 @@ public: float angle = 0.0f, float focus = Math::PI*2.0f, float minDist = 0.0f, - float maxDist = 1000.0f, + float maxDist = 10000000.0f, bool furthest = false, RadarFilter filter = FILTER_NONE, bool cbotTypes = false); @@ -245,7 +245,7 @@ public: float angle = 0.0f, float focus = Math::PI*2.0f, float minDist = 0.0f, - float maxDist = 1000.0f, + float maxDist = 10000000.0f, bool furthest = false, RadarFilter filter = FILTER_NONE, bool cbotTypes = false); diff --git a/colobot-base/ui/screen/screen_level_list.cpp b/colobot-base/ui/screen/screen_level_list.cpp index c87c09de..5a74af58 100644 --- a/colobot-base/ui/screen/screen_level_list.cpp +++ b/colobot-base/ui/screen/screen_level_list.cpp @@ -91,6 +91,7 @@ void CScreenLevelList::CreateInterface() if ( m_category == LevelCategory::CodeBattles ) res = RT_TITLE_CODE_BATTLES; if ( m_category == LevelCategory::GamePlus ) res = RT_TITLE_PLUS; if ( m_category == LevelCategory::CustomLevels ) res = RT_TITLE_USER; + if ( m_category == LevelCategory::CareerMode ) res = RT_TITLE_CAREER; GetResource(RES_TEXT, res, name); pw->SetName(name); @@ -114,6 +115,7 @@ void CScreenLevelList::CreateInterface() if ( m_category == LevelCategory::Missions ) res = RT_PLAY_CHAP_PLANETS; if ( m_category == LevelCategory::FreeGame ) res = RT_PLAY_CHAP_PLANETS; if ( m_category == LevelCategory::GamePlus ) res = RT_PLAY_CHAP_PLANETS; + if ( m_category == LevelCategory::CareerMode ) res = RT_PLAY_CHAP_PLANETS; if ( m_category == LevelCategory::CustomLevels ) res = RT_PLAY_CHAP_USERLVL; GetResource(RES_TEXT, res, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name); @@ -128,7 +130,8 @@ void CScreenLevelList::CreateInterface() UpdateSceneChap(m_chap[m_category]); if ( m_category != LevelCategory::FreeGame && m_category != LevelCategory::CodeBattles && - m_category != LevelCategory::CustomLevels ) // Don't show completion marks in free game, code battles and userlevels + m_category != LevelCategory::CustomLevels && + m_category != LevelCategory::CareerMode ) // Don't show completion marks in free game, code battles and userlevels { pli->SetState(STATE_EXTEND); } @@ -144,6 +147,7 @@ void CScreenLevelList::CreateInterface() if ( m_category == LevelCategory::Missions ) res = RT_PLAY_LIST_MISSIONS; if ( m_category == LevelCategory::FreeGame ) res = RT_PLAY_LIST_FREEGAME; if ( m_category == LevelCategory::GamePlus ) res = RT_PLAY_LIST_MISSIONS; + if ( m_category == LevelCategory::CareerMode ) res = RT_PLAY_LIST_MISSIONS; GetResource(RES_TEXT, res, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name); pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); @@ -186,7 +190,8 @@ void CScreenLevelList::CreateInterface() // Button displays the "soluce": if ( m_category != LevelCategory::Exercises && m_category != LevelCategory::GamePlus && - m_category != LevelCategory::FreeGame ) + m_category != LevelCategory::FreeGame && + m_category != LevelCategory::CareerMode ) { pos.x = ox+sx*9.5f; pos.y = oy+sy*5.8f; diff --git a/colobot-base/ui/screen/screen_main_menu.cpp b/colobot-base/ui/screen/screen_main_menu.cpp index da18cc82..f764672c 100644 --- a/colobot-base/ui/screen/screen_main_menu.cpp +++ b/colobot-base/ui/screen/screen_main_menu.cpp @@ -123,7 +123,7 @@ void CScreenMainMenu::CreateInterface() pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_CODE_BATTLES); pb->SetState(STATE_SHADOW); - pos.y = oy+sy*5.8f; + pos.y = oy+sy*5.9f; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_USER); pb->SetState(STATE_SHADOW); try @@ -144,6 +144,12 @@ void CScreenMainMenu::CreateInterface() GetLogger()->Error("Failed loading userlevel button name: %s\n", e.what()); } + + pos.y = oy+sy*5.0f; + ddim.y = dim.y*0.4f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_CAREER); + pb->SetState(STATE_SHADOW); + ddim.y = dim.y*0.5f; pos.y = oy+sy*4.35f; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_NAME); @@ -243,6 +249,11 @@ bool CScreenMainMenu::EventProcess(const Event &event) m_main->ChangePhase(PHASE_LEVEL_LIST); break; + case EVENT_INTERFACE_CAREER: + m_main->SetLevel(LevelCategory::CareerMode, 0, 0); + m_main->ChangePhase(PHASE_LEVEL_LIST); + break; + case EVENT_INTERFACE_SETUP: m_main->ChangePhase(CScreenSetup::GetTab()); break;