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/iomap_otmm.h +85-0 View file
@@ -0,0 +1,85 @@
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_OTMM_IOMAP_H_
19+#define RME_OTMM_IOMAP_H_
20+
21+#include "iomap.h"
22+
23+#pragma pack(1)
24+
25+enum OTMM_VERSION {
26+ OTMM_VERSION_1,
27+};
28+
29+enum OTMM_TileAttributes {
30+ OTMM_ATTR_TILE_FLAGS = 1,
31+};
32+
33+enum OTMM_ItemAttribute {
34+ OTMM_ATTR_DESCRIPTION = 1,
35+ OTMM_ATTR_ACTION_ID = 2,
36+ OTMM_ATTR_UNIQUE_ID = 3,
37+ OTMM_ATTR_TEXT = 4,
38+ OTMM_ATTR_DESC = 5,
39+ OTMM_ATTR_TELE_DEST = 6,
40+ OTMM_ATTR_ITEM = 7,
41+ OTMM_ATTR_SUBTYPE = 8,
42+ OTMM_ATTR_DEPOT_ID = 9,
43+ OTMM_ATTR_DOOR_ID = 10,
44+ OTMM_ATTR_DURATION = 11,
45+};
46+
47+enum OTMM_NodeTypes {
48+ OTMM_ROOT = 1,
49+ OTMM_MAP_DATA = 2,
50+ OTMM_TILE_DATA = 3,
51+ OTMM_TILE = 4,
52+ OTMM_HOUSETILE = 5,
53+ OTMM_ITEM = 6,
54+ OTMM_SPAWN_DATA = 7,
55+ OTMM_SPAWN_AREA = 8,
56+ OTMM_MONSTER = 9,
57+ OTMM_NPC = 10,
58+ OTMM_TOWN_DATA = 11,
59+ OTMM_TOWN = 12,
60+ OTMM_HOUSE_DATA = 13,
61+ OTMM_HOUSE = 14,
62+ OTMM_DESCRIPTION = 15,
63+ OTMM_EDITOR = 16,
64+};
65+
66+#pragma pack()
67+
68+class NodeFileReadHandle;
69+class NodeFileWriteHandle;
70+
71+class IOMapOTMM : public IOMap {
72+public:
73+ IOMapOTMM();
74+ ~IOMapOTMM();
75+
76+ virtual MapVersion getVersionInfo(const FileName& identifier);
77+
78+ virtual bool loadMap(Map& map, NodeFileReadHandle& handle, const FileName& identifier, bool showdialog);
79+ virtual bool loadMap(Map& map, const FileName& identifier, bool showdialog);
80+
81+ virtual bool saveMap(Map& map, NodeFileWriteHandle& handle, const FileName& identifier, bool showdialog);
82+ virtual bool saveMap(Map& map, const FileName& identifier, bool showdialog);
83+};
84+
85+#endif
A RD_Map_Editor/source/island_generator_dialog.h +143-0 View file
@@ -0,0 +1,143 @@
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_ISLAND_GENERATOR_DIALOG_H_
19+#define RME_ISLAND_GENERATOR_DIALOG_H_
20+
21+#include "main.h"
22+#include "common_windows.h"
23+#include "dcbutton.h"
24+#include "editor.h"
25+#include "brush.h"
26+#include "ground_brush.h"
27+
28+// Event IDs
29+enum {
30+ ID_ISLAND_GENERATE_SINGLE = 34000,
31+ ID_ISLAND_GENERATE_MULTIPLE,
32+ ID_ISLAND_CANCEL,
33+ ID_ISLAND_RANDOM_SEED,
34+ ID_ISLAND_SHAPE_SELECT,
35+ ID_ISLAND_SIZE_CHANGE,
36+ ID_ISLAND_ROUGHNESS_CHANGE,
37+ ID_ISLAND_SEED_TEXT,
38+ ID_ISLAND_BORDER_SELECT,
39+ ID_ISLAND_BORDER_PREVIEW
40+};
41+
42+class IslandPreviewButton : public DCButton {
43+public:
44+ IslandPreviewButton(wxWindow* parent);
45+ ~IslandPreviewButton() { }
46+
47+ uint16_t GetItemId() const { return m_id; }
48+ void SetItemId(uint16_t id);
49+
50+private:
51+ uint16_t m_id;
52+};
53+
54+class IslandGeneratorDialog : public wxDialog {
55+public:
56+ IslandGeneratorDialog(wxWindow* parent);
57+ ~IslandGeneratorDialog();
58+
59+ void SetStartPosition(const Position& pos) {
60+ start_position = pos;
61+ pos_x_spin->SetValue(pos.x);
62+ pos_y_spin->SetValue(pos.y);
63+ pos_z_spin->SetValue(pos.z);
64+ }
65+
66+ // UI Event Handlers
67+ void OnGroundClick(wxMouseEvent& event);
68+ void OnWaterClick(wxMouseEvent& event);
69+ void OnGenerateClick(wxCommandEvent& event);
70+ void OnCancelClick(wxCommandEvent& event);
71+ void OnShapeSelect(wxCommandEvent& event);
72+ void OnSeedText(wxCommandEvent& event);
73+ void OnSizeChange(wxSpinEvent& event);
74+ void OnRoughnessChange(wxSpinEvent& event);
75+ void OnRandomizeSeed(wxCommandEvent& event);
76+ void OnPreviewUpdate(wxCommandEvent& event);
77+ void OnGenerateMultiple(wxCommandEvent& event);
78+ void OnBorderSelect(wxCommandEvent& event);
79+ void OnBorderPreview(wxCommandEvent& event);
80+
81+private:
82+ void UpdateWidgets();
83+ void UpdatePreview();
84+ void GenerateIsland();
85+ void GenerateMultipleIslands(int count, int spacing);
86+ wxString GetDataDirectoryForVersion(const wxString& versionStr);
87+ std::vector<std::pair<uint16_t, uint16_t>> ParseRangeString(const wxString& input);
88+ void OnIdInput(wxCommandEvent& event);
89+ void LoadBorderChoices();
90+ void UpdateBorderPreview();
91+
92+ struct BorderData {
93+ wxString name;
94+ int id;
95+ std::vector<uint16_t> items;
96+ wxBitmap preview;
97+ };
98+
99+ // UI Controls
100+ IslandPreviewButton* ground_button;
101+ IslandPreviewButton* water_button;
102+ wxTextCtrl* ground_range_input;
103+ wxTextCtrl* water_range_input;
104+ wxChoice* shape_choice;
105+ wxSpinCtrl* size_spin;
106+ wxSpinCtrl* roughness_spin;
107+ wxTextCtrl* seed_input;
108+ wxButton* random_seed_button;
109+ wxButton* generate_button;
110+ wxButton* generate_multiple_button;
111+ wxButton* cancel_button;
112+ wxGauge* progress;
113+ wxStaticBitmap* preview_bitmap;
114+ wxCheckBox* use_automagic;
115+
116+ // Border controls
117+ wxListBox* border_list;
118+ wxStaticBitmap* border_preview;
119+ std::vector<BorderData> border_data;
120+ int selected_border_id;
121+
122+ // Position controls
123+ wxSpinCtrl* pos_x_spin;
124+ wxSpinCtrl* pos_y_spin;
125+ wxSpinCtrl* pos_z_spin;
126+
127+ // Multiple islands controls
128+ wxSpinCtrl* islands_count_spin;
129+ wxSpinCtrl* islands_spacing_spin;
130+
131+ // Generation parameters
132+ uint16_t ground_id;
133+ uint16_t water_id;
134+ int island_size;
135+ int roughness;
136+ wxString seed;
137+ wxString selected_shape;
138+ Position start_position;
139+
140+ DECLARE_EVENT_TABLE()
141+};
142+
143+#endif // RME_ISLAND_GENERATOR_DIALOG_H_
A RD_Map_Editor/source/item.cpp +562-0 View file
@@ -0,0 +1,562 @@
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 "brush.h"
21+#include "graphics.h"
22+#include "gui.h"
23+#include "tile.h"
24+#include "complexitem.h"
25+#include "iomap.h"
26+#include "item.h"
27+
28+#include "ground_brush.h"
29+#include "carpet_brush.h"
30+#include "table_brush.h"
31+#include "wall_brush.h"
32+
33+Item* Item::Create(uint16_t _type, uint16_t _subtype /*= 0xFFFF*/) {
34+ if (_type == 0) {
35+ return nullptr;
36+ }
37+ Item* newItem = nullptr;
38+
39+ const ItemType& it = g_items[_type];
40+
41+ if (it.id != 0) {
42+ if (it.isDepot()) {
43+ newItem = newd Depot(_type);
44+ } else if (it.isContainer()) {
45+ newItem = newd Container(_type);
46+ } else if (it.isTeleport()) {
47+ newItem = newd Teleport(_type);
48+ } else if (it.isDoor()) {
49+ newItem = newd Door(_type);
50+ } else if (it.isPodium()) {
51+ newItem = newd Podium(_type);
52+ } else if (_subtype == 0xFFFF) {
53+ if (it.isFluidContainer()) {
54+ newItem = newd Item(_type, LIQUID_NONE);
55+ } else if (it.isSplash()) {
56+ newItem = newd Item(_type, LIQUID_WATER);
57+ } else if (it.charges > 0) {
58+ newItem = newd Item(_type, it.charges);
59+ } else {
60+ newItem = newd Item(_type, 1);
61+ }
62+ } else {
63+ newItem = newd Item(_type, _subtype);
64+ }
65+ } else {
66+ newItem = newd Item(_type, _subtype);
67+ }
68+
69+ return newItem;
70+}
71+
72+Item::Item(unsigned short _type, unsigned short _count) :
73+ id(_type),
74+ subtype(1),
75+ selected(false),
76+ frame(0) {
77+ if (hasSubtype()) {
78+ subtype = _count;
79+ }
80+}
81+
82+Item::~Item() {
83+ ////
84+}
85+
86+Item* Item::deepCopy() const {
87+ Item* copy = Create(id, subtype);
88+ if (copy) {
89+ copy->selected = selected;
90+ if (attributes) {
91+ copy->attributes = newd ItemAttributeMap(*attributes);
92+ }
93+ }
94+ return copy;
95+}
96+
97+Item* transformItem(Item* old_item, uint16_t new_id, Tile* parent) {
98+ if (old_item == nullptr) {
99+ return nullptr;
100+ }
101+
102+ old_item->setID(new_id);
103+ // Through the magic of deepCopy, this will now be a pointer to an item of the correct type.
104+ Item* new_item = old_item->deepCopy();
105+ if (parent) {
106+ // Find the old item and remove it from the tile, insert this one instead!
107+ if (old_item == parent->ground) {
108+ delete old_item;
109+ parent->ground = new_item;
110+ return new_item;
111+ }
112+
113+ std::queue<Container*> containers;
114+ for (ItemVector::iterator item_iter = parent->items.begin(); item_iter != parent->items.end(); ++item_iter) {
115+ if (*item_iter == old_item) {
116+ delete old_item;
117+ item_iter = parent->items.erase(item_iter);
118+ parent->items.insert(item_iter, new_item);
119+ return new_item;
120+ }
121+
122+ Container* c = dynamic_cast<Container*>(*item_iter);
123+ if (c) {
124+ containers.push(c);
125+ }
126+ }
127+
128+ while (containers.size() != 0) {
129+ Container* container = containers.front();
130+ ItemVector& v = container->getVector();
131+ for (ItemVector::iterator item_iter = v.begin(); item_iter != v.end(); ++item_iter) {
132+ Item* i = *item_iter;
133+ Container* c = dynamic_cast<Container*>(i);
134+ if (c) {
135+ containers.push(c);
136+ }
137+
138+ if (i == old_item) {
139+ // Found it!
140+ item_iter = v.erase(item_iter);
141+ v.insert(item_iter, new_item);
142+ return new_item;
143+ }
144+ }
145+ containers.pop();
146+ }
147+ }
148+
149+ delete new_item;
150+ return nullptr;
151+}
152+
153+uint32_t Item::memsize() const {
154+ uint32_t mem = sizeof(*this);
155+ return mem;
156+}
157+
158+void Item::setID(uint16_t newid) {
159+ id = newid;
160+}
161+
162+void Item::setSubtype(uint16_t n) {
163+ subtype = n;
164+}
165+
166+bool Item::hasSubtype() const {
167+ const ItemType& it = g_items[id];
168+ return (it.isFluidContainer() || it.isSplash() || isCharged() || it.stackable || it.charges != 0);
169+}
170+
171+uint16_t Item::getSubtype() const {
172+ if (hasSubtype()) {
173+ return subtype;
174+ }
175+ return 0;
176+}
177+
178+bool Item::hasProperty(enum ITEMPROPERTY prop) const {
179+ const ItemType& it = g_items[id];
180+ switch (prop) {
181+ case BLOCKSOLID:
182+ if (it.unpassable) {
183+ return true;
184+ }
185+ break;
186+
187+ case MOVEABLE:
188+ if (it.moveable && getUniqueID() == 0) {
189+ return true;
190+ }
191+ break;
192+ /*
193+ case HASHEIGHT:
194+ if(it.height != 0 )
195+ return true;
196+ break;
197+ */
198+ case BLOCKPROJECTILE:
199+ if (it.blockMissiles) {
200+ return true;
201+ }
202+ break;
203+
204+ case BLOCKPATHFIND:
205+ if (it.blockPathfinder) {
206+ return true;
207+ }
208+ break;
209+
210+ case HOOK_SOUTH:
211+ if (it.hookSouth) {
212+ return true;
213+ }
214+ break;
215+
216+ case HOOK_EAST:
217+ if (it.hookEast) {
218+ return true;
219+ }
220+ break;
221+
222+ case BLOCKINGANDNOTMOVEABLE:
223+ if (it.unpassable && (!it.moveable || getUniqueID() != 0)) {
224+ return true;
225+ }
226+ break;
227+
228+ case HASLIGHT:
229+ if (hasLight()) {
230+ return true;
231+ }
232+ break;
233+
234+ default:
235+ return false;
236+ }
237+ return false;
238+}
239+
240+std::pair<int, int> Item::getDrawOffset() const {
241+ ItemType& it = g_items[id];
242+ if (it.sprite != nullptr) {
243+ return it.sprite->getDrawOffset();
244+ }
245+ return std::make_pair(0, 0);
246+}
247+
248+bool Item::hasLight() const {
249+ const ItemType& type = g_items.getItemType(id);
250+ if (type.sprite) {
251+ return type.sprite->hasLight();
252+ }
253+ return false;
254+}
255+
256+SpriteLight Item::getLight() const {
257+ const ItemType& type = g_items.getItemType(id);
258+ if (type.sprite) {
259+ return type.sprite->getLight();
260+ }
261+ return SpriteLight { 0, 0 };
262+}
263+
264+double Item::getWeight() const {
265+ ItemType& it = g_items[id];
266+ if (it.stackable) {
267+ return it.weight * std::max(1, (int)subtype);
268+ }
269+
270+ return it.weight;
271+}
272+
273+void Item::setUniqueID(unsigned short n) {
274+ setAttribute("uid", n);
275+}
276+
277+void Item::setActionID(unsigned short n) {
278+ setAttribute("aid", n);
279+}
280+
281+void Item::setText(const std::string& str) {
282+ setAttribute("text", str);
283+}
284+
285+void Item::setDescription(const std::string& str) {
286+ setAttribute("desc", str);
287+}
288+
289+void Item::setTier(unsigned short n) {
290+ setAttribute("tier", n);
291+}
292+
293+double Item::getWeight() {
294+ ItemType& it = g_items[id];
295+ if (it.isStackable()) {
296+ return it.weight * subtype;
297+ }
298+ return it.weight;
299+}
300+
301+bool Item::canHoldText() const {
302+ return isReadable() || canWriteText();
303+}
304+
305+bool Item::canHoldDescription() const {
306+ return g_items[id].allowDistRead;
307+}
308+
309+uint8_t Item::getMiniMapColor() const {
310+ GameSprite* spr = g_items[id].sprite;
311+ if (spr) {
312+ return spr->getMiniMapColor();
313+ }
314+ return 0;
315+}
316+
317+GroundBrush* Item::getGroundBrush() const {
318+ ItemType& item_type = g_items.getItemType(id);
319+ if (item_type.isGroundTile() && item_type.brush && item_type.brush->isGround()) {
320+ return item_type.brush->asGround();
321+ }
322+ return nullptr;
323+}
324+
325+TableBrush* Item::getTableBrush() const {
326+ ItemType& item_type = g_items.getItemType(id);
327+ if (item_type.isTable && item_type.brush && item_type.brush->isTable()) {
328+ return item_type.brush->asTable();
329+ }
330+ return nullptr;
331+}
332+
333+CarpetBrush* Item::getCarpetBrush() const {
334+ ItemType& item_type = g_items.getItemType(id);
335+ if (item_type.isCarpet && item_type.brush && item_type.brush->isCarpet()) {
336+ return item_type.brush->asCarpet();
337+ }
338+ return nullptr;
339+}
340+
341+DoorBrush* Item::getDoorBrush() const {
342+ ItemType& item_type = g_items.getItemType(id);
343+ if (!item_type.isWall || !item_type.isBrushDoor || !item_type.brush || !item_type.brush->isWall()) {
344+ return nullptr;
345+ }
346+
347+ DoorType door_type = item_type.brush->asWall()->getDoorTypeFromID(id);
348+ DoorBrush* door_brush = nullptr;
349+ // Quite a horrible dependency on a global here, meh.
350+ switch (door_type) {
351+ case WALL_DOOR_NORMAL: {
352+ door_brush = g_gui.normal_door_brush;
353+ break;
354+ }
355+ case WALL_DOOR_LOCKED: {
356+ door_brush = g_gui.locked_door_brush;
357+ break;
358+ }
359+ case WALL_DOOR_QUEST: {
360+ door_brush = g_gui.quest_door_brush;
361+ break;
362+ }
363+ case WALL_DOOR_MAGIC: {
364+ door_brush = g_gui.magic_door_brush;
365+ break;
366+ }
367+ case WALL_DOOR_NORMAL_ALT: {
368+ door_brush = g_gui.normal_door_alt_brush;
369+ break;
370+ }
371+ case WALL_ARCHWAY: {
372+ door_brush = g_gui.archway_door_brush;
373+ break;
374+ }
375+ case WALL_WINDOW: {
376+ door_brush = g_gui.window_door_brush;
377+ break;
378+ }
379+ case WALL_HATCH_WINDOW: {
380+ door_brush = g_gui.hatch_door_brush;
381+ break;
382+ }
383+ default: {
384+ break;
385+ }
386+ }
387+ return door_brush;
388+}
389+
390+WallBrush* Item::getWallBrush() const {
391+ ItemType& item_type = g_items.getItemType(id);
392+ if (item_type.isWall && item_type.brush && item_type.brush->isWall()) {
393+ return item_type.brush->asWall();
394+ }
395+ return nullptr;
396+}
397+
398+BorderType Item::getWallAlignment() const {
399+ ItemType& it = g_items[id];
400+ if (!it.isWall) {
401+ return BORDER_NONE;
402+ }
403+ return it.border_alignment;
404+}
405+
406+BorderType Item::getBorderAlignment() const {
407+ ItemType& it = g_items[id];
408+ return it.border_alignment;
409+}
410+
411+void Item::animate() {
412+ ItemType& type = g_items[id];
413+ GameSprite* sprite = type.sprite;
414+ if (!sprite || !sprite->animator) {
415+ return;
416+ }
417+
418+ frame = sprite->animator->getFrame();
419+}
420+
421+// ============================================================================
422+// Static conversions
423+
424+std::string Item::LiquidID2Name(uint16_t id) {
425+ switch (id) {
426+ case LIQUID_NONE:
427+ return "None";
428+ case LIQUID_WATER:
429+ return "Water";
430+ case LIQUID_BLOOD:
431+ return "Blood";
432+ case LIQUID_BEER:
433+ return "Beer";
434+ case LIQUID_SLIME:
435+ return "Slime";
436+ case LIQUID_LEMONADE:
437+ return "Lemonade";
438+ case LIQUID_MILK:
439+ return "Milk";
440+ case LIQUID_MANAFLUID:
441+ return "Manafluid";
442+ case LIQUID_WATER2:
443+ return "Water";
444+ case LIQUID_LIFEFLUID:
445+ return "Lifefluid";
446+ case LIQUID_OIL:
447+ return "Oil";
448+ case LIQUID_SLIME2:
449+ return "Slime";
450+ case LIQUID_URINE:
451+ return "Urine";
452+ case LIQUID_COCONUT_MILK:
453+ return "Coconut Milk";
454+ case LIQUID_WINE:
455+ return "Wine";
456+ case LIQUID_MUD:
457+ return "Mud";
458+ case LIQUID_FRUIT_JUICE:
459+ return "Fruit Juice";
460+ case LIQUID_LAVA:
461+ return "Lava";
462+ case LIQUID_RUM:
463+ return "Rum";
464+ case LIQUID_SWAMP:
465+ return "Swamp";
466+ case LIQUID_INK:
467+ return "Ink";
468+ case LIQUID_TEA:
469+ return "Tea";
470+ case LIQUID_MEAD:
471+ return "Mead";
472+ default:
473+ return "Unknown";
474+ }
475+}
476+
477+uint16_t Item::LiquidName2ID(std::string liquid) {
478+ to_lower_str(liquid);
479+ if (liquid == "none") {
480+ return LIQUID_NONE;
481+ }
482+ if (liquid == "water") {
483+ return LIQUID_WATER;
484+ }
485+ if (liquid == "blood") {
486+ return LIQUID_BLOOD;
487+ }
488+ if (liquid == "beer") {
489+ return LIQUID_BEER;
490+ }
491+ if (liquid == "slime") {
492+ return LIQUID_SLIME;
493+ }
494+ if (liquid == "lemonade") {
495+ return LIQUID_LEMONADE;
496+ }
497+ if (liquid == "milk") {
498+ return LIQUID_MILK;
499+ }
500+ if (liquid == "manafluid") {
501+ return LIQUID_MANAFLUID;
502+ }
503+ if (liquid == "lifefluid") {
504+ return LIQUID_LIFEFLUID;
505+ }
506+ if (liquid == "oil") {
507+ return LIQUID_OIL;
508+ }
509+ if (liquid == "urine") {
510+ return LIQUID_URINE;
511+ }
512+ if (liquid == "coconut milk") {
513+ return LIQUID_COCONUT_MILK;
514+ }
515+ if (liquid == "wine") {
516+ return LIQUID_WINE;
517+ }
518+ if (liquid == "mud") {
519+ return LIQUID_MUD;
520+ }
521+ if (liquid == "fruit juice") {
522+ return LIQUID_FRUIT_JUICE;
523+ }
524+ if (liquid == "lava") {
525+ return LIQUID_LAVA;
526+ }
527+ if (liquid == "rum") {
528+ return LIQUID_RUM;
529+ }
530+ if (liquid == "swamp") {
531+ return LIQUID_SWAMP;
532+ }
533+ if (liquid == "ink") {
534+ return LIQUID_INK;
535+ }
536+ if (liquid == "tea") {
537+ return LIQUID_TEA;
538+ }
539+ if (liquid == "mead") {
540+ return LIQUID_MEAD;
541+ }
542+ return LIQUID_NONE;
543+}
544+
545+// ============================================================================
546+// XML Saving & loading
547+
548+Item* Item::Create(pugi::xml_node xml) {
549+ pugi::xml_attribute attribute;
550+
551+ int16_t id = 0;
552+ if ((attribute = xml.attribute("id"))) {
553+ id = attribute.as_ushort();
554+ }
555+
556+ int16_t count = 1;
557+ if ((attribute = xml.attribute("count")) || (attribute = xml.attribute("subtype"))) {
558+ count = attribute.as_ushort();
559+ }
560+
561+ return Create(id, count);
562+}
A RD_Map_Editor/source/item.h +537-0 View file
@@ -0,0 +1,537 @@
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_ITEM_H_
19+#define RME_ITEM_H_
20+
21+#include "items.h"
22+#include "iomap_otbm.h"
23+// #include "iomap_otmm.h"
24+#include "item_attributes.h"
25+#include "doodad_brush.h"
26+#include "raw_brush.h"
27+
28+class Creature;
29+class Border;
30+class Tile;
31+
32+struct SpriteLight;
33+
34+enum ITEMPROPERTY {
35+ BLOCKSOLID,
36+ HASHEIGHT,
37+ BLOCKPROJECTILE,
38+ BLOCKPATHFIND,
39+ PROTECTIONZONE,
40+ HOOK_SOUTH,
41+ HOOK_EAST,
42+ MOVEABLE,
43+ BLOCKINGANDNOTMOVEABLE,
44+ HASLIGHT
45+};
46+
47+enum SplashType {
48+ LIQUID_NONE = 0,
49+ LIQUID_WATER = 1,
50+ LIQUID_BLOOD = 2,
51+ LIQUID_BEER = 3,
52+ LIQUID_SLIME = 4,
53+ LIQUID_LEMONADE = 5,
54+ LIQUID_MILK = 6,
55+ LIQUID_MANAFLUID = 7,
56+ LIQUID_INK = 8,
57+ LIQUID_WATER2 = 9,
58+ LIQUID_LIFEFLUID = 10,
59+ LIQUID_OIL = 11,
60+ LIQUID_SLIME2 = 12,
61+ LIQUID_URINE = 13,
62+ LIQUID_COCONUT_MILK = 14,
63+ LIQUID_WINE = 15,
64+ LIQUID_MUD = 19,
65+ LIQUID_FRUIT_JUICE = 21,
66+ LIQUID_LAVA = 26,
67+ LIQUID_RUM = 27,
68+ LIQUID_SWAMP = 28,
69+ LIQUID_TEA = 35,
70+ LIQUID_MEAD = 43,
71+
72+ LIQUID_FIRST = LIQUID_WATER,
73+ LIQUID_LAST = LIQUID_MEAD
74+};
75+
76+IMPLEMENT_INCREMENT_OP(SplashType)
77+
78+class Item : public ItemAttributes {
79+public:
80+ // Factory member to create item of right type based on type
81+ static Item* Create(uint16_t _type, uint16_t _subtype = 0xFFFF);
82+ static Item* Create(pugi::xml_node);
83+ static Item* Create_OTBM(const IOMap& maphandle, BinaryNode* stream);
84+ // static Item* Create_OTMM(const IOMap& maphandle, BinaryNode* stream);
85+
86+protected:
87+ // Constructor for items
88+ Item(unsigned short _type, unsigned short _count);
89+
90+public:
91+ virtual ~Item();
92+
93+ // Deep copy thingy
94+ virtual Item* deepCopy() const;
95+
96+ // Get memory footprint size
97+ uint32_t memsize() const;
98+ /*
99+ virtual Container* getContainer() {return nullptr;}
100+ virtual const Container* getContainer() const {return nullptr;}
101+ virtual Teleport* getTeleport() {return nullptr;}
102+ virtual const Teleport* getTeleport() const {return nullptr;}
103+ virtual TrashHolder* getTrashHolder() {return nullptr;}
104+ virtual const TrashHolder* getTrashHolder() const {return nullptr;}
105+ virtual Mailbox* getMailbox() {return nullptr;}
106+ virtual const Mailbox* getMailbox() const {return nullptr;}
107+ virtual Door* getDoor() {return nullptr;}
108+ virtual const Door* getDoor() const {return nullptr;}
109+ virtual MagicField* getMagicField() {return nullptr;}
110+ virtual const MagicField* getMagicField() const {return nullptr;}
111+ */
112+
113+ // OTBM map interface
114+ // Serialize and unserialize (for save/load)
115+ // Used internally
116+ virtual bool readItemAttribute_OTBM(const IOMap& maphandle, OTBM_ItemAttribute attr, BinaryNode* stream);
117+ virtual bool unserializeAttributes_OTBM(const IOMap& maphandle, BinaryNode* stream);
118+ virtual bool unserializeItemNode_OTBM(const IOMap& maphandle, BinaryNode* node);
119+
120+ // Will return a node containing this item
121+ virtual bool serializeItemNode_OTBM(const IOMap& maphandle, NodeFileWriteHandle& f) const;
122+ // Will write this item to the stream supplied in the argument
123+ virtual void serializeItemCompact_OTBM(const IOMap& maphandle, NodeFileWriteHandle& f) const;
124+ virtual void serializeItemAttributes_OTBM(const IOMap& maphandle, NodeFileWriteHandle& f) const;
125+
126+ // OTMM map interface
127+ /*
128+ // Serialize and unserialize (for save/load)
129+ // Used internally
130+ virtual bool readItemAttribute_OTMM(const IOMap& maphandle, OTMM_ItemAttribute attr, BinaryNode* stream);
131+ virtual bool unserializeAttributes_OTMM(const IOMap& maphandle, BinaryNode* stream);
132+ virtual bool unserializeItemNode_OTMM(const IOMap& maphandle, BinaryNode* node);
133+
134+ // Will return a node containing this item
135+ virtual bool serializeItemNode_OTMM(const IOMap& maphandle, NodeFileWriteHandle& f) const;
136+ // Will write this item to the stream supplied in the argument
137+ virtual void serializeItemCompact_OTMM(const IOMap& maphandle, NodeFileWriteHandle& f) const;
138+ virtual void serializeItemAttributes_OTMM(const IOMap& maphandle, NodeFileWriteHandle& f) const;
139+ */
140+
141+ // Static conversions
142+ static std::string LiquidID2Name(uint16_t id);
143+ static uint16_t LiquidName2ID(std::string id);
144+
145+ // IDs
146+ uint16_t getID() const {
147+ return id;
148+ }
149+ uint16_t getClientID() const {
150+ return g_items[id].clientID;
151+ }
152+ // NOTE: This is very volatile, do NOT use this unless you know exactly what you're doing
153+ // which you probably don't so avoid it like the plague!
154+ void setID(uint16_t id);
155+
156+ bool typeExists() const {
157+ return g_items.typeExists(id);
158+ }
159+
160+ // Usual attributes
161+ virtual double getWeight() const;
162+ int getAttack() const {
163+ return g_items[id].attack;
164+ }
165+ int getArmor() const {
166+ return g_items[id].armor;
167+ }
168+ int getDefense() const {
169+ return g_items[id].defense;
170+ }
171+ uint16_t getSlotPosition() const {
172+ return g_items[id].slot_position;
173+ }
174+ uint8_t getWeaponType() const {
175+ return g_items[id].weapon_type;
176+ }
177+ uint8_t getClassification() const {
178+ return g_items[id].classification;
179+ } // 12.81
180+
181+ // Item g_settings
182+ bool canHoldText() const;
183+ bool canHoldDescription() const;
184+ bool isReadable() const {
185+ return g_items[id].canReadText;
186+ }
187+ bool canWriteText() const {
188+ return g_items[id].canWriteText;
189+ }
190+ uint32_t getMaxWriteLength() const {
191+ return g_items[id].maxTextLen;
192+ }
193+ Brush* getBrush() const {
194+ return g_items[id].brush;
195+ }
196+ GroundBrush* getGroundBrush() const;
197+ WallBrush* getWallBrush() const;
198+ DoorBrush* getDoorBrush() const;
199+ TableBrush* getTableBrush() const;
200+ CarpetBrush* getCarpetBrush() const;
201+ Brush* getDoodadBrush() const {
202+ return g_items[id].doodad_brush;
203+ } // This is not necessarily a doodad brush
204+ RAWBrush* getRAWBrush() const {
205+ return g_items[id].raw_brush;
206+ }
207+ bool hasCollectionBrush() const {
208+ return g_items[id].collection_brush;
209+ }
210+ uint16_t getGroundEquivalent() const {
211+ return g_items[id].ground_equivalent;
212+ }
213+ uint16_t hasBorderEquivalent() const {
214+ return g_items[id].has_equivalent;
215+ }
216+ uint32_t getBorderGroup() const {
217+ return g_items[id].border_group;
218+ }
219+
220+ // Drawing related
221+ uint8_t getMiniMapColor() const;
222+ int getHeight() const;
223+ std::pair<int, int> getDrawOffset() const;
224+
225+ bool hasLight() const;
226+ SpriteLight getLight() const;
227+
228+ // Item types
229+ bool hasProperty(enum ITEMPROPERTY prop) const;
230+ bool isBlocking() const {
231+ return g_items[id].unpassable;
232+ }
233+ bool isStackable() const {
234+ return g_items[id].stackable;
235+ }
236+ bool isClientCharged() const {
237+ return g_items[id].isClientCharged();
238+ }
239+ bool isExtraCharged() const {
240+ return g_items[id].isExtraCharged();
241+ }
242+ bool isCharged() const {
243+ return isClientCharged() || isExtraCharged();
244+ }
245+ bool isFluidContainer() const {
246+ return (g_items[id].isFluidContainer());
247+ }
248+ bool isAlwaysOnBottom() const {
249+ return g_items[id].alwaysOnBottom;
250+ }
251+ int getTopOrder() const {
252+ return g_items[id].alwaysOnTopOrder;
253+ }
254+ bool isGroundTile() const {
255+ return g_items[id].isGroundTile();
256+ }
257+ bool isSplash() const {
258+ return g_items[id].isSplash();
259+ }
260+ bool isMagicField() const {
261+ return g_items[id].isMagicField();
262+ }
263+ bool isNotMoveable() const {
264+ return !g_items[id].moveable;
265+ }
266+ bool isMoveable() const {
267+ return g_items[id].moveable;
268+ }
269+ bool isPickupable() const {
270+ return g_items[id].pickupable;
271+ }
272+ // bool isWeapon() const {return (g_items[id].weaponType != WEAPON_NONE && g_items[id].weaponType != WEAPON_AMMO);}
273+ // bool isUseable() const {return g_items[id].useable;}
274+ bool isHangable() const {
275+ return g_items[id].isHangable;
276+ }
277+ bool isRoteable() const {
278+ const ItemType& it = g_items[id];
279+ return it.rotable && it.rotateTo;
280+ }
281+ void doRotate() {
282+ if (isRoteable()) {
283+ id = g_items[id].rotateTo;
284+ }
285+ }
286+ bool hasCharges() const {
287+ return g_items[id].charges != 0;
288+ }
289+ bool isBorder() const {
290+ return g_items[id].isBorder;
291+ }
292+ bool isOptionalBorder() const {
293+ return g_items[id].isOptionalBorder;
294+ }
295+ bool isWall() const {
296+ return g_items[id].isWall;
297+ }
298+ bool isDoor() const {
299+ return g_items[id].isDoor();
300+ }
301+ bool isOpen() const {
302+ return g_items[id].isOpen;
303+ }
304+ bool isBrushDoor() const {
305+ return g_items[id].isBrushDoor;
306+ }
307+ bool isTable() const {
308+ return g_items[id].isTable;
309+ }
310+ bool isCarpet() const {
311+ return g_items[id].isCarpet;
312+ }
313+ bool isMetaItem() const {
314+ return g_items[id].isMetaItem();
315+ }
316+
317+ // Slot-based Item Types
318+ bool isWeapon() const {
319+ uint8_t weaponType = g_items[id].weapon_type;
320+ return weaponType != WEAPON_NONE && weaponType != WEAPON_AMMO;
321+ }
322+ bool isAmmunition() const {
323+ return g_items[id].weapon_type == WEAPON_AMMO;
324+ }
325+ bool isWearableEquipment() const { // Determine if the item is wearable piece of armor
326+ uint16_t slotPosition = g_items[id].slot_position;
327+ return slotPosition & SLOTP_HEAD || slotPosition & SLOTP_NECKLACE ||
328+ // slotPosition & SLOTP_BACKPACK || // handled as container in properties window
329+ slotPosition & SLOTP_ARMOR || slotPosition & SLOTP_LEGS || slotPosition & SLOTP_FEET || slotPosition & SLOTP_RING || (slotPosition & SLOTP_AMMO && !isAmmunition()); // light sources that give stats
330+ }
331+
332+ // Wall alignment (vertical, horizontal, pole, corner)
333+ BorderType getWallAlignment() const;
334+ // Border aligment (south, west etc.)
335+ BorderType getBorderAlignment() const;
336+
337+ // Get the border type for z-ordering
338+ BorderType getBorderType() const;
339+
340+ // Set the z-ordering location value for the item
341+ void setLocation(int z_level);
342+ int getLocation() const;
343+
344+ // Get the name!
345+ const std::string getName() const {
346+ return g_items[id].name;
347+ }
348+ const std::string getFullName() const {
349+ return g_items[id].name + g_items[id].editorsuffix;
350+ }
351+
352+ // Selection
353+ bool isSelected() const {
354+ return selected;
355+ }
356+ void select() {
357+ selected = true;
358+ }
359+ void deselect() {
360+ selected = false;
361+ }
362+ void toggleSelection() {
363+ selected = !selected;
364+ }
365+
366+ // Item properties!
367+ virtual bool isComplex() const {
368+ return attributes && attributes->size();
369+ } // If this item requires full save (not compact)
370+
371+ // Weight
372+ bool hasWeight() {
373+ return isPickupable();
374+ }
375+ virtual double getWeight();
376+
377+ // Subtype (count, fluid, charges)
378+ int getCount() const;
379+ uint16_t getSubtype() const;
380+ void setSubtype(uint16_t n);
381+ bool hasSubtype() const;
382+
383+ // Unique ID
384+ void setUniqueID(uint16_t n);
385+ uint16_t getUniqueID() const;
386+
387+ // Action ID
388+ void setActionID(uint16_t n);
389+ uint16_t getActionID() const;
390+
391+ // Tier (12.81)
392+ void setTier(uint16_t n);
393+ uint16_t getTier() const;
394+
395+ // Text
396+ void setText(const std::string& str);
397+ std::string getText() const;
398+
399+ // Description
400+ void setDescription(const std::string& str);
401+ std::string getDescription() const;
402+
403+ void animate();
404+ int getFrame() const {
405+ return frame;
406+ }
407+
408+ // Item locking
409+ bool isLocked() const {return locked;}
410+ void setLocked(bool b) {locked = b;}
411+
412+
413+
414+ // Check if item blocks creatures (for border generation)
415+ bool isBlockingCreature() const {
416+ return g_items[id].unpassable;
417+ }
418+
419+ // Check if item is a stair based on name
420+ bool isStairs() const {
421+ // Check by ID first - specific known floor transition tiles
422+ if (id == 459 || // Classic floor change
423+ id == 924 || // Ramp-style stair
424+ id == 1364 || // Northern wooden stairs
425+ id == 1369 || // Southern wooden stairs
426+ id == 1386) { // Wooden ladder/stair
427+ return true;
428+ }
429+
430+ // Then check by ItemType property (if available)
431+ if (g_items[id].floorChangeDown ||
432+ g_items[id].floorChangeNorth ||
433+ g_items[id].floorChangeSouth ||
434+ g_items[id].floorChangeEast ||
435+ g_items[id].floorChangeWest) {
436+ return true;
437+ }
438+
439+ // Finally check by name
440+ const std::string& name = getName();
441+ std::string lowerName = name;
442+ std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower);
443+ return lowerName.find("stair") != std::string::npos ||
444+ lowerName.find("spiral") != std::string::npos ||
445+ lowerName.find("ramp") != std::string::npos ||
446+ lowerName.find("floor change") != std::string::npos ||
447+ lowerName.find("level change") != std::string::npos;
448+ }
449+
450+ // Check if item is a ladder based on name
451+ bool isLadder() const {
452+ // Check for known ladder IDs
453+ if (id == 1386 || // Wooden ladder/stair
454+ id == 3687 || // Wooden ladder
455+ id == 5543) { // Ship ladder
456+ return true;
457+ }
458+
459+ // Check by floor change properties
460+ if (g_items[id].floorChangeDown || g_items[id].floorChange) {
461+ return true;
462+ }
463+
464+ // Check by name
465+ const std::string& name = getName();
466+ std::string lowerName = name;
467+ std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower);
468+ return lowerName.find("ladder") != std::string::npos;
469+ }
470+
471+protected:
472+ uint16_t id; // the same id as in ItemType
473+ // Subtype is either fluid type, count, subtype or charges
474+ uint16_t subtype;
475+ bool selected;
476+ int frame;
477+ bool locked;
478+
479+private:
480+ Item& operator=(const Item& i); // Can't copy
481+ Item(const Item& i); // Can't copy-construct
482+ Item& operator==(const Item& i); // Can't compare
483+};
484+
485+typedef std::vector<Item*> ItemVector;
486+typedef std::list<Item*> ItemList;
487+
488+Item* transformItem(Item* old_item, uint16_t new_id, Tile* parent = nullptr);
489+
490+inline int Item::getCount() const {
491+ if (isStackable() || isExtraCharged() || isClientCharged()) {
492+ return subtype;
493+ }
494+ return 1;
495+}
496+
497+inline uint16_t Item::getUniqueID() const {
498+ const int32_t* a = getIntegerAttribute("uid");
499+ if (a) {
500+ return *a;
501+ }
502+ return 0;
503+}
504+
505+inline uint16_t Item::getActionID() const {
506+ const int32_t* a = getIntegerAttribute("aid");
507+ if (a) {
508+ return *a;
509+ }
510+ return 0;
511+}
512+
513+inline uint16_t Item::getTier() const {
514+ const int32_t* a = getIntegerAttribute("tier");
515+ if (a) {
516+ return *a;
517+ }
518+ return 0;
519+}
520+
521+inline std::string Item::getText() const {
522+ const std::string* a = getStringAttribute("text");
523+ if (a) {
524+ return *a;
525+ }
526+ return "";
527+}
528+
529+inline std::string Item::getDescription() const {
530+ const std::string* a = getStringAttribute("desc");
531+ if (a) {
532+ return *a;
533+ }
534+ return "";
535+}
536+
537+#endif
Top