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