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 #ifndef MAPEDITOR_H
19 #define MAPEDITOR_H
20 
21 #include <data.h>
22 
23 #include <MapEditor/MapData.h>
24 #include <MapEditor/ReinforcementInfo.h>
25 #include <MapEditor/TeamInfo.h>
26 #include <MapEditor/MapInfo.h>
27 #include <MapEditor/MapMirror.h>
28 #include <MapEditor/MapEditorInterface.h>
29 #include <MapEditor/MapEditorOperation.h>
30 
31 
32 #include <INIMap/INIMapEditorLoader.h>
33 
34 #include <ScreenBorder.h>
35 
36 #include <DataTypes.h>
37 
38 #include <SDL.h>
39 #include <string>
40 #include <vector>
41 #include <stack>
42 
43 class MapMirror;
44 
45 class MapEditor {
46 
47 public:
48 
49     class Player {
50     public:
51 
52         Player(const std::string& name, HOUSETYPE house, HOUSETYPE colorOfHouse, bool bActive, bool bAnyHouse, const std::string& brain = "Human", int maxunit = 0)
name(name)53          : name(name), house(house), colorOfHouse(colorOfHouse), bActive(bActive), bAnyHouse(bAnyHouse), brain(brain), maxunit(maxunit) {
54             quota = 0;
55             credits = 2000;
56         }
57 
58         std::string name;
59         HOUSETYPE house;
60         HOUSETYPE colorOfHouse;
61         bool bActive;
62         bool bAnyHouse;
63         int quota;
64         int credits;
65         std::string brain;
66         int maxunit;
67     };
68 
69     class EditorMode {
70     public:
71 
EditorMode()72         EditorMode()
73          : mode(EditorMode_Selection) {
74         }
75 
EditorMode(bool dummy)76         explicit EditorMode(bool dummy)
77          : mode(EditorMode_TacticalPos) {
78         }
79 
EditorMode(TERRAINTYPE terrainType,int pensize)80         EditorMode(TERRAINTYPE terrainType, int pensize)
81          : mode(EditorMode_Terrain), terrainType(terrainType), pensize(pensize) {
82         }
83 
EditorMode(HOUSETYPE house,int itemID,int health)84         EditorMode(HOUSETYPE house, int itemID, int health)
85          : mode(EditorMode_Structure), house(house), itemID(itemID), health(health) {
86         }
87 
EditorMode(HOUSETYPE house,int itemID,int health,unsigned char angle,ATTACKMODE attackmode)88         EditorMode(HOUSETYPE house, int itemID, int health, unsigned char angle, ATTACKMODE attackmode)
89          : mode(EditorMode_Unit), house(house), itemID(itemID), health(health), angle(angle), attackmode(attackmode) {
90         }
91 
92         enum {
93             EditorMode_Selection,
94             EditorMode_Terrain,
95             EditorMode_Structure,
96             EditorMode_Unit,
97             EditorMode_TacticalPos
98         } mode;
99 
100         TERRAINTYPE     terrainType = Terrain_Sand;
101         int             pensize = 0;
102         HOUSETYPE       house = HOUSE_HARKONNEN;
103         int             itemID = 0;
104         int             health = 0;
105         unsigned char   angle = 0;
106         ATTACKMODE      attackmode = ATTACKMODE_INVALID;
107     };
108 
109     class Structure {
110     public:
Structure(int id,HOUSETYPE house,int itemID,int health,Coord position)111         Structure(int id, HOUSETYPE house, int itemID, int health, Coord position)
112          : id(id), house(house), itemID(itemID), health(health), position(position) {
113 
114         }
115 
116         int             id;
117         HOUSETYPE       house;
118         int             itemID;
119         int             health;
120         Coord           position;
121     };
122 
123     class Unit {
124     public:
Unit(int id,HOUSETYPE house,int itemID,int health,Coord position,unsigned char angle,ATTACKMODE attackmode)125         Unit(int id, HOUSETYPE house, int itemID, int health, Coord position, unsigned char angle, ATTACKMODE attackmode)
126          : id(id), house(house), itemID(itemID), health(health), position(position), angle(angle), attackmode(attackmode) {
127 
128         }
129 
130         int             id;
131         HOUSETYPE       house;
132         int             itemID;
133         int             health;
134         Coord           position;
135         unsigned char   angle;
136         ATTACKMODE      attackmode;
137     };
138 
139     MapEditor();
140     MapEditor(const MapEditor& o) = delete;
141     ~MapEditor();
142 
143     friend class INIMapEditorLoader; ///< loading INI Maps is done with a INIMapEditorLoader helper object
144 
145     void RunEditor();
146 
onQuit()147     void onQuit() {
148         bQuitEditor = true;
149     }
150 
getLastSaveName()151     const std::string& getLastSaveName() const { return lastSaveName; };
152 
hasChangeSinceLastSave()153     bool hasChangeSinceLastSave() const { return bChangedSinceLastSave; };
154 
155     std::string generateMapname() const;
156 
getPlayers()157     std::vector<Player>& getPlayers() {
158         return players;
159     }
160 
informPlayersChanged()161     void informPlayersChanged() { pInterface->onHouseChanges(); };
162 
163     void setMirrorMode(MirrorMode newMirrorMode);
164 
getMapMirror()165     std::shared_ptr<MapMirror> getMapMirror() { return mapMirror; }
166 
getMapInfo()167     MapInfo& getMapInfo() { return mapInfo; };
168 
setMapInfo(MapInfo newMapInfo)169     void setMapInfo(MapInfo newMapInfo) { mapInfo = newMapInfo; };
170 
getMapVersion()171     int getMapVersion() const {
172         if(mapInfo.mapSeed != INVALID) {
173             return 1;
174         } else {
175             return 2;
176         }
177     }
178 
179     void setMap(const MapData& mapdata, const MapInfo& newMapInfo);
180 
getMap()181     MapData& getMap() {
182         return map;
183     }
184 
getSpiceBlooms()185     std::vector<Coord>& getSpiceBlooms() { return spiceBlooms; };
186 
getSpecialBlooms()187     std::vector<Coord>& getSpecialBlooms() { return specialBlooms; };
188 
getSpiceFields()189     std::vector<Coord>& getSpiceFields() { return spiceFields; };
190 
191 
getChoam()192     std::map<int,int>& getChoam() { return choam; };
193 
getReinforcements()194     std::vector<ReinforcementInfo>& getReinforcements() { return reinforcements; };
195 
setReinforcements(const std::vector<ReinforcementInfo> & newReinforcements)196     void setReinforcements(const std::vector<ReinforcementInfo>& newReinforcements) {
197         reinforcements = newReinforcements;
198     }
199 
getTeams()200     std::vector<TeamInfo>& getTeams() { return teams; };
201 
setTeams(const std::vector<TeamInfo> & newTeams)202     void setTeams(const std::vector<TeamInfo>& newTeams) {
203         teams = newTeams;
204     }
205 
getStructureList()206     std::vector<Structure>& getStructureList() {
207         return structures;
208     }
209 
getStructure(int structureID)210     Structure* getStructure(int structureID) {
211         for(Structure& structure : structures) {
212             if(structure.id == structureID) {
213                 return &structure;
214             }
215         }
216 
217         return nullptr;
218     }
219 
220     std::vector<int> getMirrorStructures(int unitID);
221 
getSelectedStructureID()222     int getSelectedStructureID() const {
223         return selectedStructureID;
224     }
225 
getSelectedStructure()226     Structure* getSelectedStructure() {
227         return getStructure(selectedStructureID);
228     }
229 
getUnitList()230     std::vector<Unit>& getUnitList() {
231         return units;
232     }
233 
getUnit(int unitID)234     Unit* getUnit(int unitID) {
235         for(Unit& unit : units) {
236             if(unit.id == unitID) {
237                 return &unit;
238             }
239         }
240 
241         return nullptr;
242     }
243 
244 
245     std::vector<int> getMirrorUnits(int unitID, bool bAddMissingAsInvalid = false);
246 
getSelectedUnitID()247     int getSelectedUnitID() const {
248         return selectedUnitID;
249     }
250 
getSelectedUnit()251     Unit* getSelectedUnit() {
252         return getUnit(selectedUnitID);
253     }
254 
255     bool isTileBlocked(int x, int y, bool bSlabIsBlocking, bool bUnitsAreBlocking) const;
256 
257     void setEditorMode(const EditorMode& newEditorMode);
258 
259     void startOperation();
260 
addUndoOperation(std::shared_ptr<MapEditorOperation> op)261     void addUndoOperation(std::shared_ptr<MapEditorOperation> op) {
262         undoOperationStack.push(op);
263         bChangedSinceLastSave = true;
264     }
265 
266     void undoLastOperation();
267 
268     void redoLastOperation();
269 
clearRedoOperations()270     inline void clearRedoOperations() {
271         while(!redoOperationStack.empty()) {
272             redoOperationStack.pop();
273         }
274     }
275 
276     void saveMap(const std::string& filepath);
277     void loadMap(const std::string& filepath);
278 
279 private:
280     void performMapEdit(int xpos, int ypos, bool bRepeated);
281 
282     void performTerrainChange(int x, int y, TERRAINTYPE terrainType);
283 
284     void drawScreen();
285     void processInput();
286     void drawCursor();
287     void drawMap(ScreenBorder* pScreenborder, bool bCompleteMap);
288     TERRAINTYPE getTerrain(int x, int y);
289     void saveMapshot();
290 
291 private:
292     MapEditorInterface*             pInterface;     ///< This is the whole interface (top bar and side bar)
293 
294 
295     SDL_Rect                        sideBarPos;
296     SDL_Rect                        topBarPos;
297     SDL_Rect                        bottomBarPos;
298 
299     bool                            bQuitEditor;
300 
301     bool                            scrollDownMode;     ///< currently scrolling the map down?
302     bool                            scrollLeftMode;     ///< currently scrolling the map left?
303     bool                            scrollRightMode;    ///< currently scrolling the map right?
304     bool                            scrollUpMode;       ///< currently scrolling the map up?
305 
306     bool                            shift;
307 
308     bool                            bChangedSinceLastSave;
309 
310     EditorMode                      currentEditorMode;
311 
312     MirrorMode                      currentMirrorMode;
313     std::shared_ptr<MapMirror>      mapMirror;
314 
315     bool                            bLeftMousePressed;
316     int                             lastTerrainEditPosX;
317     int                             lastTerrainEditPosY;
318 
319     int                             selectedUnitID;
320     int                             selectedStructureID;
321     Coord                           selectedMapItemCoord;   ///< only used for classic maps
322 
323 
324 
325     std::string                     lastSaveName;
326     std::shared_ptr<INIFile>        loadedINIFile;
327 
328     std::vector<Player>             players;
329 
330 
331     MapData                         map;
332     MapInfo                         mapInfo;
333 
334     std::vector<Coord>              spiceBlooms;    ///< only for classic maps
335     std::vector<Coord>              specialBlooms;  ///< only for classic maps
336     std::vector<Coord>              spiceFields;    ///< only for classic maps
337 
338     std::map<int,int>               choam;
339 
340     std::vector<ReinforcementInfo>  reinforcements;
341 
342     std::vector<TeamInfo>           teams;
343 
344     std::vector<Unit>               units;
345     std::vector<Structure>          structures;
346 
347 
348     std::stack<std::shared_ptr<MapEditorOperation> > undoOperationStack;
349     std::stack<std::shared_ptr<MapEditorOperation> > redoOperationStack;
350 };
351 
352 #endif // MAPEDITOR_H
353