1 /*
2  *  This file is part of Dune Legacy.
3  *
4  *  Dune Legacy is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Dune Legacy is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Dune Legacy.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <sand.h>
19 
20 #include <globals.h>
21 
22 #include <FileClasses/GFXManager.h>
23 #include <FileClasses/TextManager.h>
24 #include <FileClasses/music/MusicPlayer.h>
25 
26 #include <Menu/BriefingMenu.h>
27 #include <Menu/CampaignStatsMenu.h>
28 #include <Menu/CustomGameStatsMenu.h>
29 
30 #include <CutScenes/Meanwhile.h>
31 #include <CutScenes/Finale.h>
32 
33 #include <Game.h>
34 #include <GameInitSettings.h>
35 #include <data.h>
36 
37 #include <misc/exceptions.h>
38 
39 #include <algorithm>
40 
41 /**
42     This function draws the cursor to the screen. The coordinate is read from
43     the two global variables drawnMouseX and drawnMouseY.
44 */
drawCursor()45 void drawCursor() {
46     if(!(SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_FOCUS)) {
47         return;
48     }
49 
50     SDL_Texture* tex = pGFXManager->getUIGraphic(cursorFrame);
51 
52     SDL_Rect dest = calcDrawingRect(tex, drawnMouseX, drawnMouseY);
53 
54     //reposition image so pointing on right spot
55 
56     if (cursorFrame == UI_CursorRight) {
57         dest.x -= dest.w/2;
58     } else if (cursorFrame == UI_CursorDown) {
59         dest.y -= dest.h/2;
60     }
61 
62     if ((cursorFrame == UI_CursorAttack_Zoomlevel0) || (cursorFrame == UI_CursorMove_Zoomlevel0)) {
63         dest.x -= dest.w/2;
64         dest.y -= dest.h/2;
65     }
66 
67     SDL_RenderCopy(renderer, tex, nullptr, &dest);
68 }
69 
70 /**
71     This function resolves the picture corresponding to one item id.
72     \param itemID   the id of the item to resolve (e.g. Unit_Quad)
73     \return the surface corresponding. This surface should not be freed or modified. nullptr on error.
74 */
resolveItemPicture(int itemID,HOUSETYPE house)75 SDL_Texture* resolveItemPicture(int itemID, HOUSETYPE house) {
76     int newPicID;
77 
78     switch(itemID) {
79         case Structure_Barracks:            newPicID = Picture_Barracks;            break;
80         case Structure_ConstructionYard:    newPicID = Picture_ConstructionYard;    break;
81         case Structure_GunTurret:           newPicID = Picture_GunTurret;           break;
82         case Structure_HeavyFactory:        newPicID = Picture_HeavyFactory;        break;
83         case Structure_HighTechFactory:     newPicID = Picture_HighTechFactory;     break;
84         case Structure_IX:                  newPicID = Picture_IX;                  break;
85         case Structure_LightFactory:        newPicID = Picture_LightFactory;        break;
86         case Structure_Palace:              newPicID = Picture_Palace;              break;
87         case Structure_Radar:               newPicID = Picture_Radar;               break;
88         case Structure_Refinery:            newPicID = Picture_Refinery;            break;
89         case Structure_RepairYard:          newPicID = Picture_RepairYard;          break;
90         case Structure_RocketTurret:        newPicID = Picture_RocketTurret;        break;
91         case Structure_Silo:                newPicID = Picture_Silo;                break;
92         case Structure_Slab1:               newPicID = Picture_Slab1;               break;
93         case Structure_Slab4:               newPicID = Picture_Slab4;               break;
94         case Structure_StarPort:            newPicID = Picture_StarPort;            break;
95         case Structure_Wall:                newPicID = Picture_Wall;                break;
96         case Structure_WindTrap:            newPicID = Picture_WindTrap;            break;
97         case Structure_WOR:                 newPicID = Picture_WOR;                 break;
98 
99         case Unit_Carryall:                 newPicID = Picture_Carryall;            break;
100         case Unit_Devastator:               newPicID = Picture_Devastator;          break;
101         case Unit_Deviator:                 newPicID = Picture_Deviator;            break;
102         case Unit_Frigate:                  newPicID = Picture_Frigate;             break;
103         case Unit_Harvester:                newPicID = Picture_Harvester;           break;
104         case Unit_Launcher:                 newPicID = Picture_Launcher;            break;
105         case Unit_MCV:                      newPicID = Picture_MCV;                 break;
106         case Unit_Ornithopter:              newPicID = Picture_Ornithopter;         break;
107         case Unit_Quad:                     newPicID = Picture_Quad;                break;
108         case Unit_RaiderTrike:              newPicID = Picture_RaiderTrike;         break;
109         case Unit_SiegeTank:                newPicID = Picture_SiegeTank;           break;
110         case Unit_SonicTank:                newPicID = Picture_SonicTank;           break;
111         case Unit_Tank:                     newPicID = Picture_Tank;                break;
112         case Unit_Trike:                    newPicID = Picture_Trike;               break;
113         case Unit_Saboteur:                 newPicID = Picture_Saboteur;            break;
114         case Unit_Sandworm:                 newPicID = Picture_Sandworm;            break;
115         case Unit_Soldier:                  newPicID = Picture_Soldier;             break;
116         case Unit_Trooper: {
117             switch(house) {
118                 case HOUSE_SARDAUKAR:       newPicID = Picture_Sardaukar;           break;
119                 case HOUSE_FREMEN:          newPicID = Picture_Fremen;              break;
120                 default:                    newPicID = Picture_Trooper;             break;
121             }
122         } break;
123         case Unit_Special:                  newPicID = Picture_Special;             break;
124         case Unit_Infantry:                 newPicID = Picture_Soldier;             break;
125         case Unit_Troopers: {
126             switch(house) {
127                 case HOUSE_SARDAUKAR:       newPicID = Picture_Sardaukar;           break;
128                 case HOUSE_FREMEN:          newPicID = Picture_Fremen;              break;
129                 default:                    newPicID = Picture_Trooper;             break;
130             }
131         } break;
132 
133         default:
134             THROW(std::invalid_argument, "resolveItemPicture(): Invalid item ID " + stringify(itemID) + "!");
135         break;
136     }
137 
138     return pGFXManager->getSmallDetailPic(newPicID);
139 }
140 
141 
142 /**
143     This function returns the anim id based on the passed filename.
144     \param  filename    the filename (e.g. STARPORT.WSA)
145     \return the id of the animation (e.g. Anim_StarPort)
146 */
getAnimByFilename(const std::string & filename)147 int getAnimByFilename(const std::string& filename) {
148     std::string lowerFilename = strToLower(filename);
149 
150     if(lowerFilename == "fartr.wsa")            return Anim_AtreidesPlanet;
151     else if(lowerFilename == "fhark.wsa")       return Anim_HarkonnenPlanet;
152     else if(lowerFilename == "fordos.wsa")      return Anim_OrdosPlanet;
153     else if(lowerFilename == "win1.wsa")        return Anim_Win1;
154     else if(lowerFilename == "win2.wsa")        return Anim_Win2;
155     else if(lowerFilename == "lostbild.wsa")    return Anim_Lose1;
156     else if(lowerFilename == "lostvehc.wsa")    return Anim_Lose2;
157     else if(lowerFilename == "barrac.wsa")      return Anim_Barracks;
158     else if(lowerFilename == "carryall.wsa")    return Anim_Carryall;
159     else if(lowerFilename == "construc.wsa")    return Anim_ConstructionYard;
160     else if(lowerFilename == "fremen.wsa")      return Anim_Fremen;
161     else if(lowerFilename == "gold-bb.wsa")     return Anim_DeathHand;
162     else if(lowerFilename == "harktank.wsa")    return Anim_Devastator;
163     else if(lowerFilename == "harvest.wsa")     return Anim_Harvester;
164     else if(lowerFilename == "headqrts.wsa")    return Anim_Radar;
165     else if(lowerFilename == "hitcftry.wsa")    return Anim_HighTechFactory;
166     else if(lowerFilename == "htank.wsa")       return Anim_SiegeTank;
167     else if(lowerFilename == "hvyftry.wsa")     return Anim_HeavyFactory;
168     else if(lowerFilename == "hyinfy.wsa")      return Anim_Trooper;
169     else if(lowerFilename == "infantry.wsa")    return Anim_Infantry;
170     else if(lowerFilename == "ix.wsa")          return Anim_IX;
171     else if(lowerFilename == "liteftry.wsa")    return Anim_LightFactory;
172     else if(lowerFilename == "ltank.wsa")       return Anim_Tank;
173     else if(lowerFilename == "mcv.wsa")         return Anim_MCV;
174     else if(lowerFilename == "ordrtank.wsa")    return Anim_Deviator;
175     else if(lowerFilename == "orni.wsa")        return Anim_Ornithopter;
176     else if(lowerFilename == "otrike.wsa")      return Anim_Raider;
177     else if(lowerFilename == "palace.wsa")      return Anim_Palace;
178     else if(lowerFilename == "quad.wsa")        return Anim_Quad;
179     else if(lowerFilename == "refinery.wsa")    return Anim_Refinery;
180     else if(lowerFilename == "repair.wsa")      return Anim_RepairYard;
181     else if(lowerFilename == "rtank.wsa")       return Anim_Launcher;
182     else if(lowerFilename == "rturret.wsa")     return Anim_RocketTurret;
183     else if(lowerFilename == "saboture.wsa")    return Anim_Saboteur;
184     else if(lowerFilename == "slab.wsa")        return Anim_Slab1;
185     else if(lowerFilename == "stank.wsa")       return Anim_SonicTank;
186     else if(lowerFilename == "starport.wsa")    return Anim_StarPort;
187     else if(lowerFilename == "storage.wsa")     return Anim_Silo;
188     else if(lowerFilename == "trike.wsa")       return Anim_Trike;
189     else if(lowerFilename == "turret.wsa")      return Anim_GunTurret;
190     else if(lowerFilename == "wall.wsa")        return Anim_Wall;
191     else if(lowerFilename == "windtrap.wsa")    return Anim_WindTrap;
192     else if(lowerFilename == "wor.wsa")         return Anim_WOR;
193     else if(lowerFilename == "worm.wsa")        return Anim_Sandworm;
194     else if(lowerFilename == "sardukar.wsa")    return Anim_Sardaukar;
195     else if(lowerFilename == "frigate.wsa")     return Anim_Frigate;
196     else if(lowerFilename == "4slab.wsa")       return Anim_Slab4;
197     else                                        return 0;
198 }
199 
200 /**
201     This function returns the size of the specified item.
202     \param ItemID   the id of the item (e.g. Structure_HeavyFactory)
203     \return a Coord containg the size (e.g. (3,2) ). Returns (0,0) on error.
204 */
getStructureSize(int itemID)205 Coord getStructureSize(int itemID) {
206 
207     switch(itemID) {
208         case Structure_Barracks:            return Coord(2,2); break;
209         case Structure_ConstructionYard:    return Coord(2,2); break;
210         case Structure_GunTurret:           return Coord(1,1); break;
211         case Structure_HeavyFactory:        return Coord(3,2); break;
212         case Structure_HighTechFactory:     return Coord(3,2); break;
213         case Structure_IX:                  return Coord(2,2); break;
214         case Structure_LightFactory:        return Coord(2,2); break;
215         case Structure_Palace:              return Coord(3,3); break;
216         case Structure_Radar:               return Coord(2,2); break;
217         case Structure_Refinery:            return Coord(3,2); break;
218         case Structure_RepairYard:          return Coord(3,2); break;
219         case Structure_RocketTurret:        return Coord(1,1); break;
220         case Structure_Silo:                return Coord(2,2); break;
221         case Structure_StarPort:            return Coord(3,3); break;
222         case Structure_Slab1:               return Coord(1,1); break;
223         case Structure_Slab4:               return Coord(2,2); break;
224         case Structure_Wall:                return Coord(1,1); break;
225         case Structure_WindTrap:            return Coord(2,2); break;
226         case Structure_WOR:                 return Coord(2,2); break;
227         default:                            return Coord(0,0); break;
228     }
229 
230     return Coord(0,0);
231 }
232 
233 /**
234     This function return the item id of an item specified by name. There may be multiple names for
235     one item. The case of the name is ignored.
236     \param name the name of the item (e.g. "rocket-turret" or "r-turret".
237     \return the id of the item (e.g. Structure_RocketTurret)
238 */
getItemIDByName(const std::string & name)239 Uint32  getItemIDByName(const std::string& name) {
240     std::string lowerName = strToLower(name);
241 
242     if(lowerName == "barracks")                                                 return Structure_Barracks;
243     else if((lowerName == "const yard") || (lowerName == "construction yard"))  return Structure_ConstructionYard;
244     else if((lowerName == "r-turret") || (lowerName == "rocket-turret"))        return Structure_RocketTurret;
245     else if((lowerName == "turret") || (lowerName == "gun-turret"))             return Structure_GunTurret;
246     else if((lowerName == "heavy fctry") || (lowerName == "heavy factory"))     return Structure_HeavyFactory;
247     else if((lowerName == "hi-tech") || (lowerName == "hightech factory"))      return Structure_HighTechFactory;
248     else if((lowerName == "ix") || (lowerName == "house ix"))                   return Structure_IX;
249     else if((lowerName == "light fctry") || (lowerName == "light factory"))     return Structure_LightFactory;
250     else if(lowerName == "palace")                                              return Structure_Palace;
251     else if((lowerName == "outpost") || (lowerName == "radar"))                 return Structure_Radar;
252     else if(lowerName == "refinery")                                            return Structure_Refinery;
253     else if((lowerName == "repair") || (lowerName == "repair yard"))            return Structure_RepairYard;
254     else if((lowerName == "spice silo") || (lowerName == "silo"))               return Structure_Silo;
255     else if((lowerName == "concrete") || (lowerName == "slab1"))                return Structure_Slab1;
256     else if(lowerName == "slab4")                                               return Structure_Slab4;
257     else if((lowerName == "star port") || (lowerName == "starport"))            return Structure_StarPort;
258     else if(lowerName == "wall")                                                return Structure_Wall;
259     else if(lowerName == "windtrap")                                            return Structure_WindTrap;
260     else if(lowerName == "wor")                                                 return Structure_WOR;
261     else if((lowerName == "carryall") || (lowerName == "carry-all"))            return Unit_Carryall;
262     else if((lowerName == "devastator") || (lowerName == "devistator"))         return Unit_Devastator;
263     else if(lowerName == "deviator")                                            return Unit_Deviator;
264     else if(lowerName == "frigate")                                             return Unit_Frigate;
265     else if(lowerName == "harvester")                                           return Unit_Harvester;
266     else if(lowerName == "soldier")                                             return Unit_Soldier;
267     else if(lowerName == "launcher")                                            return Unit_Launcher;
268     else if(lowerName == "mcv")                                                 return Unit_MCV;
269     else if((lowerName == "thopters") || (lowerName == "'thopters")
270             || (lowerName == "thopter") || (lowerName == "'thopter")
271             || (lowerName == "ornithopter"))                                    return Unit_Ornithopter;
272     else if(lowerName == "quad")                                                return Unit_Quad;
273     else if(lowerName == "saboteur")                                            return Unit_Saboteur;
274     else if(lowerName == "sandworm")                                            return Unit_Sandworm;
275     else if(lowerName == "siege tank")                                          return Unit_SiegeTank;
276     else if((lowerName == "sonic tank") || (lowerName == "sonictank"))          return Unit_SonicTank;
277     else if(lowerName == "tank")                                                return Unit_Tank;
278     else if(lowerName == "trike")                                               return Unit_Trike;
279     else if((lowerName == "raider trike") || (lowerName == "raider"))           return Unit_RaiderTrike;
280     else if(lowerName == "trooper")                                             return Unit_Trooper;
281     else if(lowerName == "special")                                             return Unit_Special;
282     else if(lowerName == "infantry")                                            return Unit_Infantry;
283     else if(lowerName == "troopers")                                            return Unit_Troopers;
284     else                                                                        return ItemID_Invalid;
285 }
286 
287 
288 /**
289     This function returns the name of an item id.
290     \param itemID the id of the item (e.g. Unit_Sandworm)
291     \return the name of the item (e.g. "Sandworm").
292 */
getItemNameByID(Uint32 itemID)293 std::string getItemNameByID(Uint32 itemID) {
294     switch(itemID) {
295         case Structure_Barracks:            return "Barracks";          break;
296         case Structure_ConstructionYard:    return "Const Yard";        break;
297         case Structure_GunTurret:           return "Turret";            break;
298         case Structure_HeavyFactory:        return "Heavy Fctry";       break;
299         case Structure_HighTechFactory:     return "Hi-Tech";           break;
300         case Structure_IX:                  return "IX";                break;
301         case Structure_LightFactory:        return "Light Fctry";       break;
302         case Structure_Palace:              return "Palace";            break;
303         case Structure_Radar:               return "Outpost";           break;
304         case Structure_Refinery:            return "Refinery";          break;
305         case Structure_RepairYard:          return "Repair";            break;
306         case Structure_RocketTurret:        return "R-Turret";          break;
307         case Structure_Silo:                return "Spice Silo";        break;
308         case Structure_Slab1:               return "Concrete";         break;
309         case Structure_Slab4:               return "Slab4";         break;
310         case Structure_StarPort:            return "Starport";          break;
311         case Structure_Wall:                return "Wall";              break;
312         case Structure_WindTrap:            return "Windtrap";          break;
313         case Structure_WOR:                 return "WOR";               break;
314 
315         case Unit_Carryall:                 return "Carryall";          break;
316         case Unit_Devastator:               return "Devastator";        break;
317         case Unit_Deviator:                 return "Deviator";          break;
318         case Unit_Frigate:                  return "Frigate";          break;
319         case Unit_Harvester:                return "Harvester";     break;
320         case Unit_Launcher:                 return "Launcher";          break;
321         case Unit_MCV:                      return "MCV";               break;
322         case Unit_Ornithopter:              return "'Thopter";          break;
323         case Unit_Quad:                     return "Quad";              break;
324         case Unit_RaiderTrike:              return "Raider Trike";      break;
325         case Unit_SiegeTank:                return "Siege Tank";        break;
326         case Unit_SonicTank:                return "Sonic Tank";        break;
327         case Unit_Tank:                     return "Tank";              break;
328         case Unit_Trike:                    return "Trike";         break;
329         case Unit_Saboteur:                 return "Saboteur";          break;
330         case Unit_Sandworm:                 return "Sandworm";          break;
331         case Unit_Soldier:                  return "Soldier";           break;
332         case Unit_Trooper:                  return "Trooper";           break;
333         case Unit_Special:                  return "Special";           break;
334         case Unit_Infantry:                 return "Infantry";          break;
335         case Unit_Troopers:                 return "Troopers";          break;
336 
337         default:
338             THROW(std::invalid_argument, "getItemNameByID(): Invalid item ID!");
339         break;
340     }
341 }
342 
343 
344 /**
345     This function resolves the name corresponding to one item id.
346     \param itemID   the id of the item to resolve (e.g. Unit_Quad)
347     \return the string corresponding.
348 */
resolveItemName(int itemID)349 std::string resolveItemName(int itemID) {
350     switch(itemID) {
351         case Structure_Barracks:            return _("@DUNE.ENG|253#Barracks");            break;
352         case Structure_ConstructionYard:    return _("@DUNE.ENG|249#Construction Yard");   break;
353         case Structure_GunTurret:           return _("@DUNE.ENG|263#Gun Turret");          break;
354         case Structure_HeavyFactory:        return _("@DUNE.ENG|241#Heacy Factory");       break;
355         case Structure_HighTechFactory:     return _("@DUNE.ENG|243#Hightech Factory");    break;
356         case Structure_IX:                  return _("@DUNE.ENG|245#House IX");            break;
357         case Structure_LightFactory:        return _("@DUNE.ENG|239#Light Factory");       break;
358         case Structure_Palace:              return _("@DUNE.ENG|237#Palace");              break;
359         case Structure_Radar:               return _("@DUNE.ENG|269#Radar");               break;
360         case Structure_Refinery:            return _("@DUNE.ENG|256#Refinery");            break;
361         case Structure_RepairYard:          return _("@DUNE.ENG|259#Repair Yard");         break;
362         case Structure_RocketTurret:        return _("@DUNE.ENG|265#Rocket Turret");       break;
363         case Structure_Silo:                return _("@DUNE.ENG|267#Silo");                break;
364         case Structure_Slab1:               return _("@DUNE.ENG|233#Slab");                break;
365         case Structure_Slab4:               return _("@DUNE.ENG|235#Slab (2x2)");          break;
366         case Structure_StarPort:            return _("@DUNE.ENG|255#Starport");            break;
367         case Structure_Wall:                return _("@DUNE.ENG|261#Wall");                break;
368         case Structure_WindTrap:            return _("@DUNE.ENG|251#Windtrap");            break;
369         case Structure_WOR:                 return _("@DUNE.ENG|247#WOR");                 break;
370 
371         case Unit_Carryall:                 return _("@DUNE.ENG|195#Carryall");            break;
372         case Unit_Devastator:               return _("@DUNE.ENG|217#Devastator");          break;
373         case Unit_Deviator:                 return _("@DUNE.ENG|211#Deviator");            break;
374         case Unit_Frigate:                  return _("Frigate");                           break;
375         case Unit_Harvester:                return _("@DUNE.ENG|227#Harvester");           break;
376         case Unit_Launcher:                 return _("@DUNE.ENG|209#Launcher");            break;
377         case Unit_MCV:                      return _("@DUNE.ENG|229#MCV");                 break;
378         case Unit_Ornithopter:              return _("@DUNE.ENG|197#Ornithopter");         break;
379         case Unit_Quad:                     return _("@DUNE.ENG|225#Quad");                break;
380         case Unit_RaiderTrike:              return _("@DUNE.ENG|223#Raider Trike");        break;
381         case Unit_SiegeTank:                return _("@DUNE.ENG|215#Siege Tank");          break;
382         case Unit_SonicTank:                return _("@DUNE.ENG|219#Sonic Tank");          break;
383         case Unit_Tank:                     return _("@DUNE.ENG|213#Tank");                break;
384         case Unit_Trike:                    return _("@DUNE.ENG|221#Trike");               break;
385         case Unit_Saboteur:                 return _("@DUNE.ENG|207#Saboteur");            break;
386         case Unit_Sandworm:                 return _("@DUNE.ENG|231#Sandworm");            break;
387         case Unit_Soldier:                  return _("@DUNE.ENG|203#Soldier");             break;
388         case Unit_Trooper:                  return _("@DUNE.ENG|205#Trooper");             break;
389         case Unit_Special:                  return _("Sonic/Devast./Devia.");              break;
390         case Unit_Infantry:                 return _("@DUNE.ENG|199#Infantry");            break;
391         case Unit_Troopers:                 return _("@DUNE.ENG|201#Troopers");            break;
392 
393         default:
394             THROW(std::invalid_argument, "resolveItemName(): Invalid item ID!");
395         break;
396     }
397 }
398 
399 
400 /**
401     This function returns the number of each house providing the house name as a string. The comparison is
402     done case-insensitive.
403     \param name the name of the house (e.g."Atreides")
404     \return the number of the house (e.g. HOUSE_ATREIDES). HOUSE_INVALID is returned on error.
405 */
getHouseByName(const std::string & name)406 HOUSETYPE getHouseByName(const std::string& name) {
407     std::string lowerName = strToLower(name);
408 
409     if(lowerName == "harkonnen")         return HOUSE_HARKONNEN;
410     else if(lowerName == "atreides")     return HOUSE_ATREIDES;
411     else if(lowerName == "ordos")        return HOUSE_ORDOS;
412     else if(lowerName == "fremen")       return HOUSE_FREMEN;
413     else if(lowerName == "sardaukar")    return HOUSE_SARDAUKAR;
414     else if(lowerName == "mercenary")    return HOUSE_MERCENARY;
415     else                                return HOUSE_INVALID;
416 }
417 
418 /**
419     This function returns the name of house the house number.
420     \param house the number of the house (e.g. HOUSE_ATREIDES)
421     \return the name of the house (e.g. "Atreides").
422 */
getHouseNameByNumber(HOUSETYPE house)423 std::string getHouseNameByNumber(HOUSETYPE house) {
424     if(house >= 0 && house < NUM_HOUSES) {
425         static const char* houseName[NUM_HOUSES] = {    "Harkonnen",
426                                                         "Atreides",
427                                                         "Ordos",
428                                                         "Fremen",
429                                                         "Sardaukar",
430                                                         "Mercenary"
431                                                    };
432         return houseName[house];
433     } else {
434         THROW(std::invalid_argument, "Invalid house number %d!", house);
435     }
436 }
437 
getAttackModeByName(const std::string & name)438 ATTACKMODE getAttackModeByName(const std::string& name) {
439     std::string lowerName = strToLower(name);
440 
441     if(lowerName == "guard")                                    return GUARD;
442     else if(lowerName == "area guard")                          return AREAGUARD;
443     else if(lowerName == "ambush")                              return AMBUSH;
444     else if((lowerName == "hunt") || (lowerName == "attack"))   return HUNT;
445     else if(lowerName == "harvest")                             return HARVEST;
446     else if(lowerName == "sabotage")                            return SABOTAGE;
447     else if(lowerName == "stop")                                return STOP;
448     else if(lowerName == "capture")                             return CAPTURE;
449     else if(lowerName == "retreat")                             return RETREAT;
450     else                                                        return ATTACKMODE_INVALID;
451 }
452 
453 
getAttackModeNameByMode(ATTACKMODE attackMode)454 std::string getAttackModeNameByMode(ATTACKMODE attackMode) {
455     switch(attackMode) {
456         case GUARD:     return "Guard";         break;
457         case AREAGUARD: return "Area Guard";    break;
458         case AMBUSH:    return "Ambush";        break;
459         case HUNT:      return "Hunt";          break;
460         case HARVEST:   return "Harvest";       break;
461         case SABOTAGE:  return "Sabotage";      break;
462         case STOP:      return "Stop";          break;
463         case CAPTURE:   return "Capture";          break;
464         default:
465             THROW(std::invalid_argument, "getAttackModeNameByMode(): Invalid attack mode!");
466         break;
467     }
468 }
469 
470 
getColorByTerrainType(int terrainType)471 Uint32 getColorByTerrainType(int terrainType) {
472     Uint32 color = COLOR_BLACK;
473     switch (terrainType) {
474         case Terrain_Dunes:         color = COLOR_DESERTSAND;  break;
475         case Terrain_Mountain:      color = COLOR_MOUNTAIN;    break;
476         case Terrain_Rock:          color = COLOR_ROCK;        break;
477         case Terrain_Sand:          color = COLOR_DESERTSAND;  break;
478         case Terrain_Spice:         color = COLOR_SPICE;       break;
479         case Terrain_ThickSpice:    color = COLOR_THICKSPICE;  break;
480         case Terrain_SpiceBloom:    color = COLOR_BLOOM;       break;
481         case Terrain_SpecialBloom:  color = COLOR_BLOOM;       break;
482         case Terrain_Slab:          color = COLOR_ROCK;        break;
483         default:                    color = COLOR_ROCK;        break;
484     }
485 
486     return color;
487 }
488 
489 
490 
getDropLocationByName(const std::string & name)491 DropLocation getDropLocationByName(const std::string& name) {
492     std::string lowerName = strToLower(name);
493 
494     if(lowerName == "north") {
495         return Drop_North;
496     } else if(lowerName == "east") {
497         return Drop_East;
498     } else if(lowerName == "south") {
499         return Drop_South;
500     } else if(lowerName == "west") {
501         return Drop_West;
502     } else if(lowerName == "air") {
503         return Drop_Air;
504     } else if(lowerName == "visible") {
505         return Drop_Visible;
506     } else if(lowerName == "enemybase") {
507         return Drop_Enemybase;
508     } else if(lowerName == "homebase") {
509         return Drop_Homebase;
510     } else {
511         return Drop_Invalid;
512     }
513 }
514 
515 
getDropLocationNameByID(DropLocation dropLocation)516 std::string getDropLocationNameByID(DropLocation dropLocation) {
517     switch(dropLocation) {
518         case Drop_North:     return "North";     break;
519         case Drop_East:      return "East";      break;
520         case Drop_South:     return "South";     break;
521         case Drop_West:      return "West";      break;
522         case Drop_Air:       return "Air";       break;
523         case Drop_Visible:   return "Visible";   break;
524         case Drop_Enemybase: return "Enemybase"; break;
525         case Drop_Homebase:  return "Homebase";  break;
526         default:
527             THROW(std::invalid_argument, "getDropLocationNameByID(): Invalid drop location!");
528         break;
529     }
530 }
531 
resolveDropLocationName(DropLocation dropLocation)532 std::string resolveDropLocationName(DropLocation dropLocation) {
533     switch(dropLocation) {
534         case Drop_North:     return _("top edge");     break;
535         case Drop_East:      return _("right edge");   break;
536         case Drop_South:     return _("bottom edge");  break;
537         case Drop_West:      return _("left edge");    break;
538         case Drop_Air:       return _("random");       break;
539         case Drop_Visible:   return _("middle");       break;
540         case Drop_Enemybase: return _("enemy base");   break;
541         case Drop_Homebase:  return _("home base");    break;
542         default:
543             THROW(std::invalid_argument, "resolveDropLocationName(): Invalid drop location!");
544         break;
545     }
546 }
547 
getTeamBehaviorByName(const std::string & name)548 TeamBehavior getTeamBehaviorByName(const std::string& name) {
549     std::string lowerName = strToLower(name);
550 
551     if(lowerName == "normal") {
552         return TeamBehavior_Normal;
553     } else if(lowerName == "guard") {
554         return TeamBehavior_Guard;
555     } else if(lowerName == "kamikaze") {
556         return TeamBehavior_Kamikaze;
557     } else if(lowerName == "staging") {
558         return TeamBehavior_Staging;
559     } else if(lowerName == "flee") {
560         return TeamBehavior_Flee;
561     } else {
562         return TeamBehavior_Invalid;
563     }
564 }
565 
566 
getTeamBehaviorNameByID(TeamBehavior teamBehavior)567 std::string getTeamBehaviorNameByID(TeamBehavior teamBehavior) {
568     switch(teamBehavior) {
569         case TeamBehavior_Normal:     return "Normal";     break;
570         case TeamBehavior_Guard:      return "Guard";      break;
571         case TeamBehavior_Kamikaze:   return "Kamikaze";   break;
572         case TeamBehavior_Staging:    return "Staging";    break;
573         case TeamBehavior_Flee:       return "Flee";       break;
574         default:
575             THROW(std::invalid_argument, "getTeamBehaviorNameByID(): Invalid team behavior!");
576         break;
577     }
578 }
579 
580 
getTeamTypeByName(const std::string & name)581 TeamType getTeamTypeByName(const std::string& name) {
582     std::string lowerName = strToLower(name);
583 
584     if(lowerName == "foot") {
585         return TeamType_Foot;
586     } else if(lowerName == "wheel" || lowerName == "wheeled") {
587         return TeamType_Wheeled;
588     } else if(lowerName == "track" || lowerName == "tracked") {
589         return TeamType_Tracked;
590     } else if(lowerName == "winged") {
591         return TeamType_Winged;
592     } else if(lowerName == "slither") {
593         return TeamType_Slither;
594     } else if(lowerName == "harvester") {
595         return TeamType_Harvester;
596     } else {
597         return TeamType_Invalid;
598     }
599 }
600 
601 
getTeamTypeNameByID(TeamType teamType)602 std::string getTeamTypeNameByID(TeamType teamType) {
603     switch(teamType) {
604         case TeamType_Foot:      return "Foot";      break;
605         case TeamType_Wheeled:   return "Wheeled";   break;
606         case TeamType_Tracked:   return "Tracked";   break;
607         case TeamType_Winged:    return "Winged";    break;
608         case TeamType_Slither:   return "Slither";   break;
609         case TeamType_Harvester: return "Harvester"; break;
610         default:
611             THROW(std::invalid_argument, "getTeamTypeNameByID(): Invalid team type!");
612         break;
613     }
614 }
615 
616 
617 /**
618     This function returns the house-dependent weakness of a unit to get deviated
619     \param  house   the house of the unit (choose the real owner);
620 */
getDeviateWeakness(HOUSETYPE house)621 FixPoint getDeviateWeakness(HOUSETYPE house) {
622 
623     // Deviators are crap enough. If this is a custom game remove the weakness nerf
624     // So that Ordos is playable for Humans
625     //if(currentGame->gameType == GameType::CustomGame){
626         //return FixPt(0,100);
627     return 1;
628     //}
629 
630 /*
631     switch(house) {
632         case HOUSE_HARKONNEN:   return FixPt(0,78);
633         case HOUSE_ATREIDES:    return FixPt(0,30);
634         case HOUSE_ORDOS:       return FixPt(0,50);
635         case HOUSE_FREMEN:      return FixPt(0,08);
636         case HOUSE_SARDAUKAR:   return FixPt(0,04);
637         case HOUSE_MERCENARY:   return FixPt(0,50);
638         default:                return FixPt(0,00);
639     }*/
640 }
641 
642 
643 
644 /**
645     Starts a game replay
646     \param  filename    the filename of the replay file
647 */
startReplay(const std::string & filename)648 void startReplay(const std::string& filename) {
649     SDL_Log("Initializing replay...");
650     currentGame = new Game();
651     currentGame->initReplay(filename);
652 
653     currentGame->runMainLoop();
654 
655     delete currentGame;
656 
657     // Change music to menu music
658     musicPlayer->changeMusic(MUSIC_MENU);
659 }
660 
661 
662 /**
663     Starts a new game. If this game is quit it might start another game. This other game is also started from
664     this function. This is done until there is no more game to be started.
665     \param init contains all the information to start the game
666 */
startSinglePlayerGame(const GameInitSettings & init)667 void startSinglePlayerGame(const GameInitSettings& init)
668 {
669     GameInitSettings currentGameInitInfo = init;
670 
671     while(1) {
672 
673         SDL_Log("Initializing game...");
674         currentGame = new Game();
675         currentGame->initGame(currentGameInitInfo);
676 
677         // get init settings from game as it might have changed (through loading the game)
678         currentGameInitInfo = currentGame->getGameInitSettings();
679 
680         currentGame->runMainLoop();
681 
682         bool bGetNext = true;
683         while(bGetNext) {
684             switch(currentGame->whatNext()) {
685                 case GAME_DEBRIEFING_WIN: {
686                     SDL_Log("Debriefing...");
687                     BriefingMenu* pBriefing = new BriefingMenu(currentGameInitInfo.getHouseID(), currentGameInitInfo.getMission(), DEBRIEFING_WIN);
688                     pBriefing->showMenu();
689                     delete pBriefing;
690 
691                     SDL_Log("Game statistics...");
692                     CampaignStatsMenu* pCampaignStats = new CampaignStatsMenu(missionNumberToLevelNumber(currentGameInitInfo.getMission()));
693                     pCampaignStats->showMenu();
694                     delete pCampaignStats;
695 
696                     int houseID = currentGameInitInfo.getHouseID();
697 
698                     if(currentGameInitInfo.getGameType() == GameType::Campaign) {
699                         int level = missionNumberToLevelNumber(currentGameInitInfo.getMission());
700 
701                         if(level == 4 && (houseID == HOUSE_HARKONNEN || houseID == HOUSE_ATREIDES || houseID == HOUSE_ORDOS)) {
702                             SDL_Log("Playing meanwhile...");
703                             Meanwhile* pMeanwhile = new Meanwhile(houseID,true);
704                             pMeanwhile->run();
705                             delete pMeanwhile;
706                         } else if(level == 8 && (houseID == HOUSE_HARKONNEN || houseID == HOUSE_ATREIDES || houseID == HOUSE_ORDOS)) {
707                             SDL_Log("Playing meanwhile...");
708                             Meanwhile* pMeanwhile = new Meanwhile(houseID,false);
709                             pMeanwhile->run();
710                             delete pMeanwhile;
711                         } else if(level == 9) {
712                             SDL_Log("Playing finale.....");
713                             Finale* pFinale = new Finale(houseID);
714                             pFinale->run();
715                             delete pFinale;
716                         }
717                     }
718                 } break;
719 
720                 case GAME_DEBRIEFING_LOST: {
721                     SDL_Log("Debriefing...");
722                     BriefingMenu* pBriefing = new BriefingMenu(currentGameInitInfo.getHouseID(), currentGameInitInfo.getMission(), DEBRIEFING_LOST);
723                     pBriefing->showMenu();
724                     delete pBriefing;
725                 } break;
726 
727                 case GAME_CUSTOM_GAME_STATS: {
728                     SDL_Log("Game statistics...");
729                     CustomGameStatsMenu* pCustomGameStats = new CustomGameStatsMenu();
730                     pCustomGameStats->showMenu();
731                     delete pCustomGameStats;
732                 } break;
733 
734                 case GAME_LOAD:
735                 case GAME_NEXTMISSION: {
736                     currentGameInitInfo = currentGame->getNextGameInitSettings();
737                     delete currentGame;
738                     bGetNext = false;
739                 } break;
740 
741                 case GAME_RETURN_TO_MENU:
742                 default: {
743                     delete currentGame;
744                     currentGame = nullptr;
745 
746                     // Change music to menu music
747                     musicPlayer->changeMusic(MUSIC_MENU);
748 
749                     return;
750                 } break;
751             }
752         }
753 
754 
755     }
756 }
757 
758 /**
759     Starts a new multiplayer game.
760     \param init contains all the information to start the game
761 */
startMultiPlayerGame(const GameInitSettings & init)762 void startMultiPlayerGame(const GameInitSettings& init)
763 {
764     GameInitSettings currentGameInitInfo = init;
765 
766     SDL_Log("Initializing game...");
767     currentGame = new Game();
768     currentGame->initGame(currentGameInitInfo);
769 
770     // get init settings from game as it might have changed (through loading the game)
771     currentGameInitInfo = currentGame->getGameInitSettings();
772 
773     currentGame->runMainLoop();
774 
775     if(currentGame->whatNext() == GAME_CUSTOM_GAME_STATS) {
776         SDL_Log("Game statistics...");
777         CustomGameStatsMenu* pCustomGameStats = new CustomGameStatsMenu();
778         pCustomGameStats->showMenu();
779         delete pCustomGameStats;
780     }
781 
782     delete currentGame;
783     currentGame = nullptr;
784 }
785