item.h

main 538 lines · 14.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#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
28class Creature;
29class Border;
30class Tile;
31
32struct SpriteLight;
33
34enum 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
47enum 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
76IMPLEMENT_INCREMENT_OP(SplashType)
77
78class Item : public ItemAttributes {
79public:
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
86protected:
87 // Constructor for items
88 Item(unsigned short _type, unsigned short _count);
89
90public:
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
471protected:
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
479private:
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
485typedef std::vector<Item*> ItemVector;
486typedef std::list<Item*> ItemList;
487
488Item* transformItem(Item* old_item, uint16_t new_id, Tile* parent = nullptr);
489
490inline int Item::getCount() const {
491 if (isStackable() || isExtraCharged() || isClientCharged()) {
492 return subtype;
493 }
494 return 1;
495}
496
497inline uint16_t Item::getUniqueID() const {
498 const int32_t* a = getIntegerAttribute("uid");
499 if (a) {
500 return *a;
501 }
502 return 0;
503}
504
505inline uint16_t Item::getActionID() const {
506 const int32_t* a = getIntegerAttribute("aid");
507 if (a) {
508 return *a;
509 }
510 return 0;
511}
512
513inline uint16_t Item::getTier() const {
514 const int32_t* a = getIntegerAttribute("tier");
515 if (a) {
516 return *a;
517 }
518 return 0;
519}
520
521inline std::string Item::getText() const {
522 const std::string* a = getStringAttribute("text");
523 if (a) {
524 return *a;
525 }
526 return "";
527}
528
529inline 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
538
Top