1 #ifndef __GAME_SAVES_H__ 2 #define __GAME_SAVES_H__ 3 4 #include "../SharedDefines.h" 5 #include "BaseGameApp.h" 6 7 // This can be refactored into classes, but this is not a pressing concern for me right now 8 // as it works as intended 9 10 const uint32 LEVELS_COUNT = 14; 11 12 // TODO: Should be data driven 13 Point GetSpawnPosition(uint32 levelNumber, uint32 checkpointNumber); 14 15 struct CheckpointSave 16 { CheckpointSaveCheckpointSave17 CheckpointSave() 18 { 19 checkpointIdx = 0; 20 score = 0; 21 health = 0; 22 lives = 0; 23 bulletCount = 0; 24 magicCount = 0; 25 dynamiteCount = 0; 26 } 27 ToXmlCheckpointSave28 TiXmlElement* ToXml() 29 { 30 TiXmlElement* pCheckpointXml = new TiXmlElement("Checkpoint"); 31 XML_ADD_TEXT_ELEMENT("CheckpointNumber", ToStr(checkpointIdx).c_str(), pCheckpointXml); 32 XML_ADD_TEXT_ELEMENT("Score", ToStr(score).c_str(), pCheckpointXml); 33 XML_ADD_TEXT_ELEMENT("Health", ToStr(health).c_str(), pCheckpointXml); 34 XML_ADD_TEXT_ELEMENT("Lives", ToStr(lives).c_str(), pCheckpointXml); 35 XML_ADD_TEXT_ELEMENT("BulletCount", ToStr(bulletCount).c_str(), pCheckpointXml); 36 XML_ADD_TEXT_ELEMENT("MagicCount", ToStr(magicCount).c_str(), pCheckpointXml); 37 XML_ADD_TEXT_ELEMENT("DynamiteCount", ToStr(dynamiteCount).c_str(), pCheckpointXml); 38 39 return pCheckpointXml; 40 } 41 LoadFromXmlCheckpointSave42 void LoadFromXml(TiXmlElement* pCheckpointXml) 43 { 44 assert(pCheckpointXml); 45 46 if (TiXmlElement* pElem = pCheckpointXml->FirstChildElement("CheckpointNumber")) 47 { 48 checkpointIdx = std::stoi(pElem->GetText()); 49 } 50 if (TiXmlElement* pElem = pCheckpointXml->FirstChildElement("Score")) 51 { 52 score = std::stoi(pElem->GetText()); 53 } 54 if (TiXmlElement* pElem = pCheckpointXml->FirstChildElement("Health")) 55 { 56 health = std::stoi(pElem->GetText()); 57 } 58 if (TiXmlElement* pElem = pCheckpointXml->FirstChildElement("Lives")) 59 { 60 lives = std::stoi(pElem->GetText()); 61 } 62 if (TiXmlElement* pElem = pCheckpointXml->FirstChildElement("BulletCount")) 63 { 64 bulletCount = std::stoi(pElem->GetText()); 65 } 66 if (TiXmlElement* pElem = pCheckpointXml->FirstChildElement("MagicCount")) 67 { 68 magicCount = std::stoi(pElem->GetText()); 69 } 70 if (TiXmlElement* pElem = pCheckpointXml->FirstChildElement("DynamiteCount")) 71 { 72 dynamiteCount = std::stoi(pElem->GetText()); 73 } 74 75 assert(checkpointIdx <= 2); 76 } 77 78 // 0 - start / new game, 79 // 1 - first checkpoint 80 // 2 - second checkpoint 81 uint32 checkpointIdx; 82 83 uint32 score; 84 uint32 health; 85 uint32 lives; 86 uint32 bulletCount; 87 uint32 magicCount; 88 uint32 dynamiteCount; 89 }; 90 91 struct LevelSave 92 { LevelSaveLevelSave93 LevelSave() 94 { 95 levelNumber = -1; // Undefined 96 } 97 LevelSaveLevelSave98 LevelSave(uint32 levelNumber, std::string levelName) 99 { 100 this->levelNumber = levelNumber; 101 this->levelName = levelName; 102 } 103 LevelSaveLevelSave104 LevelSave(TiXmlElement* pLevelXml) 105 { 106 LoadFromXml(pLevelXml); 107 } 108 ToXmlLevelSave109 TiXmlElement* ToXml() 110 { 111 TiXmlElement* pLevelXml = new TiXmlElement("Level"); 112 XML_ADD_TEXT_ELEMENT("LevelNumber", ToStr(levelNumber).c_str(), pLevelXml); 113 XML_ADD_TEXT_ELEMENT("LevelName", levelName.c_str(), pLevelXml); 114 for (auto saveIter : checkpointMap) 115 { 116 pLevelXml->LinkEndChild(saveIter.second.ToXml()); 117 } 118 119 return pLevelXml; 120 } 121 LoadFromXmlLevelSave122 void LoadFromXml(TiXmlElement* pLevelXml) 123 { 124 if (TiXmlElement* pElem = pLevelXml->FirstChildElement("LevelNumber")) 125 { 126 levelNumber = std::stoi(pElem->GetText()); 127 } 128 129 if (TiXmlElement* pElem = pLevelXml->FirstChildElement("LevelName")) 130 { 131 levelName = pElem->GetText(); 132 } 133 134 for (TiXmlElement* pCheckpoint = pLevelXml->FirstChildElement("Checkpoint"); 135 pCheckpoint; pCheckpoint = pCheckpoint->NextSiblingElement("Checkpoint")) 136 { 137 CheckpointSave save; 138 save.LoadFromXml(pCheckpoint); 139 checkpointMap[save.checkpointIdx] = save; 140 } 141 142 //assert(!levelName.empty()); 143 if (levelName.empty()) 144 { 145 LOG_WARNING("Leve name is empty ! Level number: " + ToStr(levelNumber)); 146 } 147 LOG(ToStr(levelNumber)); 148 } 149 AddCheckpointSaveLevelSave150 void AddCheckpointSave(CheckpointSave& checkpointSave) 151 { 152 checkpointMap[checkpointSave.checkpointIdx] = checkpointSave; 153 } 154 GetLastCheckpointSaveLevelSave155 CheckpointSave* GetLastCheckpointSave() 156 { 157 assert(!checkpointMap.empty()); 158 159 // Little bit unlucky when using map 160 uint32 lastCheckpoint = 0; 161 162 for (auto checkpointIter : checkpointMap) 163 { 164 if (checkpointIter.second.checkpointIdx > lastCheckpoint) 165 { 166 lastCheckpoint = checkpointIter.second.checkpointIdx; 167 } 168 } 169 170 return &checkpointMap[lastCheckpoint]; 171 } 172 173 // Can return NULL GetCheckpointSaveLevelSave174 CheckpointSave* GetCheckpointSave(uint32 checkpointNumber) 175 { 176 auto findIt = checkpointMap.find(checkpointNumber); 177 if (findIt == checkpointMap.end()) 178 { 179 return NULL; 180 } 181 182 return &(findIt->second); 183 } 184 185 uint32 levelNumber; 186 std::string levelName; 187 std::map<uint32, CheckpointSave> checkpointMap; 188 }; 189 190 typedef std::map<uint32, LevelSave> LevelSaveMap; 191 class GameSaveMgr 192 { 193 public: Initialize(TiXmlElement * pGameSaveData)194 bool Initialize(TiXmlElement* pGameSaveData) 195 { 196 if (g_pApp->GetGlobalOptions()->loadAllLevelSaves) 197 { 198 InitializeWithAllLevels(); 199 return true; 200 } 201 202 if (!pGameSaveData) 203 { 204 return false; 205 } 206 207 for (TiXmlElement* pLevel = pGameSaveData->FirstChildElement("Level"); 208 pLevel; pLevel = pLevel->NextSiblingElement("Level")) 209 { 210 LevelSave levelSave(pLevel); 211 assert(levelSave.levelNumber <= LEVELS_COUNT); 212 213 m_LevelSaveMap[levelSave.levelNumber] = levelSave; 214 } 215 216 if (m_LevelSaveMap.empty()) 217 { 218 LOG_ERROR("No saves were found. There should always be atleast first level."); 219 return false; 220 } 221 222 return true; 223 } 224 InitializeWithAllLevels()225 void InitializeWithAllLevels() 226 { 227 int lastLevel = 14; 228 229 CheckpointSave fullCheckpoint0; 230 fullCheckpoint0.bulletCount = 99; 231 fullCheckpoint0.checkpointIdx = 0; 232 fullCheckpoint0.dynamiteCount = 99; 233 fullCheckpoint0.health = 100; 234 fullCheckpoint0.lives = 9; 235 fullCheckpoint0.magicCount = 99; 236 fullCheckpoint0.score = 0; 237 238 CheckpointSave fullCheckpoint1; 239 fullCheckpoint1.bulletCount = 99; 240 fullCheckpoint1.checkpointIdx = 1; 241 fullCheckpoint1.dynamiteCount = 99; 242 fullCheckpoint1.health = 100; 243 fullCheckpoint1.lives = 9; 244 fullCheckpoint1.magicCount = 99; 245 fullCheckpoint1.score = 0; 246 247 CheckpointSave fullCheckpoint2; 248 fullCheckpoint2.bulletCount = 99; 249 fullCheckpoint2.checkpointIdx = 2; 250 fullCheckpoint2.dynamiteCount = 99; 251 fullCheckpoint2.health = 100; 252 fullCheckpoint2.lives = 9; 253 fullCheckpoint2.magicCount = 99; 254 fullCheckpoint2.score = 0; 255 256 for (int levelIdx = 1; levelIdx <= lastLevel; levelIdx++) 257 { 258 LevelSave levelSave; 259 switch (levelIdx) 260 { 261 case 1: levelSave.levelName = "La Roca"; break; 262 case 2: levelSave.levelName = "Battlements"; break; 263 case 3: levelSave.levelName = "Thief's Forest"; break; 264 case 4: levelSave.levelName = "Dark Woods"; break; 265 case 5: levelSave.levelName = "Town"; break; 266 case 6: levelSave.levelName = "Puerto De Lobo"; break; 267 case 7: levelSave.levelName = "Docks"; break; 268 case 8: levelSave.levelName = "Shipyards"; break; 269 case 9: levelSave.levelName = "Pirate's Cove"; break; 270 case 10: levelSave.levelName = "Cliffs"; break; 271 case 11: levelSave.levelName = "Caverns"; break; 272 case 12: levelSave.levelName = "Undersea Caves"; break; 273 case 13: levelSave.levelName = "Tiger Island"; break; 274 case 14: levelSave.levelName = "Temple"; break; 275 default: assert(false); break; 276 } 277 levelSave.levelNumber = levelIdx; 278 279 levelSave.checkpointMap[0] = fullCheckpoint0; 280 levelSave.checkpointMap[1] = fullCheckpoint1; 281 levelSave.checkpointMap[2] = fullCheckpoint2; 282 283 m_LevelSaveMap[levelIdx] = levelSave; 284 } 285 } 286 ToXml()287 TiXmlElement* ToXml() 288 { 289 TiXmlElement* pGameSaves = new TiXmlElement("GameSaves"); 290 for (auto levelSave : m_LevelSaveMap) 291 { 292 pGameSaves->LinkEndChild(levelSave.second.ToXml()); 293 } 294 295 return pGameSaves; 296 } 297 AddLevelEntry(uint32 levelNumber,std::string levelName)298 void AddLevelEntry(uint32 levelNumber, std::string levelName) 299 { 300 assert(levelNumber <= LEVELS_COUNT); 301 302 m_LevelSaveMap[levelNumber] = LevelSave(levelNumber, levelName); 303 } 304 AddCheckpointSave(uint32 levelNumber,CheckpointSave & save)305 void AddCheckpointSave(uint32 levelNumber, CheckpointSave& save) 306 { 307 assert(levelNumber <= LEVELS_COUNT); 308 309 auto findIt = m_LevelSaveMap.find(levelNumber); 310 if (findIt == m_LevelSaveMap.end()) 311 { 312 LOG_ERROR("Creating checkpoint for level save which is unitialized !"); 313 m_LevelSaveMap[levelNumber] = LevelSave(levelNumber, "Unknown"); 314 } 315 316 m_LevelSaveMap[levelNumber].checkpointMap[save.checkpointIdx] = save; 317 } 318 319 // Can return NULL GetLevelSave(uint32 levelNumber)320 LevelSave* GetLevelSave(uint32 levelNumber) 321 { 322 assert(levelNumber <= LEVELS_COUNT); 323 324 auto findIt = m_LevelSaveMap.find(levelNumber); 325 if (findIt == m_LevelSaveMap.end()) 326 { 327 return NULL; 328 } 329 330 return &(findIt->second); 331 } 332 HasLevelSave(uint32 levelNumber)333 bool HasLevelSave(uint32 levelNumber) 334 { 335 return (GetLevelSave(levelNumber) != NULL); 336 } 337 338 // Can return NULL GetCheckpointSave(uint32 levelNumber,uint32 checkpointNumber)339 const CheckpointSave* GetCheckpointSave(uint32 levelNumber, uint32 checkpointNumber) 340 { 341 LevelSave* pLevelSave = GetLevelSave(levelNumber); 342 if (pLevelSave == NULL) 343 { 344 return NULL; 345 } 346 347 return pLevelSave->GetCheckpointSave(checkpointNumber); 348 } 349 HasCheckpointSave(uint32 levelNumber,uint32 checkpointNumber)350 bool HasCheckpointSave(uint32 levelNumber, uint32 checkpointNumber) 351 { 352 return (GetCheckpointSave(levelNumber, checkpointNumber) != NULL); 353 } 354 355 private: 356 LevelSaveMap m_LevelSaveMap; 357 }; 358 359 360 #endif