tileset.cpp

main 274 lines · 8.2 KB Raw
Alex Alex Commit Map Editor 18/10/2026 23:40
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 "tileset.h"
21#include "creatures.h"
22#include "creature_brush.h"
23#include "items.h"
24#include "raw_brush.h"
25
26Tileset::Tileset(Brushes& brushes, const std::string& name) :
27 name(name),
28 brushes(brushes) {
29 ////
30}
31
32Tileset::~Tileset() {
33 for (TilesetCategoryArray::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
34 delete *iter;
35 }
36}
37
38void Tileset::clear() {
39 for (TilesetCategoryArray::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
40 (*iter)->brushlist.clear();
41 }
42}
43
44bool Tileset::containsBrush(Brush* brush) const {
45 for (TilesetCategoryArray::const_iterator iter = categories.begin(); iter != categories.end(); ++iter) {
46 if ((*iter)->containsBrush(brush)) {
47 return true;
48 }
49 }
50
51 return false;
52}
53
54TilesetCategory* Tileset::getCategory(TilesetCategoryType type) {
55 ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
56 for (TilesetCategoryArray::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
57 if ((*iter)->getType() == type) {
58 return *iter;
59 }
60 }
61 TilesetCategory* tsc = newd TilesetCategory(*this, type);
62 categories.push_back(tsc);
63 return tsc;
64}
65
66bool TilesetCategory::containsBrush(Brush* brush) const {
67 for (std::vector<Brush*>::const_iterator iter = brushlist.begin(); iter != brushlist.end(); ++iter) {
68 if (*iter == brush) {
69 return true;
70 }
71 }
72
73 return false;
74}
75
76const TilesetCategory* Tileset::getCategory(TilesetCategoryType type) const {
77 ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
78 for (TilesetCategoryArray::const_iterator iter = categories.begin(); iter != categories.end(); ++iter) {
79 if ((*iter)->getType() == type) {
80 return *iter;
81 }
82 }
83 return nullptr;
84}
85
86void Tileset::loadCategory(pugi::xml_node node, wxArrayString& warnings) {
87 TilesetCategory* category = nullptr;
88 TilesetCategory* subCategory = nullptr;
89
90 const std::string& nodeName = as_lower_str(node.name());
91 if (nodeName == "terrain") {
92 category = getCategory(TILESET_TERRAIN);
93 } else if (nodeName == "collections") {
94 category = getCategory(TILESET_COLLECTION);
95 } else if (nodeName == "doodad") {
96 category = getCategory(TILESET_DOODAD);
97 } else if (nodeName == "items") {
98 category = getCategory(TILESET_ITEM);
99 } else if (nodeName == "raw") {
100 category = getCategory(TILESET_RAW);
101 } else if (nodeName == "terrain_and_raw") {
102 category = getCategory(TILESET_TERRAIN);
103 subCategory = getCategory(TILESET_RAW);
104 } else if (nodeName == "collections_and_raw") {
105 category = getCategory(TILESET_COLLECTION);
106 subCategory = getCategory(TILESET_RAW);
107 } else if (nodeName == "collections_and_terrain") {
108 category = getCategory(TILESET_COLLECTION);
109 subCategory = getCategory(TILESET_TERRAIN);
110 } else if (nodeName == "doodad_and_raw") {
111 category = getCategory(TILESET_DOODAD);
112 subCategory = getCategory(TILESET_RAW);
113 } else if (nodeName == "items_and_raw") {
114 category = getCategory(TILESET_ITEM);
115 subCategory = getCategory(TILESET_RAW);
116 } else if (nodeName == "creatures") {
117 category = getCategory(TILESET_CREATURE);
118 for (pugi::xml_node brushNode = node.first_child(); brushNode; brushNode = brushNode.next_sibling()) {
119 const std::string& brushName = as_lower_str(brushNode.name());
120 if (brushName != "creature") {
121 continue;
122 }
123
124 pugi::xml_attribute attribute;
125 if (!(attribute = brushNode.attribute("name"))) {
126 warnings.push_back("Couldn't read creature name tag of creature tileset");
127 continue;
128 }
129
130 const std::string& creatureName = attribute.as_string();
131 CreatureType* ctype = g_creatures[creatureName];
132 if (ctype) {
133 CreatureBrush* brush;
134 if (ctype->brush) {
135 brush = ctype->brush;
136 } else {
137 brush = ctype->brush = newd CreatureBrush(ctype);
138 brushes.addBrush(brush);
139 }
140 brush->flagAsVisible();
141 category->brushlist.push_back(brush);
142 } else {
143 warnings.push_back(wxString("Unknown creature type \"") << wxstr(creatureName) << "\"");
144 }
145 }
146 }
147
148 if (!category) {
149 return;
150 }
151
152 for (pugi::xml_node brushNode = node.first_child(); brushNode; brushNode = brushNode.next_sibling()) {
153 category->loadBrush(brushNode, warnings);
154 if (subCategory) {
155 subCategory->loadBrush(brushNode, warnings);
156 }
157 }
158}
159
160//
161
162TilesetCategory::TilesetCategory(Tileset& parent, TilesetCategoryType type) :
163 type(type), tileset(parent) {
164 ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
165}
166
167TilesetCategory::~TilesetCategory() {
168 ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
169}
170
171bool TilesetCategory::isTrivial() const {
172 return (type == TILESET_ITEM) || (type == TILESET_RAW);
173}
174
175void TilesetCategory::loadBrush(pugi::xml_node node, wxArrayString& warnings) {
176 pugi::xml_attribute attribute;
177
178 std::string brushName = node.attribute("after").as_string();
179 if ((attribute = node.attribute("afteritem"))) {
180 ItemType& it = g_items[attribute.as_ushort()];
181 if (it.id != 0) {
182 brushName = it.raw_brush ? it.raw_brush->getName() : std::string();
183 }
184 }
185
186 const std::string& nodeName = as_lower_str(node.name());
187 if (nodeName == "brush") {
188 if (!(attribute = node.attribute("name"))) {
189 return;
190 }
191
192 Brush* brush = tileset.brushes.getBrush(attribute.as_string());
193 if (brush) {
194 auto insertPosition = brushlist.end();
195 if (!brushName.empty()) {
196 for (auto itt = brushlist.begin(); itt != brushlist.end(); ++itt) {
197 if ((*itt)->getName() == brushName) {
198 insertPosition = ++itt;
199 break;
200 }
201 }
202 }
203 brush->flagAsVisible();
204 brushlist.insert(insertPosition, brush);
205
206 if (type == TILESET_COLLECTION) {
207 brush->setCollection();
208 }
209 } else {
210 warnings.push_back("Brush \"" + wxString(attribute.as_string(), wxConvUTF8) + "\" doesn't exist.");
211 }
212 } else if (nodeName == "item") {
213 uint16_t fromId = 0, toId = 0;
214 if (!(attribute = node.attribute("id"))) {
215 if (!(attribute = node.attribute("fromid"))) {
216 warnings.push_back("Couldn't read raw ids.");
217 }
218 toId = node.attribute("toid").as_ushort();
219 }
220
221 fromId = attribute.as_ushort();
222 toId = std::max<uint16_t>(fromId, toId);
223
224 std::vector<Brush*> tempBrushVector;
225 for (uint16_t id = fromId; id <= toId; ++id) {
226 ItemType& it = g_items[id];
227 if (it.id == 0) {
228 warnings.push_back(wxString::Format("Tileset: %s, Brush: %s, Previous %d, From: %d, To: %d", wxstr(tileset.name), wxstr(brushName), tileset.previousId, fromId, toId));
229 warnings.push_back("Unknown item id #" + std::to_string(id) + ".");
230 continue;
231 }
232
233 RAWBrush* brush;
234 if (it.raw_brush) {
235 brush = it.raw_brush;
236 if (type == TILESET_COLLECTION) {
237 it.raw_brush->setCollection();
238 }
239 } else {
240 brush = it.raw_brush = newd RAWBrush(it.id);
241 it.has_raw = true;
242 if (type == TILESET_COLLECTION) {
243 it.raw_brush->setCollection();
244 }
245 tileset.brushes.addBrush(brush); // This will take care of cleaning up afterwards
246 }
247
248 if (type == TILESET_COLLECTION) {
249 it.collection_brush = brush;
250 }
251
252 if (it.doodad_brush == nullptr && !isTrivial()) {
253 it.doodad_brush = brush;
254 }
255
256 brush->flagAsVisible();
257 tempBrushVector.push_back(brush);
258
259 tileset.previousId = id;
260 }
261
262 auto insertPosition = brushlist.end();
263 if (!brushName.empty()) {
264 for (auto itt = brushlist.begin(); itt != brushlist.end(); ++itt) {
265 if ((*itt)->getName() == brushName) {
266 insertPosition = ++itt;
267 break;
268 }
269 }
270 }
271 brushlist.insert(insertPosition, tempBrushVector.begin(), tempBrushVector.end());
272 }
273}
274
Top