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