Map Editor

RD Core / Commit #3

Commit Map Editor

Alex Alex committed 18/10/2026 23:40 main Patch
436 files +250,791 -0
A RD_Map_Editor/source/con_vector.h +79-0 View file
@@ -0,0 +1,79 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_CON_VECTOR_H_
19+#define RME_CON_VECTOR_H_
20+
21+#define REALLOC_INCREASE 600
22+
23+template <class T> // This only really works with pointers.. hrhr "T" might be abit misleading.. :o
24+class contigous_vector {
25+ T __pointer_check(T t) {
26+ return *t;
27+ } // If this fails, you have tried using this class with a non-pointer type, DONT
28+public:
29+ contigous_vector(size_t start_size = 7) {
30+ start = reinterpret_cast<T*>(malloc(sizeof(T) * start_size));
31+ memset(start, 0, sizeof(T) * start_size);
32+ sz = start_size;
33+ }
34+ ~contigous_vector() {
35+ free(start);
36+ }
37+
38+ void resize(size_t new_size) {
39+ size_t old_size = sz;
40+ start = reinterpret_cast<T*>(realloc(start, sizeof(T) * new_size));
41+ memset(start + old_size, 0, sizeof(T) * (new_size - old_size));
42+ sz = new_size;
43+ }
44+ size_t size() {
45+ return sz;
46+ }
47+
48+ T& locate(size_t index) {
49+ // Masterly inefficient!
50+ while (index >= sz) {
51+ resize(sz + REALLOC_INCREASE);
52+ }
53+ return start[index];
54+ }
55+
56+ T at(size_t index) const {
57+ if (index >= sz) {
58+ return nullptr;
59+ }
60+ return start[index];
61+ }
62+
63+ void set(size_t index, T value) {
64+ locate(index) = value;
65+ }
66+
67+ T operator[](size_t index) {
68+ return at(index);
69+ }
70+ const T operator[](size_t index) const {
71+ return at(index);
72+ }
73+
74+private:
75+ T* start;
76+ size_t sz;
77+};
78+
79+#endif
A RD_Map_Editor/source/copybuffer.cpp +310-0 View file
@@ -0,0 +1,310 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+
20+#include "copybuffer.h"
21+#include "editor.h"
22+#include "gui.h"
23+#include "creature.h"
24+#include "minimap_window.h"
25+
26+CopyBuffer::CopyBuffer() :
27+ tiles(newd BaseMap()) {
28+ ;
29+}
30+
31+size_t CopyBuffer::GetTileCount() {
32+ return tiles ? (size_t)tiles->size() : 0;
33+}
34+
35+BaseMap& CopyBuffer::getBufferMap() {
36+ ASSERT(tiles);
37+ return *tiles;
38+}
39+
40+CopyBuffer::~CopyBuffer() {
41+ clear();
42+}
43+
44+Position CopyBuffer::getPosition() const {
45+ ASSERT(tiles);
46+ return copyPos;
47+}
48+
49+void CopyBuffer::clear() {
50+ delete tiles;
51+ tiles = nullptr;
52+}
53+
54+void CopyBuffer::copy(Editor& editor, int floor) {
55+ if (editor.selection.size() == 0) {
56+ g_gui.SetStatusText("No tiles to copy.");
57+ return;
58+ }
59+
60+ clear();
61+ tiles = newd BaseMap();
62+
63+ int tile_count = 0;
64+ int item_count = 0;
65+ copyPos = Position(0xFFFF, 0xFFFF, floor);
66+
67+ for (TileSet::iterator it = editor.selection.begin(); it != editor.selection.end(); ++it) {
68+ ++tile_count;
69+
70+ Tile* tile = *it;
71+ TileLocation* newlocation = tiles->createTileL(tile->getPosition());
72+ Tile* copied_tile = tiles->allocator(newlocation);
73+
74+ if (tile->ground && tile->ground->isSelected()) {
75+ copied_tile->house_id = tile->house_id;
76+ copied_tile->setMapFlags(tile->getMapFlags());
77+ copied_tile->setZoneIds(tile);
78+ }
79+
80+ ItemVector tile_selection = tile->getSelectedItems();
81+ for (ItemVector::iterator iit = tile_selection.begin(); iit != tile_selection.end(); ++iit) {
82+ ++item_count;
83+ // Copy items to copybuffer
84+ copied_tile->addItem((*iit)->deepCopy());
85+ }
86+
87+ if (tile->creature && tile->creature->isSelected()) {
88+ copied_tile->creature = tile->creature->deepCopy();
89+ }
90+ if (tile->spawn && tile->spawn->isSelected()) {
91+ copied_tile->spawn = tile->spawn->deepCopy();
92+ }
93+
94+ tiles->setTile(copied_tile);
95+
96+ if (copied_tile->getX() < copyPos.x) {
97+ copyPos.x = copied_tile->getX();
98+ }
99+
100+ if (copied_tile->getY() < copyPos.y) {
101+ copyPos.y = copied_tile->getY();
102+ }
103+ }
104+
105+ std::ostringstream ss;
106+ ss << "Copied " << tile_count << " tile" << (tile_count > 1 ? "s" : "") << " (" << item_count << " item" << (item_count > 1 ? "s" : "") << ")";
107+ g_gui.SetStatusText(wxstr(ss.str()));
108+}
109+
110+void CopyBuffer::cut(Editor& editor, int floor) {
111+ if (editor.selection.size() == 0) {
112+ g_gui.SetStatusText("No tiles to cut.");
113+ return;
114+ }
115+
116+ clear();
117+ tiles = newd BaseMap();
118+
119+ int tile_count = 0;
120+ int item_count = 0;
121+ copyPos = Position(0xFFFF, 0xFFFF, floor);
122+
123+ BatchAction* batch = editor.actionQueue->createBatch(ACTION_CUT_TILES);
124+ Action* action = editor.actionQueue->createAction(batch);
125+
126+ PositionList tilestoborder;
127+
128+ for (TileSet::iterator it = editor.selection.begin(); it != editor.selection.end(); ++it) {
129+ tile_count++;
130+
131+ Tile* tile = *it;
132+ Tile* newtile = tile->deepCopy(editor.map);
133+ Tile* copied_tile = tiles->allocator(tile->getLocation());
134+
135+ if (tile->ground && tile->ground->isSelected()) {
136+ copied_tile->house_id = newtile->house_id;
137+ newtile->house_id = 0;
138+ copied_tile->setZoneIds(tile);
139+ copied_tile->setMapFlags(tile->getMapFlags());
140+ newtile->setMapFlags(TILESTATE_NONE);
141+ newtile->clearZoneId();
142+ }
143+
144+ ItemVector tile_selection = newtile->popSelectedItems();
145+ for (ItemVector::iterator iit = tile_selection.begin(); iit != tile_selection.end(); ++iit) {
146+ item_count++;
147+ // Add items to copybuffer
148+ copied_tile->addItem(*iit);
149+ }
150+
151+ if (newtile->creature && newtile->creature->isSelected()) {
152+ copied_tile->creature = newtile->creature;
153+ newtile->creature = nullptr;
154+ }
155+
156+ if (newtile->spawn && newtile->spawn->isSelected()) {
157+ copied_tile->spawn = newtile->spawn;
158+ newtile->spawn = nullptr;
159+ }
160+
161+ tiles->setTile(copied_tile->getPosition(), copied_tile);
162+
163+ if (copied_tile->getX() < copyPos.x) {
164+ copyPos.x = copied_tile->getX();
165+ }
166+
167+ if (copied_tile->getY() < copyPos.y) {
168+ copyPos.y = copied_tile->getY();
169+ }
170+
171+ if (g_settings.getInteger(Config::USE_AUTOMAGIC)) {
172+ for (int y = -1; y <= 1; y++) {
173+ for (int x = -1; x <= 1; x++) {
174+ tilestoborder.push_back(Position(tile->getX() + x, tile->getY() + y, tile->getZ()));
175+ }
176+ }
177+ }
178+ action->addChange(newd Change(newtile));
179+ }
180+
181+ batch->addAndCommitAction(action);
182+
183+ // Remove duplicates
184+ tilestoborder.sort();
185+ tilestoborder.unique();
186+
187+ if (g_settings.getInteger(Config::USE_AUTOMAGIC)) {
188+ action = editor.actionQueue->createAction(batch);
189+ for (PositionList::iterator it = tilestoborder.begin(); it != tilestoborder.end(); ++it) {
190+ TileLocation* location = editor.map.createTileL(*it);
191+ if (location->get()) {
192+ Tile* new_tile = location->get()->deepCopy(editor.map);
193+ new_tile->borderize(&editor.map);
194+ new_tile->wallize(&editor.map);
195+ action->addChange(newd Change(new_tile));
196+ } else {
197+ Tile* new_tile = editor.map.allocator(location);
198+ new_tile->borderize(&editor.map);
199+ if (new_tile->size()) {
200+ action->addChange(newd Change(new_tile));
201+ } else {
202+ delete new_tile;
203+ }
204+ }
205+ }
206+
207+ batch->addAndCommitAction(action);
208+ }
209+
210+ editor.addBatch(batch);
211+ std::stringstream ss;
212+ ss << "Cut out " << tile_count << " tile" << (tile_count > 1 ? "s" : "") << " (" << item_count << " item" << (item_count > 1 ? "s" : "") << ")";
213+ g_gui.SetStatusText(wxstr(ss.str()));
214+}
215+
216+void CopyBuffer::paste(Editor& editor, const Position& toPosition) {
217+ if (!tiles) {
218+ return;
219+ }
220+
221+ BatchAction* batchAction = editor.actionQueue->createBatch(ACTION_PASTE_TILES);
222+ Action* action = editor.actionQueue->createAction(batchAction);
223+
224+ // Track modified positions for minimap update
225+ PositionVector modifiedPositions;
226+
227+ // Original paste logic
228+ for (MapIterator it = tiles->begin(); it != tiles->end(); ++it) {
229+ Tile* buffer_tile = (*it)->get();
230+ Position pos = buffer_tile->getPosition() - copyPos + toPosition;
231+
232+ if (!pos.isValid()) {
233+ continue;
234+ }
235+
236+ // Add position for minimap update
237+ modifiedPositions.push_back(pos);
238+
239+ // Add surrounding positions for border updates
240+ for(int dx = -1; dx <= 1; dx++) {
241+ for(int dy = -1; dy <= 1; dy++) {
242+ Position borderPos(pos.x + dx, pos.y + dy, pos.z);
243+ if(borderPos.isValid()) {
244+ modifiedPositions.push_back(borderPos);
245+ }
246+ }
247+ }
248+
249+ TileLocation* location = editor.map.createTileL(pos);
250+ Tile* copy_tile = buffer_tile->deepCopy(editor.map);
251+ Tile* old_dest_tile = location->get();
252+ Tile* new_dest_tile = nullptr;
253+ copy_tile->setLocation(location);
254+
255+ if (g_settings.getInteger(Config::MERGE_PASTE) || !copy_tile->ground) {
256+ if (old_dest_tile) {
257+ new_dest_tile = old_dest_tile->deepCopy(editor.map);
258+ } else {
259+ new_dest_tile = editor.map.allocator(location);
260+ }
261+ new_dest_tile->merge(copy_tile);
262+ delete copy_tile;
263+ } else {
264+ new_dest_tile = copy_tile;
265+ }
266+
267+ action->addChange(newd Change(new_dest_tile));
268+ }
269+
270+ batchAction->addAndCommitAction(action);
271+
272+ if (g_settings.getInteger(Config::USE_AUTOMAGIC) && g_settings.getInteger(Config::BORDERIZE_PASTE)) {
273+ action = editor.actionQueue->createAction(batchAction);
274+ TileList borderize_tiles;
275+ Map& map = editor.map;
276+
277+ for (const Position& pos : modifiedPositions) {
278+ Tile* tile = map.getTile(pos);
279+ if (tile) {
280+ borderize_tiles.push_back(tile);
281+ }
282+ }
283+
284+ // Remove duplicates
285+ borderize_tiles.sort();
286+ borderize_tiles.unique();
287+
288+ for (Tile* tile : borderize_tiles) {
289+ if (tile) {
290+ Tile* newTile = tile->deepCopy(editor.map);
291+ newTile->borderize(&map);
292+ newTile->wallize(&map);
293+ action->addChange(newd Change(newTile));
294+ }
295+ }
296+
297+ batchAction->addAndCommitAction(action);
298+ }
299+
300+ editor.addBatch(batchAction);
301+
302+ // Update minimap with modified positions
303+ if (g_gui.minimap) {
304+ g_gui.minimap->UpdateDrawnTiles(modifiedPositions);
305+ }
306+}
307+
308+bool CopyBuffer::canPaste() const {
309+ return tiles && tiles->size() != 0;
310+}
A RD_Map_Editor/source/copybuffer.h +54-0 View file
@@ -0,0 +1,54 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_COPYBUFFER_H_
19+#define RME_COPYBUFFER_H_
20+
21+#include <wx/dataobj.h>
22+
23+#include "position.h"
24+#include "basemap.h"
25+
26+class Editor;
27+
28+class CopyBuffer {
29+public:
30+ CopyBuffer();
31+ virtual ~CopyBuffer();
32+
33+ // In-editor implantation
34+ void copy(Editor& editor, int floor);
35+ void cut(Editor& editor, int floor);
36+ void paste(Editor& editor, const Position& toPosition);
37+ bool canPaste() const;
38+ // Returns the upper-left corner of the copybuffer
39+ Position getPosition() const;
40+
41+ // Clears the copybuffer (eg. resets it)
42+ void clear();
43+
44+ size_t GetTileCount();
45+
46+ BaseMap& getBufferMap();
47+
48+private:
49+ void collectModifiedPositions(const Position& toPosition, PositionVector& positions);
50+ Position copyPos;
51+ BaseMap* tiles;
52+};
53+
54+#endif
A RD_Map_Editor/source/creature.cpp +86-0 View file
@@ -0,0 +1,86 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+
20+#include "creature.h"
21+
22+Creature::Creature(CreatureType* ctype) :
23+ direction(SOUTH), spawntime(0), saved(false), selected(false) {
24+ if (ctype) {
25+ type_name = ctype->name;
26+ }
27+}
28+
29+Creature::Creature(std::string ctype_name) :
30+ type_name(ctype_name), direction(SOUTH), spawntime(0), saved(false), selected(false) {
31+ ////
32+}
33+
34+Creature::~Creature() {
35+ ////
36+}
37+
38+std::string Creature::DirID2Name(uint16_t id) {
39+ switch (id) {
40+ case NORTH:
41+ return "North";
42+ case EAST:
43+ return "East";
44+ case SOUTH:
45+ return "South";
46+ case WEST:
47+ return "West";
48+ default:
49+ return "Unknown";
50+ }
51+}
52+
53+uint16_t Creature::DirName2ID(std::string dir) {
54+ to_lower_str(dir);
55+ if (dir == "north") {
56+ return NORTH;
57+ }
58+ if (dir == "east") {
59+ return EAST;
60+ }
61+ if (dir == "south") {
62+ return SOUTH;
63+ }
64+ if (dir == "west") {
65+ return WEST;
66+ }
67+ return SOUTH;
68+}
69+
70+Creature* Creature::deepCopy() const {
71+ Creature* copy = newd Creature(type_name);
72+ copy->spawntime = spawntime;
73+ copy->direction = direction;
74+ copy->selected = selected;
75+ copy->saved = saved;
76+ return copy;
77+}
78+
79+const Outfit& Creature::getLookType() const {
80+ CreatureType* type = g_creatures[type_name];
81+ if (type) {
82+ return type->outfit;
83+ }
84+ static const Outfit otfi; // Empty outfit
85+ return otfi;
86+}
A RD_Map_Editor/source/creature.h +128-0 View file
@@ -0,0 +1,128 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_CREATURE_H_
19+#define RME_CREATURE_H_
20+
21+#include "creatures.h"
22+
23+enum Direction {
24+ NORTH = 0,
25+ EAST = 1,
26+ SOUTH = 2,
27+ WEST = 3,
28+
29+ DIRECTION_FIRST = NORTH,
30+ DIRECTION_LAST = WEST
31+};
32+
33+IMPLEMENT_INCREMENT_OP(Direction)
34+
35+class Creature {
36+public:
37+ Creature(CreatureType* ctype);
38+ Creature(std::string type_name);
39+ ~Creature();
40+
41+ // Static conversions
42+ static std::string DirID2Name(uint16_t id);
43+ static uint16_t DirName2ID(std::string id);
44+
45+ Creature* deepCopy() const;
46+
47+ const Outfit& getLookType() const;
48+
49+ bool isSaved();
50+ void save();
51+ void reset();
52+
53+ bool isSelected() const {
54+ return selected;
55+ }
56+ void deselect() {
57+ selected = false;
58+ }
59+ void select() {
60+ selected = true;
61+ }
62+
63+ bool isNpc() const;
64+
65+ std::string getName() const;
66+ CreatureBrush* getBrush() const;
67+
68+ int getSpawnTime() const {
69+ return spawntime;
70+ }
71+ void setSpawnTime(int spawntime) {
72+ this->spawntime = spawntime;
73+ }
74+
75+ Direction getDirection() const {
76+ return direction;
77+ }
78+ void setDirection(Direction direction) {
79+ this->direction = direction;
80+ }
81+
82+protected:
83+ std::string type_name;
84+ Direction direction;
85+ int spawntime;
86+ bool saved;
87+ bool selected;
88+};
89+
90+inline void Creature::save() {
91+ saved = true;
92+}
93+
94+inline void Creature::reset() {
95+ saved = false;
96+}
97+
98+inline bool Creature::isSaved() {
99+ return saved;
100+}
101+
102+inline bool Creature::isNpc() const {
103+ CreatureType* type = g_creatures[type_name];
104+ if (type) {
105+ return type->isNpc;
106+ }
107+ return false;
108+}
109+
110+inline std::string Creature::getName() const {
111+ CreatureType* type = g_creatures[type_name];
112+ if (type) {
113+ return type->name;
114+ }
115+ return "";
116+}
117+inline CreatureBrush* Creature::getBrush() const {
118+ CreatureType* type = g_creatures[type_name];
119+ if (type) {
120+ return type->brush;
121+ }
122+ return nullptr;
123+}
124+
125+typedef std::vector<Creature*> CreatureVector;
126+typedef std::list<Creature*> CreatureList;
127+
128+#endif
A RD_Map_Editor/source/creatures.cpp +433-0 View file
@@ -0,0 +1,433 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+
20+#include "gui.h"
21+#include "materials.h"
22+#include "brush.h"
23+#include "creatures.h"
24+#include "creature_brush.h"
25+
26+CreatureDatabase g_creatures;
27+
28+CreatureType::CreatureType() :
29+ isNpc(false),
30+ missing(false),
31+ in_other_tileset(false),
32+ standard(false),
33+ name(""),
34+ brush(nullptr) {
35+ ////
36+}
37+
38+CreatureType::CreatureType(const CreatureType& ct) :
39+ isNpc(ct.isNpc),
40+ missing(ct.missing),
41+ in_other_tileset(ct.in_other_tileset),
42+ standard(ct.standard),
43+ name(ct.name),
44+ outfit(ct.outfit),
45+ brush(ct.brush) {
46+ ////
47+}
48+
49+CreatureType& CreatureType::operator=(const CreatureType& ct) {
50+ isNpc = ct.isNpc;
51+ missing = ct.missing;
52+ in_other_tileset = ct.in_other_tileset;
53+ standard = ct.standard;
54+ name = ct.name;
55+ outfit = ct.outfit;
56+ brush = ct.brush;
57+ return *this;
58+}
59+
60+CreatureType::~CreatureType() {
61+ ////
62+}
63+
64+CreatureType* CreatureType::loadFromXML(pugi::xml_node node, wxArrayString& warnings) {
65+ pugi::xml_attribute attribute;
66+ if (!(attribute = node.attribute("type"))) {
67+ warnings.push_back("Couldn't read type tag of creature node.");
68+ return nullptr;
69+ }
70+
71+ const std::string& tmpType = attribute.as_string();
72+ if (tmpType != "monster" && tmpType != "npc") {
73+ warnings.push_back("Invalid type tag of creature node \"" + wxstr(tmpType) + "\"");
74+ return nullptr;
75+ }
76+
77+ if (!(attribute = node.attribute("name"))) {
78+ warnings.push_back("Couldn't read name tag of creature node.");
79+ return nullptr;
80+ }
81+
82+ CreatureType* ct = newd CreatureType();
83+ ct->name = attribute.as_string();
84+ ct->isNpc = tmpType == "npc";
85+
86+ if ((attribute = node.attribute("looktype"))) {
87+ ct->outfit.lookType = attribute.as_int();
88+ if (g_gui.gfx.getCreatureSprite(ct->outfit.lookType) == nullptr) {
89+ warnings.push_back("Invalid creature \"" + wxstr(ct->name) + "\" look type #" + std::to_string(ct->outfit.lookType));
90+ }
91+ }
92+
93+ if ((attribute = node.attribute("lookitem"))) {
94+ ct->outfit.lookItem = attribute.as_int();
95+ }
96+
97+ if ((attribute = node.attribute("lookmount"))) {
98+ ct->outfit.lookMount = attribute.as_int();
99+ }
100+
101+ if ((attribute = node.attribute("lookaddon"))) {
102+ ct->outfit.lookAddon = attribute.as_int();
103+ }
104+
105+ if ((attribute = node.attribute("lookhead"))) {
106+ ct->outfit.lookHead = attribute.as_int();
107+ }
108+
109+ if ((attribute = node.attribute("lookbody"))) {
110+ ct->outfit.lookBody = attribute.as_int();
111+ }
112+
113+ if ((attribute = node.attribute("looklegs"))) {
114+ ct->outfit.lookLegs = attribute.as_int();
115+ }
116+
117+ if ((attribute = node.attribute("lookfeet"))) {
118+ ct->outfit.lookFeet = attribute.as_int();
119+ }
120+
121+ if ((attribute = node.attribute("lookmounthead"))) {
122+ ct->outfit.lookMountHead = attribute.as_int();
123+ }
124+
125+ if ((attribute = node.attribute("lookmountbody"))) {
126+ ct->outfit.lookMountBody = attribute.as_int();
127+ }
128+
129+ if ((attribute = node.attribute("lookmountlegs"))) {
130+ ct->outfit.lookMountLegs = attribute.as_int();
131+ }
132+
133+ if ((attribute = node.attribute("lookmountfeet"))) {
134+ ct->outfit.lookMountFeet = attribute.as_int();
135+ }
136+
137+ return ct;
138+}
139+
140+CreatureType* CreatureType::loadFromOTXML(const FileName& filename, pugi::xml_document& doc, wxArrayString& warnings) {
141+ ASSERT(doc != nullptr);
142+
143+ bool isNpc;
144+ pugi::xml_node node;
145+ if ((node = doc.child("monster"))) {
146+ isNpc = false;
147+ } else if ((node = doc.child("npc"))) {
148+ isNpc = true;
149+ } else {
150+ warnings.push_back("This file is not a monster/npc file");
151+ return nullptr;
152+ }
153+
154+ pugi::xml_attribute attribute;
155+ if (!(attribute = node.attribute("name"))) {
156+ warnings.push_back("Couldn't read name tag of creature node.");
157+ return nullptr;
158+ }
159+
160+ CreatureType* ct = newd CreatureType();
161+ if (isNpc) {
162+ ct->name = nstr(filename.GetName());
163+ } else {
164+ ct->name = attribute.as_string();
165+ }
166+ ct->isNpc = isNpc;
167+
168+ for (pugi::xml_node optionNode = node.first_child(); optionNode; optionNode = optionNode.next_sibling()) {
169+ if (as_lower_str(optionNode.name()) != "look") {
170+ continue;
171+ }
172+
173+ if ((attribute = optionNode.attribute("type"))) {
174+ ct->outfit.lookType = attribute.as_int();
175+ }
176+
177+ if ((attribute = optionNode.attribute("item")) || (attribute = optionNode.attribute("lookex")) || (attribute = optionNode.attribute("typeex"))) {
178+ ct->outfit.lookItem = attribute.as_int();
179+ }
180+
181+ if ((attribute = optionNode.attribute("mount"))) {
182+ ct->outfit.lookMount = attribute.as_int();
183+ }
184+
185+ if ((attribute = optionNode.attribute("addon"))) {
186+ ct->outfit.lookAddon = attribute.as_int();
187+ }
188+
189+ if ((attribute = optionNode.attribute("head"))) {
190+ ct->outfit.lookHead = attribute.as_int();
191+ }
192+
193+ if ((attribute = optionNode.attribute("body"))) {
194+ ct->outfit.lookBody = attribute.as_int();
195+ }
196+
197+ if ((attribute = optionNode.attribute("legs"))) {
198+ ct->outfit.lookLegs = attribute.as_int();
199+ }
200+
201+ if ((attribute = optionNode.attribute("feet"))) {
202+ ct->outfit.lookFeet = attribute.as_int();
203+ }
204+
205+ if ((attribute = optionNode.attribute("mounthead"))) {
206+ ct->outfit.lookMountHead = attribute.as_int();
207+ }
208+
209+ if ((attribute = optionNode.attribute("mountbody"))) {
210+ ct->outfit.lookMountBody = attribute.as_int();
211+ }
212+
213+ if ((attribute = optionNode.attribute("mountlegs"))) {
214+ ct->outfit.lookMountLegs = attribute.as_int();
215+ }
216+
217+ if ((attribute = optionNode.attribute("mountfeet"))) {
218+ ct->outfit.lookMountFeet = attribute.as_int();
219+ }
220+ }
221+ return ct;
222+}
223+
224+CreatureDatabase::CreatureDatabase() {
225+ ////
226+}
227+
228+CreatureDatabase::~CreatureDatabase() {
229+ clear();
230+}
231+
232+void CreatureDatabase::clear() {
233+ for (CreatureMap::iterator iter = creature_map.begin(); iter != creature_map.end(); ++iter) {
234+ delete iter->second;
235+ }
236+ creature_map.clear();
237+}
238+
239+CreatureType* CreatureDatabase::operator[](const std::string& name) {
240+ CreatureMap::iterator iter = creature_map.find(as_lower_str(name));
241+ if (iter != creature_map.end()) {
242+ return iter->second;
243+ }
244+ return nullptr;
245+}
246+
247+CreatureType* CreatureDatabase::addMissingCreatureType(const std::string& name, bool isNpc) {
248+ assert((*this)[name] == nullptr);
249+
250+ CreatureType* ct = newd CreatureType();
251+ ct->name = name;
252+ ct->isNpc = isNpc;
253+ ct->missing = true;
254+ ct->outfit.lookType = 130;
255+
256+ creature_map.insert(std::make_pair(as_lower_str(name), ct));
257+ return ct;
258+}
259+
260+CreatureType* CreatureDatabase::addCreatureType(const std::string& name, bool isNpc, const Outfit& outfit) {
261+ assert((*this)[name] == nullptr);
262+
263+ CreatureType* ct = newd CreatureType();
264+ ct->name = name;
265+ ct->isNpc = isNpc;
266+ ct->missing = false;
267+ ct->outfit = outfit;
268+
269+ creature_map.insert(std::make_pair(as_lower_str(name), ct));
270+ return ct;
271+}
272+
273+bool CreatureDatabase::hasMissing() const {
274+ for (CreatureMap::const_iterator iter = creature_map.begin(); iter != creature_map.end(); ++iter) {
275+ if (iter->second->missing) {
276+ return true;
277+ }
278+ }
279+ return false;
280+}
281+
282+bool CreatureDatabase::loadFromXML(const FileName& filename, bool standard, wxString& error, wxArrayString& warnings) {
283+ pugi::xml_document doc;
284+ pugi::xml_parse_result result = doc.load_file(filename.GetFullPath().mb_str());
285+ if (!result) {
286+ error = "Couldn't open file \"" + filename.GetFullName() + "\", invalid format?";
287+ return false;
288+ }
289+
290+ pugi::xml_node node = doc.child("creatures");
291+ if (!node) {
292+ error = "Invalid file signature, this file is not a valid creatures file.";
293+ return false;
294+ }
295+
296+ for (pugi::xml_node creatureNode = node.first_child(); creatureNode; creatureNode = creatureNode.next_sibling()) {
297+ if (as_lower_str(creatureNode.name()) != "creature") {
298+ continue;
299+ }
300+
301+ CreatureType* creatureType = CreatureType::loadFromXML(creatureNode, warnings);
302+ if (creatureType) {
303+ creatureType->standard = standard;
304+ if ((*this)[creatureType->name]) {
305+ warnings.push_back("Duplicate creature type name \"" + wxstr(creatureType->name) + "\"! Discarding...");
306+ delete creatureType;
307+ } else {
308+ creature_map[as_lower_str(creatureType->name)] = creatureType;
309+ }
310+ }
311+ }
312+ return true;
313+}
314+
315+bool CreatureDatabase::importXMLFromOT(const FileName& filename, wxString& error, wxArrayString& warnings) {
316+ pugi::xml_document doc;
317+ pugi::xml_parse_result result = doc.load_file(filename.GetFullPath().mb_str());
318+ if (!result) {
319+ error = "Couldn't open file \"" + filename.GetFullName() + "\", invalid format?";
320+ return false;
321+ }
322+
323+ pugi::xml_node node;
324+ if ((node = doc.child("monsters"))) {
325+ for (pugi::xml_node monsterNode = node.first_child(); monsterNode; monsterNode = monsterNode.next_sibling()) {
326+ if (as_lower_str(monsterNode.name()) != "monster") {
327+ continue;
328+ }
329+
330+ pugi::xml_attribute attribute;
331+ if (!(attribute = monsterNode.attribute("file"))) {
332+ continue;
333+ }
334+
335+ FileName monsterFile(filename);
336+ monsterFile.SetFullName(wxString(attribute.as_string(), wxConvUTF8));
337+
338+ pugi::xml_document monsterDoc;
339+ pugi::xml_parse_result monsterResult = monsterDoc.load_file(monsterFile.GetFullPath().mb_str());
340+ if (!monsterResult) {
341+ continue;
342+ }
343+
344+ CreatureType* creatureType = CreatureType::loadFromOTXML(monsterFile, monsterDoc, warnings);
345+ if (creatureType) {
346+ CreatureType* current = (*this)[creatureType->name];
347+ if (current) {
348+ *current = *creatureType;
349+ delete creatureType;
350+ } else {
351+ creature_map[as_lower_str(creatureType->name)] = creatureType;
352+
353+ Tileset* tileSet = nullptr;
354+ if (creatureType->isNpc) {
355+ tileSet = g_materials.tilesets["NPCs"];
356+ } else {
357+ tileSet = g_materials.tilesets["Others"];
358+ }
359+ ASSERT(tileSet != nullptr);
360+
361+ Brush* brush = newd CreatureBrush(creatureType);
362+ g_brushes.addBrush(brush);
363+
364+ TilesetCategory* tileSetCategory = tileSet->getCategory(TILESET_CREATURE);
365+ tileSetCategory->brushlist.push_back(brush);
366+ }
367+ }
368+ }
369+ } else if ((node = doc.child("monster")) || (node = doc.child("npc"))) {
370+ CreatureType* creatureType = CreatureType::loadFromOTXML(filename, doc, warnings);
371+ if (creatureType) {
372+ CreatureType* current = (*this)[creatureType->name];
373+
374+ if (current) {
375+ *current = *creatureType;
376+ delete creatureType;
377+ } else {
378+ creature_map[as_lower_str(creatureType->name)] = creatureType;
379+
380+ Tileset* tileSet = nullptr;
381+ if (creatureType->isNpc) {
382+ tileSet = g_materials.tilesets["NPCs"];
383+ } else {
384+ tileSet = g_materials.tilesets["Others"];
385+ }
386+ ASSERT(tileSet != nullptr);
387+
388+ Brush* brush = newd CreatureBrush(creatureType);
389+ g_brushes.addBrush(brush);
390+
391+ TilesetCategory* tileSetCategory = tileSet->getCategory(TILESET_CREATURE);
392+ tileSetCategory->brushlist.push_back(brush);
393+ }
394+ }
395+ } else {
396+ error = "This is not valid OT npc/monster data file.";
397+ return false;
398+ }
399+ return true;
400+}
401+
402+bool CreatureDatabase::saveToXML(const FileName& filename) {
403+ pugi::xml_document doc;
404+
405+ pugi::xml_node decl = doc.prepend_child(pugi::node_declaration);
406+ decl.append_attribute("version") = "1.0";
407+
408+ pugi::xml_node creatureNodes = doc.append_child("creatures");
409+ for (const auto& creatureEntry : creature_map) {
410+ CreatureType* creatureType = creatureEntry.second;
411+ if (!creatureType->standard) {
412+ pugi::xml_node creatureNode = creatureNodes.append_child("creature");
413+
414+ creatureNode.append_attribute("name") = creatureType->name.c_str();
415+ creatureNode.append_attribute("type") = creatureType->isNpc ? "npc" : "monster";
416+
417+ const Outfit& outfit = creatureType->outfit;
418+ creatureNode.append_attribute("looktype") = outfit.lookType;
419+ creatureNode.append_attribute("lookitem") = outfit.lookItem;
420+ creatureNode.append_attribute("lookmount") = outfit.lookMount;
421+ creatureNode.append_attribute("lookaddon") = outfit.lookAddon;
422+ creatureNode.append_attribute("lookhead") = outfit.lookHead;
423+ creatureNode.append_attribute("lookbody") = outfit.lookBody;
424+ creatureNode.append_attribute("looklegs") = outfit.lookLegs;
425+ creatureNode.append_attribute("lookfeet") = outfit.lookFeet;
426+ creatureNode.append_attribute("lookmounthead") = outfit.lookMountHead;
427+ creatureNode.append_attribute("lookmountbody") = outfit.lookMountBody;
428+ creatureNode.append_attribute("lookmountlegs") = outfit.lookMountLegs;
429+ creatureNode.append_attribute("lookmountfeet") = outfit.lookMountFeet;
430+ }
431+ }
432+ return doc.save_file(filename.GetFullPath().mb_str(), "\t", pugi::format_default, pugi::encoding_utf8);
433+}
A RD_Map_Editor/source/creatures.h +83-0 View file
@@ -0,0 +1,83 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_CREATURES_H_
19+#define RME_CREATURES_H_
20+
21+#include "outfit.h"
22+
23+#include <string>
24+#include <map>
25+
26+class CreatureType;
27+class CreatureBrush;
28+
29+typedef std::map<std::string, CreatureType*> CreatureMap;
30+
31+class CreatureDatabase {
32+protected:
33+ CreatureMap creature_map;
34+
35+public:
36+ typedef CreatureMap::iterator iterator;
37+ typedef CreatureMap::const_iterator const_iterator;
38+
39+ CreatureDatabase();
40+ ~CreatureDatabase();
41+
42+ void clear();
43+
44+ CreatureType* operator[](const std::string& name);
45+ CreatureType* addMissingCreatureType(const std::string& name, bool isNpc);
46+ CreatureType* addCreatureType(const std::string& name, bool isNpc, const Outfit& outfit);
47+
48+ bool hasMissing() const;
49+ iterator begin() {
50+ return creature_map.begin();
51+ }
52+ iterator end() {
53+ return creature_map.end();
54+ }
55+
56+ bool loadFromXML(const FileName& filename, bool standard, wxString& error, wxArrayString& warnings);
57+ bool importXMLFromOT(const FileName& filename, wxString& error, wxArrayString& warnings);
58+
59+ bool saveToXML(const FileName& filename);
60+};
61+
62+class CreatureType {
63+public:
64+ CreatureType();
65+ CreatureType(const CreatureType& ct);
66+ CreatureType& operator=(const CreatureType& ct);
67+ ~CreatureType();
68+
69+ bool isNpc;
70+ bool missing;
71+ bool in_other_tileset;
72+ bool standard;
73+ std::string name;
74+ Outfit outfit;
75+ CreatureBrush* brush;
76+
77+ static CreatureType* loadFromXML(pugi::xml_node node, wxArrayString& warnings);
78+ static CreatureType* loadFromOTXML(const FileName& filename, pugi::xml_document& node, wxArrayString& warnings);
79+};
80+
81+extern CreatureDatabase g_creatures;
82+
83+#endif
A RD_Map_Editor/source/creature_brush.cpp +92-0 View file
@@ -0,0 +1,92 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+
20+#include "creature_brush.h"
21+#include "gui.h"
22+#include "settings.h"
23+#include "tile.h"
24+#include "creature.h"
25+#include "basemap.h"
26+#include "spawn.h"
27+
28+//=============================================================================
29+// Creature brush
30+
31+CreatureBrush::CreatureBrush(CreatureType* type) :
32+ Brush(),
33+ creature_type(type) {
34+ ASSERT(type->brush == nullptr);
35+ type->brush = this;
36+}
37+
38+CreatureBrush::~CreatureBrush() {
39+ ////
40+}
41+
42+int CreatureBrush::getLookID() const {
43+ return 0;
44+}
45+
46+std::string CreatureBrush::getName() const {
47+ if (creature_type) {
48+ return creature_type->name;
49+ }
50+ return "Creature Brush";
51+}
52+
53+bool CreatureBrush::canDraw(BaseMap* map, const Position& position) const {
54+ Tile* tile = map->getTile(position);
55+ if (creature_type && tile && !tile->isBlocking()) {
56+ if (tile->getLocation()->getSpawnCount() != 0 || g_settings.getInteger(Config::AUTO_CREATE_SPAWN)) {
57+ if (tile->isPZ()) {
58+ if (creature_type->isNpc) {
59+ return true;
60+ }
61+ } else {
62+ return true;
63+ }
64+ }
65+ }
66+ return false;
67+}
68+
69+void CreatureBrush::undraw(BaseMap* map, Tile* tile) {
70+ delete tile->creature;
71+ tile->creature = nullptr;
72+}
73+
74+void CreatureBrush::draw(BaseMap* map, Tile* tile, void* parameter) {
75+ ASSERT(tile);
76+ ASSERT(parameter);
77+ draw_creature(map, tile);
78+}
79+
80+void CreatureBrush::draw_creature(BaseMap* map, Tile* tile) {
81+ if (canDraw(map, tile->getPosition())) {
82+ undraw(map, tile);
83+ if (creature_type) {
84+ if (tile->spawn == nullptr && tile->getLocation()->getSpawnCount() == 0) {
85+ // manually place spawn on location
86+ tile->spawn = newd Spawn(1);
87+ }
88+ tile->creature = newd Creature(creature_type);
89+ tile->creature->setSpawnTime(g_gui.GetSpawnTime());
90+ }
91+ }
92+}
A RD_Map_Editor/source/creature_brush.h +63-0 View file
@@ -0,0 +1,63 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_CREATURE_BRUSH_H
19+#define RME_CREATURE_BRUSH_H
20+
21+#include "brush.h"
22+
23+//=============================================================================
24+// CreatureBrush, place creatures
25+
26+class CreatureBrush : public Brush {
27+public:
28+ CreatureBrush(CreatureType* type); // Create a RAWBrush of the specified type
29+ virtual ~CreatureBrush();
30+
31+ bool isCreature() const {
32+ return true;
33+ }
34+ CreatureBrush* asCreature() {
35+ return static_cast<CreatureBrush*>(this);
36+ }
37+
38+ virtual bool canDraw(BaseMap* map, const Position& position) const;
39+ virtual void draw(BaseMap* map, Tile* tile, void* parameter);
40+ void draw_creature(BaseMap* map, Tile* tile);
41+ virtual void undraw(BaseMap* map, Tile* tile);
42+
43+ CreatureType* getType() const {
44+ return creature_type;
45+ }
46+
47+ virtual int getLookID() const; // We don't have a look type, this will always return 0
48+ virtual std::string getName() const;
49+ virtual bool canDrag() const {
50+ return false;
51+ }
52+ virtual bool canSmear() const {
53+ return true;
54+ }
55+ virtual bool oneSizeFitsAll() const {
56+ return true;
57+ }
58+
59+protected:
60+ CreatureType* creature_type;
61+};
62+
63+#endif
A RD_Map_Editor/source/creature_sprite_manager.cpp +298-0 View file
@@ -0,0 +1,298 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+/*
19+ * PROPOSED ENHANCEMENT: DYNAMIC MULTI-CELL SPRITE ALLOCATION IN PALETTE
20+ *
21+ * Current implementation limitation:
22+ * Currently, each creature is assigned to a single grid cell in the palette,
23+ * regardless of its natural size. This forces larger creatures (64x64, 96x96)
24+ * to be scaled down to fit in the standard grid, losing detail.
25+ *
26+ * Proposed solution:
27+ * Allow larger sprites to occupy multiple grid cells based on their natural dimensions.
28+ *
29+ * Implementation steps:
30+ *
31+ * 1. Modify the CreatureSeamlessGridPanel class:
32+ * - Add a 'sprite_cell_span' map that stores how many cells each sprite occupies
33+ * (both horizontally and vertically)
34+ * - E.g., a 32x32 sprite has span 1x1, a 64x64 has span 2x2, a 96x96 has span 3x3
35+ *
36+ * 2. Update the RecalculateGrid method:
37+ * - Consider sprite spans when calculating the grid layout
38+ * - Adjust cell positions so large sprites don't overlap
39+ * - Create a 2D grid map that tracks which cells are occupied
40+ *
41+ * 3. Update the GetSpriteIndexAt method:
42+ * - Map x,y coordinates to the correct sprite, considering spans
43+ * - Handle click events anywhere within a sprite's area
44+ *
45+ * 4. Update the DrawItemsToPanel method:
46+ * - Calculate each sprite's position based on its span
47+ * - Draw larger sprites across multiple grid cells
48+ * - Consider a staggered grid for more efficient space usage
49+ *
50+ * 5. Modify sprite placement algorithm:
51+ * - Implement a bin-packing algorithm for optimal space usage
52+ * - Consider a simple grid-based approach:
53+ * a. Sort sprites by size (largest first)
54+ * b. For each sprite, find the first available grid position
55+ * c. Mark the cells it occupies as taken
56+ *
57+ * 6. Update highlighting and selection:
58+ * - Highlight/select the entire area occupied by a sprite
59+ * - Use a special border style to indicate multi-cell sprites
60+ *
61+ * 7. Grid navigation improvements:
62+ * - Add keyboard navigation that respects sprite boundaries
63+ * - Ensure tabbing and arrow keys work logically with varying sprite sizes
64+ *
65+ * Implementation example for determining cell span:
66+ *
67+ * int GetCellSpan(int naturalSize) {
68+ * if (naturalSize <= 32) return 1;
69+ * if (naturalSize <= 64) return 2;
70+ * if (naturalSize <= 96) return 3;
71+ * return (naturalSize + 31) / 32; // Round up to nearest cell
72+ * }
73+ *
74+ * The end result would be a more space-efficient grid where larger creatures
75+ * get more screen real estate, showing them in their full detailed glory
76+ * without being constrained to a standard grid cell.
77+ */
78+
79+#include "main.h"
80+#include "creature_sprite_manager.h"
81+#include "creatures.h"
82+#include "creature.h"
83+#include "gui.h"
84+#include "creature_brush.h"
85+#include "graphics.h"
86+
87+CreatureSpriteManager g_creature_sprites;
88+
89+CreatureSpriteManager::CreatureSpriteManager() {
90+ // Constructor
91+}
92+
93+CreatureSpriteManager::~CreatureSpriteManager() {
94+ clear();
95+}
96+
97+void CreatureSpriteManager::clear() {
98+ // Delete all cached sprites
99+ for (auto& pair : sprite_cache) {
100+ delete pair.second;
101+ }
102+ sprite_cache.clear();
103+}
104+
105+wxBitmap* CreatureSpriteManager::getSpriteBitmap(int looktype, int width, int height) {
106+ // Create a combined key that includes dimensions and looktype
107+ // This ensures we have a unique cache for each size
108+ std::string key = std::to_string(looktype) + "_" + std::to_string(width) + "x" + std::to_string(height);
109+
110+ // Check if we already have this bitmap
111+ auto it = sprite_cache.find(key);
112+ if (it != sprite_cache.end()) {
113+ return it->second;
114+ }
115+
116+ // Create a new bitmap
117+ wxBitmap* bitmap = createSpriteBitmap(looktype, width, height);
118+ if (bitmap) {
119+ sprite_cache[key] = bitmap;
120+ }
121+
122+ return bitmap;
123+}
124+
125+wxBitmap* CreatureSpriteManager::getSpriteBitmap(int looktype, int head, int body, int legs, int feet, int width, int height) {
126+ // Create a combined key that includes dimensions, looktype and outfit colors
127+ std::string key = std::to_string(looktype) + "_" +
128+ std::to_string(head) + "_" +
129+ std::to_string(body) + "_" +
130+ std::to_string(legs) + "_" +
131+ std::to_string(feet) + "_" +
132+ std::to_string(width) + "x" + std::to_string(height);
133+
134+ // Check if we already have this bitmap
135+ auto it = sprite_cache.find(key);
136+ if (it != sprite_cache.end()) {
137+ return it->second;
138+ }
139+
140+ // Create a new bitmap
141+ wxBitmap* bitmap = createSpriteBitmap(looktype, head, body, legs, feet, width, height);
142+ if (bitmap) {
143+ sprite_cache[key] = bitmap;
144+ }
145+
146+ return bitmap;
147+}
148+
149+void CreatureSpriteManager::generateCreatureSprites(const BrushVector& creatures, int width, int height) {
150+ // Pre-generate sprites for a vector of creature brushes
151+ for (Brush* brush : creatures) {
152+ if (brush->isCreature()) {
153+ CreatureBrush* cb = static_cast<CreatureBrush*>(brush);
154+ if (cb && cb->getType()) {
155+ const Outfit& outfit = cb->getType()->outfit;
156+ int looktype = outfit.lookType;
157+ if (looktype > 0) {
158+ // Check if this has color components
159+ if (outfit.lookHead || outfit.lookBody || outfit.lookLegs || outfit.lookFeet) {
160+ getSpriteBitmap(looktype, outfit.lookHead, outfit.lookBody,
161+ outfit.lookLegs, outfit.lookFeet, width, height);
162+ } else {
163+ getSpriteBitmap(looktype, width, height);
164+ }
165+ }
166+ }
167+ }
168+ }
169+}
170+
171+wxBitmap* CreatureSpriteManager::createSpriteBitmap(int looktype, int width, int height) {
172+ // Find a creature with this looktype to get its full outfit details
173+ Outfit outfit;
174+ outfit.lookType = looktype;
175+
176+ for (CreatureDatabase::iterator it = g_creatures.begin(); it != g_creatures.end(); ++it) {
177+ CreatureType* type = it->second;
178+ if (type && type->outfit.lookType == looktype) {
179+ outfit = type->outfit;
180+ break;
181+ }
182+ }
183+
184+ // Now create the bitmap using the full outfit
185+ return createSpriteBitmap(looktype, outfit.lookHead, outfit.lookBody,
186+ outfit.lookLegs, outfit.lookFeet, width, height);
187+}
188+
189+wxBitmap* CreatureSpriteManager::createSpriteBitmap(int looktype, int head, int body, int legs, int feet, int width, int height) {
190+ // Get the sprite from graphics system
191+ GameSprite* spr = g_gui.gfx.getCreatureSprite(looktype);
192+ if (!spr) {
193+ return nullptr;
194+ }
195+
196+ // Calculate the natural sprite size and scaling needed
197+ // These are publicly available properties of the GameSprite class
198+ int natural_width = spr->width > 0 ? spr->width : 32;
199+ int natural_height = spr->height > 0 ? spr->height : 32;
200+
201+ // Calculate the natural size as the maximum of width and height
202+ // This ensures square display in the palette
203+ int natural_size = std::max(natural_width, natural_height);
204+
205+ // Round up to the nearest standard size (32, 64, 96, 128, etc.)
206+ if (natural_size <= 32) {
207+ natural_size = 32;
208+ } else if (natural_size <= 64) {
209+ natural_size = 64;
210+ } else if (natural_size <= 96) {
211+ natural_size = 96;
212+ } else if (natural_size <= 128) {
213+ natural_size = 128;
214+ } else {
215+ natural_size = ((natural_size + 31) / 32) * 32; // Round up to nearest multiple of 32
216+ }
217+
218+ // Fallback to heuristics if sprite dimensions are not available
219+ if (natural_size == 32 && looktype >= 800) {
220+ natural_size = 64; // Many high looktype monsters are larger
221+ }
222+
223+ // Fallback for very high looktypes known to be larger
224+ if (looktype >= 1200 && natural_size < 96) {
225+ natural_size = 96; // Some newer monsters can be 96x96
226+ }
227+
228+ bool is_large = (natural_size > 32);
229+
230+ // Create the bitmap with target dimensions
231+ wxBitmap* bitmap = new wxBitmap(width, height);
232+ wxMemoryDC dc(*bitmap);
233+
234+ // Set transparent background (magenta)
235+ dc.SetBackground(wxBrush(wxColour(255, 0, 255)));
236+ dc.Clear();
237+
238+ // Draw the creature sprite centered in the bitmap
239+ if (spr) {
240+ // Calculate offsets to center the sprite
241+ int offsetX = (width - natural_size) / 2;
242+ int offsetY = (height - natural_size) / 2;
243+
244+ // Adjust offsets for small target sizes
245+ if (width < natural_size) {
246+ offsetX = (width - std::min(width, 32)) / 2; // Minimum size
247+ }
248+ if (height < natural_size) {
249+ offsetY = (height - std::min(height, 32)) / 2; // Minimum size
250+ }
251+
252+ // Set up the outfit with colors
253+ Outfit full_outfit;
254+ full_outfit.lookType = looktype;
255+ full_outfit.lookHead = head;
256+ full_outfit.lookBody = body;
257+ full_outfit.lookLegs = legs;
258+ full_outfit.lookFeet = feet;
259+
260+ // Determine the sprite size to use based on target dimensions and natural size
261+ SpriteSize sprite_size = SPRITE_SIZE_32x32;
262+ if (width < 32 || height < 32) {
263+ sprite_size = SPRITE_SIZE_16x16;
264+ } else if (is_large) {
265+ sprite_size = SPRITE_SIZE_64x64;
266+ }
267+
268+ // Try to draw with outfit colors or fall back to regular drawing
269+ if (full_outfit.lookHead > 0 || full_outfit.lookBody > 0 ||
270+ full_outfit.lookLegs > 0 || full_outfit.lookFeet > 0) {
271+ // Check if the DrawOutfit method is available in the game's API
272+ // If not available, fall back to regular DrawTo
273+ try {
274+ // Try to use the dedicated outfit drawing method
275+ spr->DrawOutfit(&dc, sprite_size, offsetX, offsetY, full_outfit);
276+ } catch (...) {
277+ // Fallback in case DrawOutfit isn't available in this version
278+ spr->DrawTo(&dc, sprite_size, offsetX, offsetY);
279+ }
280+ } else {
281+ // Regular sprite without outfit colors
282+ spr->DrawTo(&dc, sprite_size, offsetX, offsetY);
283+ }
284+ }
285+
286+ // Ensure transparency works
287+ wxImage img = bitmap->ConvertToImage();
288+ img.SetMaskColour(255, 0, 255);
289+
290+ // Always scale to requested size to ensure proper display in palette
291+ if (width != img.GetWidth() || height != img.GetHeight()) {
292+ img = img.Scale(width, height, wxIMAGE_QUALITY_HIGH);
293+ }
294+
295+ *bitmap = wxBitmap(img);
296+
297+ return bitmap;
298+}
A RD_Map_Editor/source/creature_sprite_manager.h +56-0 View file
@@ -0,0 +1,56 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_CREATURE_SPRITE_MANAGER_H_
19+#define RME_CREATURE_SPRITE_MANAGER_H_
20+
21+#include "main.h"
22+#include "creature_brush.h"
23+#include "graphics.h"
24+#include <map>
25+
26+class CreatureSpriteManager {
27+public:
28+ CreatureSpriteManager();
29+ ~CreatureSpriteManager();
30+
31+ // Get or create a bitmap for a specific creature looktype
32+ wxBitmap* getSpriteBitmap(int looktype, int width = 32, int height = 32);
33+
34+ // Get or create a bitmap for a specific creature with outfit colors
35+ wxBitmap* getSpriteBitmap(int looktype, int head, int body, int legs, int feet, int width = 32, int height = 32);
36+
37+ // Pre-generate creature sprites for the palette view
38+ void generateCreatureSprites(const BrushVector& creatures, int width = 32, int height = 32);
39+
40+ // Clear all cached sprites
41+ void clear();
42+
43+private:
44+ // Cache of generated creature sprites
45+ std::map<std::string, wxBitmap*> sprite_cache;
46+
47+ // Helper to create a bitmap for a specific looktype
48+ wxBitmap* createSpriteBitmap(int looktype, int width, int height);
49+
50+ // Helper to create a bitmap with outfit colors
51+ wxBitmap* createSpriteBitmap(int looktype, int head, int body, int legs, int feet, int width, int height);
52+};
53+
54+extern CreatureSpriteManager g_creature_sprites;
55+
56+#endif // RME_CREATURE_SPRITE_MANAGER_H_
A RD_Map_Editor/source/dark_mode_manager.cpp +257-0 View file
@@ -0,0 +1,257 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+#include "dark_mode_manager.h"
20+#include "settings.h"
21+#include "main_menubar.h"
22+#include "main_toolbar.h"
23+#include "gui_ids.h"
24+
25+DarkModeManager g_darkMode;
26+
27+DarkModeManager::DarkModeManager() : isDarkModeEnabled(false) {
28+ UpdateColors();
29+}
30+
31+DarkModeManager::~DarkModeManager() {
32+ // Nothing to clean up
33+}
34+
35+void DarkModeManager::Initialize() {
36+ isDarkModeEnabled = g_settings.getBoolean(Config::DARK_MODE);
37+ UpdateColors();
38+}
39+
40+void DarkModeManager::ApplyTheme(wxWindow* window) {
41+ if (!window) return;
42+
43+ // Apply colors to the window itself
44+ window->SetBackgroundColour(GetBackgroundColor());
45+ window->SetForegroundColour(GetForegroundColor());
46+
47+ // Special handling for specific window types
48+ if (auto* menuBar = dynamic_cast<wxMenuBar*>(window)) {
49+ ApplyThemeToMenuBar(menuBar);
50+ }
51+ else if (auto* statusBar = dynamic_cast<wxStatusBar*>(window)) {
52+ ApplyThemeToStatusBar(statusBar);
53+ }
54+ else if (auto* toolBar = dynamic_cast<wxToolBar*>(window)) {
55+ ApplyThemeToToolBar(toolBar);
56+ }
57+ else if (auto* dialog = dynamic_cast<wxDialog*>(window)) {
58+ ApplyThemeToDialog(dialog);
59+ }
60+
61+ // Apply theme to all child windows
62+ for (auto* child : window->GetChildren()) {
63+ ApplyTheme(child);
64+ }
65+
66+ // Force a refresh
67+ window->Refresh();
68+}
69+
70+void DarkModeManager::ApplyThemeToMenuBar(wxMenuBar* menuBar) {
71+ if (!menuBar) return;
72+
73+ menuBar->SetBackgroundColour(GetMenuBackgroundColor());
74+ menuBar->SetForegroundColour(GetMenuForegroundColor());
75+
76+ // Don't try to set colors on individual menus, as wxMenu doesn't support
77+ // SetBackgroundColour and SetForegroundColour methods directly
78+ // The menu appearance will be controlled by the system theme or
79+ // parent window settings
80+}
81+
82+void DarkModeManager::ApplyThemeToMainMenuBar(MainMenuBar* menuBar) {
83+ if (!menuBar) return;
84+
85+ // No direct UI elements in MainMenuBar to theme
86+ // The actual wxMenuBar is part of the MainFrame
87+ // and will be themed separately
88+}
89+
90+void DarkModeManager::ApplyThemeToStatusBar(wxStatusBar* statusBar) {
91+ if (!statusBar) return;
92+
93+ statusBar->SetBackgroundColour(GetBackgroundColor());
94+ statusBar->SetForegroundColour(GetForegroundColor());
95+}
96+
97+void DarkModeManager::ApplyThemeToToolBar(wxToolBar* toolBar) {
98+ if (!toolBar) return;
99+
100+ toolBar->SetBackgroundColour(GetBackgroundColor());
101+ toolBar->SetForegroundColour(GetForegroundColor());
102+}
103+
104+void DarkModeManager::ApplyThemeToMainToolBar(MainToolBar* toolBar) {
105+ if (!toolBar) return;
106+
107+ // The MainToolBar class contains multiple wxAuiToolBar instances
108+ // Try to apply theme to them one by one
109+ try {
110+ wxAuiPaneInfo standardPane = toolBar->GetPane(TOOLBAR_STANDARD);
111+ if (wxAuiToolBar* tb = dynamic_cast<wxAuiToolBar*>(standardPane.window)) {
112+ tb->SetBackgroundColour(GetBackgroundColor());
113+ tb->SetForegroundColour(GetForegroundColor());
114+ tb->Refresh();
115+ }
116+ } catch (...) {
117+ // Ignore errors if unable to access this toolbar
118+ }
119+
120+ try {
121+ wxAuiPaneInfo brushesPane = toolBar->GetPane(TOOLBAR_BRUSHES);
122+ if (wxAuiToolBar* tb = dynamic_cast<wxAuiToolBar*>(brushesPane.window)) {
123+ tb->SetBackgroundColour(GetBackgroundColor());
124+ tb->SetForegroundColour(GetForegroundColor());
125+ tb->Refresh();
126+ }
127+ } catch (...) {
128+ // Ignore errors if unable to access this toolbar
129+ }
130+
131+ try {
132+ wxAuiPaneInfo positionPane = toolBar->GetPane(TOOLBAR_POSITION);
133+ if (wxAuiToolBar* tb = dynamic_cast<wxAuiToolBar*>(positionPane.window)) {
134+ tb->SetBackgroundColour(GetBackgroundColor());
135+ tb->SetForegroundColour(GetForegroundColor());
136+ tb->Refresh();
137+ }
138+ } catch (...) {
139+ // Ignore errors if unable to access this toolbar
140+ }
141+
142+ try {
143+ wxAuiPaneInfo sizesPane = toolBar->GetPane(TOOLBAR_SIZES);
144+ if (wxAuiToolBar* tb = dynamic_cast<wxAuiToolBar*>(sizesPane.window)) {
145+ tb->SetBackgroundColour(GetBackgroundColor());
146+ tb->SetForegroundColour(GetForegroundColor());
147+ tb->Refresh();
148+ }
149+ } catch (...) {
150+ // Ignore errors if unable to access this toolbar
151+ }
152+}
153+
154+void DarkModeManager::ApplyThemeToDialog(wxDialog* dialog) {
155+ if (!dialog) return;
156+
157+ dialog->SetBackgroundColour(GetBackgroundColor());
158+ dialog->SetForegroundColour(GetForegroundColor());
159+}
160+
161+wxColour DarkModeManager::GetBackgroundColor() const {
162+ return backgroundColor;
163+}
164+
165+wxColour DarkModeManager::GetForegroundColor() const {
166+ return foregroundColor;
167+}
168+
169+wxColour DarkModeManager::GetMenuBackgroundColor() const {
170+ return menuBackgroundColor;
171+}
172+
173+wxColour DarkModeManager::GetMenuForegroundColor() const {
174+ return menuForegroundColor;
175+}
176+
177+wxColour DarkModeManager::GetSelectionBackgroundColor() const {
178+ return selectionBackgroundColor;
179+}
180+
181+wxColour DarkModeManager::GetSelectionForegroundColor() const {
182+ return selectionForegroundColor;
183+}
184+
185+wxColour DarkModeManager::GetPanelBackgroundColor() const {
186+ return panelBackgroundColor;
187+}
188+
189+wxColour DarkModeManager::GetBorderColor() const {
190+ return borderColor;
191+}
192+
193+void DarkModeManager::ToggleDarkMode() {
194+ isDarkModeEnabled = !isDarkModeEnabled;
195+ g_settings.setInteger(Config::DARK_MODE, isDarkModeEnabled ? 1 : 0);
196+ UpdateColors();
197+}
198+
199+bool DarkModeManager::IsDarkModeEnabled() const {
200+ return isDarkModeEnabled;
201+}
202+
203+void DarkModeManager::UpdateColors() {
204+ if (isDarkModeEnabled) {
205+ // Dark mode colors
206+ if (g_settings.getBoolean(Config::DARK_MODE_CUSTOM_COLOR)) {
207+ // Use custom dark mode colors from settings
208+ wxColour customColor(
209+ g_settings.getInteger(Config::DARK_MODE_RED),
210+ g_settings.getInteger(Config::DARK_MODE_GREEN),
211+ g_settings.getInteger(Config::DARK_MODE_BLUE)
212+ );
213+
214+ backgroundColor = customColor;
215+ // Adjust other colors based on the custom color
216+ foregroundColor = wxColour(230, 230, 230);
217+ menuBackgroundColor = wxColour(
218+ wxMin(customColor.Red() + 10, 255),
219+ wxMin(customColor.Green() + 10, 255),
220+ wxMin(customColor.Blue() + 10, 255)
221+ );
222+ menuForegroundColor = wxColour(230, 230, 230);
223+ selectionBackgroundColor = wxColour(65, 105, 225);
224+ selectionForegroundColor = wxColour(255, 255, 255);
225+ panelBackgroundColor = wxColour(
226+ wxMin(customColor.Red() + 5, 255),
227+ wxMin(customColor.Green() + 5, 255),
228+ wxMin(customColor.Blue() + 5, 255)
229+ );
230+ borderColor = wxColour(
231+ wxMin(customColor.Red() + 30, 255),
232+ wxMin(customColor.Green() + 30, 255),
233+ wxMin(customColor.Blue() + 30, 255)
234+ );
235+ } else {
236+ // Default dark mode colors
237+ backgroundColor = wxColour(45, 45, 48);
238+ foregroundColor = wxColour(230, 230, 230);
239+ menuBackgroundColor = wxColour(50, 50, 55);
240+ menuForegroundColor = wxColour(230, 230, 230);
241+ selectionBackgroundColor = wxColour(65, 105, 225);
242+ selectionForegroundColor = wxColour(255, 255, 255);
243+ panelBackgroundColor = wxColour(45, 45, 48);
244+ borderColor = wxColour(70, 70, 75);
245+ }
246+ } else {
247+ // Light mode colors (default wxWidgets colors)
248+ backgroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
249+ foregroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
250+ menuBackgroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_MENU);
251+ menuForegroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_MENUTEXT);
252+ selectionBackgroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
253+ selectionForegroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
254+ panelBackgroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
255+ borderColor = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
256+ }
257+}
A RD_Map_Editor/source/dark_mode_manager.h +83-0 View file
@@ -0,0 +1,83 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_DARK_MODE_MANAGER_H_
19+#define RME_DARK_MODE_MANAGER_H_
20+
21+#include "main.h"
22+
23+// Forward declarations for custom menu/toolbar classes
24+class MainMenuBar;
25+class MainToolBar;
26+
27+class DarkModeManager {
28+public:
29+ DarkModeManager();
30+ ~DarkModeManager();
31+
32+ // Initialize and set up dark mode
33+ void Initialize();
34+
35+ // Apply theme to a window and all its children
36+ void ApplyTheme(wxWindow* window);
37+
38+ // Apply theme to specific controls
39+ void ApplyThemeToMenuBar(wxMenuBar* menuBar);
40+ void ApplyThemeToStatusBar(wxStatusBar* statusBar);
41+ void ApplyThemeToToolBar(wxToolBar* toolBar);
42+ void ApplyThemeToDialog(wxDialog* dialog);
43+
44+ // Apply theme to custom classes
45+ void ApplyThemeToMainMenuBar(MainMenuBar* menuBar);
46+ void ApplyThemeToMainToolBar(MainToolBar* toolBar);
47+
48+ // Get colors for UI elements
49+ wxColour GetBackgroundColor() const;
50+ wxColour GetForegroundColor() const;
51+ wxColour GetMenuBackgroundColor() const;
52+ wxColour GetMenuForegroundColor() const;
53+ wxColour GetSelectionBackgroundColor() const;
54+ wxColour GetSelectionForegroundColor() const;
55+ wxColour GetPanelBackgroundColor() const;
56+ wxColour GetBorderColor() const;
57+
58+ // Toggle dark mode
59+ void ToggleDarkMode();
60+
61+ // Check if dark mode is enabled
62+ bool IsDarkModeEnabled() const;
63+
64+private:
65+ bool isDarkModeEnabled;
66+
67+ // Cache colors to avoid constant recalculation
68+ wxColour backgroundColor;
69+ wxColour foregroundColor;
70+ wxColour menuBackgroundColor;
71+ wxColour menuForegroundColor;
72+ wxColour selectionBackgroundColor;
73+ wxColour selectionForegroundColor;
74+ wxColour panelBackgroundColor;
75+ wxColour borderColor;
76+
77+ // Update cached colors
78+ void UpdateColors();
79+};
80+
81+extern DarkModeManager g_darkMode;
82+
83+#endif // RME_DARK_MODE_MANAGER_H_
A RD_Map_Editor/source/dat_debug_view.cpp +115-0 View file
@@ -0,0 +1,115 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+
20+#include "dat_debug_view.h"
21+
22+#include "graphics.h"
23+#include "gui.h"
24+
25+// ============================================================================
26+//
27+
28+class DatDebugViewListBox : public wxVListBox {
29+public:
30+ DatDebugViewListBox(wxWindow* parent, wxWindowID id);
31+ ~DatDebugViewListBox();
32+
33+ void OnDrawItem(wxDC& dc, const wxRect& rect, size_t index) const;
34+ wxCoord OnMeasureItem(size_t index) const;
35+
36+protected:
37+ typedef std::map<int, Sprite*> SpriteMap;
38+ SpriteMap sprites;
39+};
40+
41+DatDebugViewListBox::DatDebugViewListBox(wxWindow* parent, wxWindowID id) :
42+ wxVListBox(parent, id, wxDefaultPosition, wxDefaultSize, wxLB_SINGLE) {
43+ int n = 0;
44+ for (int id = 0; id < g_gui.gfx.getItemSpriteMaxID(); ++id) {
45+ Sprite* spr = g_gui.gfx.getSprite(id);
46+ if (spr) {
47+ sprites[n] = spr;
48+ ++n;
49+ }
50+ }
51+ SetItemCount(n);
52+}
53+
54+DatDebugViewListBox::~DatDebugViewListBox() {
55+ ////
56+}
57+
58+void DatDebugViewListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const {
59+ SpriteMap::const_iterator spr_iter = sprites.find(int(n));
60+ if (spr_iter != sprites.end()) {
61+ spr_iter->second->DrawTo(&dc, SPRITE_SIZE_32x32, rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight());
62+ }
63+
64+ if (IsSelected(n)) {
65+ if (HasFocus()) {
66+ dc.SetTextForeground(wxColor(0xFF, 0xFF, 0xFF));
67+ } else {
68+ dc.SetTextForeground(wxColor(0x00, 0x00, 0xFF));
69+ }
70+ } else {
71+ dc.SetTextForeground(wxColor(0x00, 0x00, 0x00));
72+ }
73+
74+ dc.DrawText(wxString() << n, rect.GetX() + 40, rect.GetY() + 6);
75+}
76+
77+wxCoord DatDebugViewListBox::OnMeasureItem(size_t n) const {
78+ return 32;
79+}
80+
81+// ============================================================================
82+//
83+
84+BEGIN_EVENT_TABLE(DatDebugView, wxPanel)
85+EVT_TEXT(wxID_ANY, DatDebugView::OnTextChange)
86+EVT_LISTBOX_DCLICK(wxID_ANY, DatDebugView::OnClickList)
87+END_EVENT_TABLE()
88+
89+DatDebugView::DatDebugView(wxWindow* parent) :
90+ wxPanel(parent) {
91+ wxSizer* sizer = newd wxBoxSizer(wxVERTICAL);
92+
93+ search_field = newd wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize);
94+ search_field->SetFocus();
95+ sizer->Add(search_field, 0, wxEXPAND, 2);
96+
97+ item_list = newd DatDebugViewListBox(this, wxID_ANY);
98+ item_list->SetMinSize(wxSize(470, 400));
99+ sizer->Add(item_list, 1, wxEXPAND | wxALL, 2);
100+
101+ SetSizerAndFit(sizer);
102+ Centre(wxBOTH);
103+}
104+
105+DatDebugView::~DatDebugView() {
106+ ////
107+}
108+
109+void DatDebugView::OnTextChange(wxCommandEvent& evt) {
110+ ////
111+}
112+
113+void DatDebugView::OnClickList(wxCommandEvent& evt) {
114+ ////
115+}
A RD_Map_Editor/source/dat_debug_view.h +38-0 View file
@@ -0,0 +1,38 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_DAT_DEBUG_VIEW_H_
19+#define RME_DAT_DEBUG_VIEW_H_
20+
21+class DatDebugViewListBox;
22+
23+class DatDebugView : public wxPanel {
24+public:
25+ DatDebugView(wxWindow* parent);
26+ ~DatDebugView();
27+
28+ void OnTextChange(wxCommandEvent&);
29+ void OnClickList(wxCommandEvent&);
30+
31+protected:
32+ DatDebugViewListBox* item_list;
33+ wxTextCtrl* search_field;
34+
35+ DECLARE_EVENT_TABLE()
36+};
37+
38+#endif
A RD_Map_Editor/source/dcbutton.cpp +188-0 View file
@@ -0,0 +1,188 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+
20+#include "settings.h"
21+
22+#include "dcbutton.h"
23+#include "sprites.h"
24+#include "gui.h"
25+
26+BEGIN_EVENT_TABLE(DCButton, wxPanel)
27+EVT_PAINT(DCButton::OnPaint)
28+EVT_LEFT_DOWN(DCButton::OnClick)
29+END_EVENT_TABLE()
30+
31+IMPLEMENT_DYNAMIC_CLASS(DCButton, wxPanel)
32+
33+DCButton::DCButton() :
34+ wxPanel(nullptr, wxID_ANY, wxDefaultPosition, wxSize(36, 36)),
35+ type(DC_BTN_NORMAL),
36+ state(false),
37+ size(RENDER_SIZE_16x16),
38+ sprite(nullptr),
39+ overlay(nullptr) {
40+ SetSprite(0);
41+}
42+
43+DCButton::DCButton(wxWindow* parent, wxWindowID id, wxPoint pos, int type, RenderSize sz, int sprite_id) :
44+ wxPanel(parent, id, pos, (sz == RENDER_SIZE_64x64 ? wxSize(68, 68) : sz == RENDER_SIZE_32x32 ? wxSize(36, 36)
45+ : wxSize(20, 20))),
46+ type(type),
47+ state(false),
48+ size(sz),
49+ sprite(nullptr),
50+ overlay(nullptr) {
51+ SetSprite(sprite_id);
52+}
53+
54+DCButton::~DCButton() {
55+ ////
56+}
57+
58+void DCButton::SetSprite(int _sprid) {
59+ if (_sprid != 0) {
60+ sprite = g_gui.gfx.getSprite(_sprid);
61+ } else {
62+ sprite = nullptr;
63+ }
64+ Refresh();
65+}
66+
67+void DCButton::SetOverlay(Sprite* espr) {
68+ overlay = espr;
69+ Refresh();
70+}
71+
72+void DCButton::SetValue(bool val) {
73+ ASSERT(type == DC_BTN_TOGGLE);
74+ bool oldval = val;
75+ state = val;
76+ if (state == oldval) {
77+ // Cheap to change value to the old one (which is done ALOT)
78+ if (GetValue() && g_settings.getInteger(Config::USE_GUI_SELECTION_SHADOW)) {
79+ SetOverlay(g_gui.gfx.getSprite(EDITOR_SPRITE_SELECTION_MARKER));
80+ } else {
81+ SetOverlay(nullptr);
82+ }
83+ Refresh();
84+ }
85+}
86+
87+bool DCButton::GetValue() const {
88+ ASSERT(type == DC_BTN_TOGGLE);
89+ return state;
90+}
91+
92+void DCButton::OnPaint(wxPaintEvent& event) {
93+ wxBufferedPaintDC pdc(this);
94+
95+ if (g_gui.gfx.isUnloaded()) {
96+ return;
97+ }
98+
99+ static std::unique_ptr<wxPen> highlight_pen;
100+ static std::unique_ptr<wxPen> dark_highlight_pen;
101+ static std::unique_ptr<wxPen> light_shadow_pen;
102+ static std::unique_ptr<wxPen> shadow_pen;
103+
104+ if (highlight_pen.get() == nullptr) {
105+ highlight_pen.reset(newd wxPen(wxColor(0xFF, 0xFF, 0xFF), 1, wxSOLID));
106+ }
107+ if (dark_highlight_pen.get() == nullptr) {
108+ dark_highlight_pen.reset(newd wxPen(wxColor(0xD4, 0xD0, 0xC8), 1, wxSOLID));
109+ }
110+ if (light_shadow_pen.get() == nullptr) {
111+ light_shadow_pen.reset(newd wxPen(wxColor(0x80, 0x80, 0x80), 1, wxSOLID));
112+ }
113+ if (shadow_pen.get() == nullptr) {
114+ shadow_pen.reset(newd wxPen(wxColor(0x40, 0x40, 0x40), 1, wxSOLID));
115+ }
116+
117+ int size_x = 20, size_y = 20;
118+
119+ if (size == RENDER_SIZE_16x16) {
120+ size_x = 20;
121+ size_y = 20;
122+ } else if (size == RENDER_SIZE_32x32) {
123+ size_x = 36;
124+ size_y = 36;
125+ }
126+
127+ pdc.SetBrush(*wxBLACK);
128+ pdc.DrawRectangle(0, 0, size_x, size_y);
129+ if (type == DC_BTN_TOGGLE && GetValue()) {
130+ pdc.SetPen(*shadow_pen);
131+ pdc.DrawLine(0, 0, size_x - 1, 0);
132+ pdc.DrawLine(0, 1, 0, size_y - 1);
133+ pdc.SetPen(*light_shadow_pen);
134+ pdc.DrawLine(1, 1, size_x - 2, 1);
135+ pdc.DrawLine(1, 2, 1, size_y - 2);
136+ pdc.SetPen(*dark_highlight_pen);
137+ pdc.DrawLine(size_x - 2, 1, size_x - 2, size_y - 2);
138+ pdc.DrawLine(1, size_y - 2, size_x - 1, size_y - 2);
139+ pdc.SetPen(*highlight_pen);
140+ pdc.DrawLine(size_x - 1, 0, size_x - 1, size_y - 1);
141+ pdc.DrawLine(0, size_y - 1, size_y, size_y - 1);
142+ } else {
143+ pdc.SetPen(*highlight_pen);
144+ pdc.DrawLine(0, 0, size_x - 1, 0);
145+ pdc.DrawLine(0, 1, 0, size_y - 1);
146+ pdc.SetPen(*dark_highlight_pen);
147+ pdc.DrawLine(1, 1, size_x - 2, 1);
148+ pdc.DrawLine(1, 2, 1, size_y - 2);
149+ pdc.SetPen(*light_shadow_pen);
150+ pdc.DrawLine(size_x - 2, 1, size_x - 2, size_y - 2);
151+ pdc.DrawLine(1, size_y - 2, size_x - 1, size_y - 2);
152+ pdc.SetPen(*shadow_pen);
153+ pdc.DrawLine(size_x - 1, 0, size_x - 1, size_y - 1);
154+ pdc.DrawLine(0, size_y - 1, size_y, size_y - 1);
155+ }
156+
157+ if (sprite) {
158+ if (size == RENDER_SIZE_16x16) {
159+ // Draw the picture!
160+ sprite->DrawTo(&pdc, SPRITE_SIZE_16x16, 2, 2);
161+
162+ if (overlay && type == DC_BTN_TOGGLE && GetValue()) {
163+ overlay->DrawTo(&pdc, SPRITE_SIZE_16x16, 2, 2);
164+ }
165+ } else if (size == RENDER_SIZE_32x32) {
166+ // Draw the picture!
167+ sprite->DrawTo(&pdc, SPRITE_SIZE_32x32, 2, 2);
168+
169+ if (overlay && type == DC_BTN_TOGGLE && GetValue()) {
170+ overlay->DrawTo(&pdc, SPRITE_SIZE_32x32, 2, 2);
171+ }
172+ } else if (size == RENDER_SIZE_64x64) {
173+ ////
174+ }
175+ }
176+}
177+
178+void DCButton::OnClick(wxMouseEvent& WXUNUSED(evt)) {
179+ wxCommandEvent event(type == DC_BTN_TOGGLE ? wxEVT_COMMAND_TOGGLEBUTTON_CLICKED : wxEVT_COMMAND_BUTTON_CLICKED, GetId());
180+ event.SetEventObject(this);
181+
182+ if (type == DC_BTN_TOGGLE) {
183+ SetValue(!GetValue());
184+ }
185+ SetFocus();
186+
187+ GetEventHandler()->ProcessEvent(event);
188+}
A RD_Map_Editor/source/dcbutton.h +63-0 View file
@@ -0,0 +1,63 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_DC_BUTTON_H
19+#define RME_DC_BUTTON_H
20+
21+class Sprite;
22+class GameSprite;
23+class EditorSprite;
24+
25+enum {
26+ DC_BTN_NORMAL,
27+ DC_BTN_TOGGLE,
28+};
29+
30+enum RenderSize {
31+ RENDER_SIZE_16x16,
32+ RENDER_SIZE_32x32,
33+ RENDER_SIZE_64x64,
34+};
35+
36+class DCButton : public wxPanel {
37+public:
38+ DCButton();
39+ DCButton(wxWindow* parent, wxWindowID id, wxPoint pos, int type, RenderSize sz, int sprite_id);
40+ virtual ~DCButton();
41+
42+ void SetValue(bool val);
43+ bool GetValue() const;
44+
45+ void SetSprite(int id);
46+
47+ void OnPaint(wxPaintEvent&);
48+ void OnClick(wxMouseEvent&);
49+
50+protected:
51+ void SetOverlay(Sprite* espr);
52+
53+ int type;
54+ bool state; // pressed/unpressed
55+ RenderSize size;
56+ Sprite* sprite;
57+ Sprite* overlay;
58+
59+ DECLARE_DYNAMIC_CLASS(DCButton)
60+ DECLARE_EVENT_TABLE()
61+};
62+
63+#endif
A RD_Map_Editor/source/definitions.h +177-0 View file
@@ -0,0 +1,177 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor 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 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_DEFINITIONS_H_
19+#define RME_DEFINITIONS_H_
20+
21+#define __W_RME_APPLICATION_NAME__ wxString("OTARME RD - RD Map Editor")
22+#define __RME_APPLICATION_NAME__ std::string("OTARME_RD")
23+
24+// Version info
25+// xxyyzzt (major, minor, subversion)
26+#define __RME_VERSION_MAJOR__ 6
27+#define __RME_VERSION_MINOR__ 8
28+#define __RME_SUBVERSION__ 2
29+
30+
31+#define __LIVE_NET_VERSION__ 5
32+
33+#define MAKE_VERSION_ID(major, minor, subversion) \
34+ ((major) * 10000000 + (minor) * 100000 + (subversion) * 1000)
35+
36+#define __RME_VERSION_ID__ MAKE_VERSION_ID( \
37+ __RME_VERSION_MAJOR__, \
38+ __RME_VERSION_MINOR__, \
39+ __RME_SUBVERSION__ \
40+)
41+
42+#define __SITE_URL__ "https://opengamescommunity.com"
43+
44+// #define __PRERELEASE__ 1
45+
46+#ifdef __EXPERIMENTAL__
47+ #define __RME_VERSION__ std::string(i2s(__RME_VERSION_MAJOR__) + "." + i2s(__RME_VERSION_MINOR__) + "." + i2s(__RME_SUBVERSION__) + " BETA")
48+ #define __W_RME_VERSION__ (wxString() << __RME_VERSION_MAJOR__ << "." << __RME_VERSION_MINOR__ << "." << __RME_SUBVERSION__ << " BETA")
49+#elif __SNAPSHOT__
50+ #define __RME_VERSION__ std::string(i2s(__RME_VERSION_MAJOR__) + "." + i2s(__RME_VERSION_MINOR__) + "." + i2s(__RME_SUBVERSION__) + " - SNAPSHOT")
51+ #define __W_RME_VERSION__ (wxString() << __RME_VERSION_MAJOR__ << "." << __RME_VERSION_MINOR__ << "." << __RME_SUBVERSION__ << " - SNAPSHOT")
52+#elif __PRERELEASE__
53+ #define __RME_VERSION__ std::string(i2s(__RME_VERSION_MAJOR__) + "." + i2s(__RME_VERSION_MINOR__) + "." + i2s(__RME_SUBVERSION__) + " (Pre-release)")
54+ #define __W_RME_VERSION__ (wxString() << __RME_VERSION_MAJOR__ << "." << __RME_VERSION_MINOR__ << "." << __RME_SUBVERSION__ << " (Pre-release)")
55+#else
56+ #define __RME_VERSION__ std::string(i2s(__RME_VERSION_MAJOR__) + "." + i2s(__RME_VERSION_MINOR__) + "." + i2s(__RME_SUBVERSION__))
57+ #define __W_RME_VERSION__ (wxString() << __RME_VERSION_MAJOR__ << "." << __RME_VERSION_MINOR__ << "." << __RME_SUBVERSION__)
58+#endif
59+// OS
60+
61+#define OTGZ_SUPPORT 1
62+#define ASSETS_NAME "Tibia"
63+
64+#ifdef __VISUALC__
65+ #pragma warning(disable : 4996) // Stupid MSVC complaining 'bout "unsafe" functions
66+ #pragma warning(disable : 4800) // Bool conversion warning
67+ #pragma warning(disable : 4100) // Unused parameter warning ( I like to name unused stuff... )
68+ #pragma warning(disable : 4706) // Assignment within conditional expression
69+#endif
70+
71+#ifndef FORCEINLINE
72+ #ifdef __VISUALC__
73+ #define FORCEINLINE __forceinline
74+ #else
75+ #define FORCEINLINE inline
76+ #endif
77+#endif
78+
79+// Debug mode?
80+#if defined __DEBUG__ || defined _DEBUG || defined __DEBUG_MODE__
81+ #undef __DEBUG_MODE__
82+ #define __DEBUG_MODE__ 1
83+ #undef _DEBUG
84+ #define _DEBUG 1
85+ #undef __DEBUG__
86+ #define __DEBUG__ 1
87+#else
88+ #ifndef __RELEASE__
89+ #define __RELEASE__ 1
90+ #endif
91+ #ifndef NDEBUG
92+ #define NDEBUG 1
93+ #endif
94+#endif
95+
96+#ifdef __RELEASE__
97+ #ifdef __VISUALC__
98+ #define _SCL_SECURE 0
99+ #define _SECURE_SCL 0 // They can't even decide on a coherent define interface!
100+ #define _HAS_ITERATOR_DEBUGGING 0
101+ #endif
102+#endif
103+
104+#ifndef _DONT_USE_UPDATER_
105+ #if defined __WINDOWS__ && !defined _USE_UPDATER_
106+ #define _USE_UPDATER_
107+ #endif
108+#endif
109+
110+#ifndef _DONT_USE_PROCESS_COM
111+ #if defined __WINDOWS__ && !defined _USE_PROCESS_COM
112+ #define _USE_PROCESS_COM
113+ #endif
114+#endif
115+
116+// Mathematical constants
117+#define PI 3.14159265358979323846264338327950288419716939937510
118+#define DEG2RAD (PI / 180.0)
119+#define RAD2DEG (180.0 / DEG)
120+
121+// The height of the map (there should be more checks for this...)
122+#define MAP_LAYERS 16
123+
124+#define MAP_MAX_WIDTH 65000
125+#define MAP_MAX_HEIGHT 65000
126+#define MAP_MAX_LAYER 15
127+
128+// The size of the tile in pixels
129+constexpr int TileSize = 32;
130+
131+// The default size of sprites
132+#define SPRITE_PIXELS 32
133+#define SPRITE_PIXELS_SIZE SPRITE_PIXELS* SPRITE_PIXELS
134+
135+// The sea layer
136+#define GROUND_LAYER 7
137+
138+constexpr int ClientMapWidth = 17;
139+constexpr int ClientMapHeight = 13;
140+
141+#define MAP_LOAD_FILE_WILDCARD_OTGZ "OpenTibia Binary Map (*.otbm;*.otgz)|*.otbm;*.otgz"
142+#define MAP_SAVE_FILE_WILDCARD_OTGZ "OpenTibia Binary Map (*.otbm)|*.otbm|Compressed OpenTibia Binary Map (*.otgz)|*.otgz"
143+
144+#define MAP_LOAD_FILE_WILDCARD "OpenTibia Binary Map (*.otbm)|*.otbm"
145+#define MAP_SAVE_FILE_WILDCARD "OpenTibia Binary Map (*.otbm)|*.otbm"
146+
147+// Lights
148+constexpr int MaxLightIntensity = 8;
149+constexpr int PixelFormatRGB = 3;
150+constexpr int PixelFormatRGBA = 4;
151+
152+// wxString conversions
153+#define nstr(str) std::string((const char*)(str.mb_str(wxConvUTF8)))
154+#define wxstr(str) wxString((str).c_str(), wxConvUTF8)
155+
156+// increment & decrement definitions
157+#define IMPLEMENT_INCREMENT_OP(Type) \
158+ namespace { \
159+ Type& operator++(Type& type) { \
160+ return (type = static_cast<Type>(type + 1)); \
161+ } \
162+ Type operator++(Type& type, int) { \
163+ return static_cast<Type>((++type) - 1); \
164+ } \
165+ }
166+
167+#define IMPLEMENT_DECREMENT_OP(Type) \
168+ namespace { \
169+ Type& operator--(Type& type) { \
170+ return (type = static_cast<Type>(type - 1)); \
171+ } \
172+ Type operator--(Type& type, int) { \
173+ return static_cast<Type>((--type) + 1); \
174+ } \
175+ }
176+
177+#endif
A RD_Map_Editor/source/definitions.hpp +1-0 View file
@@ -0,0 +1,1 @@
1+
Top