Server upload

RD Core / Commit #2

Commit Server upload

Alex Alex committed 18/10/2026 23:38 main Patch
1,106 files +223,404 -0
A src/items.h +461-0 View file
@@ -0,0 +1,461 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#ifndef FS_ITEMS_H_4E2221634ABA45FE85BA50F710669B3C
21+#define FS_ITEMS_H_4E2221634ABA45FE85BA50F710669B3C
22+
23+#include "const.h"
24+#include "enums.h"
25+#include "itemloader.h"
26+#include "position.h"
27+
28+enum SlotPositionBits : uint32_t {
29+ SLOTP_WHEREEVER = 0xFFFFFFFF,
30+ SLOTP_HEAD = 1 << 0,
31+ SLOTP_NECKLACE = 1 << 1,
32+ SLOTP_BACKPACK = 1 << 2,
33+ SLOTP_ARMOR = 1 << 3,
34+ SLOTP_RIGHT = 1 << 4,
35+ SLOTP_LEFT = 1 << 5,
36+ SLOTP_LEGS = 1 << 6,
37+ SLOTP_FEET = 1 << 7,
38+ SLOTP_RING = 1 << 8,
39+ SLOTP_AMMO = 1 << 9,
40+ SLOTP_DEPOT = 1 << 10,
41+ SLOTP_TWO_HAND = 1 << 11,
42+ SLOTP_HAND = (SLOTP_LEFT | SLOTP_RIGHT)
43+};
44+
45+enum ItemTypes_t {
46+ ITEM_TYPE_NONE,
47+ ITEM_TYPE_DEPOT,
48+ ITEM_TYPE_MAILBOX,
49+ ITEM_TYPE_TRASHHOLDER,
50+ ITEM_TYPE_CONTAINER,
51+ ITEM_TYPE_DOOR,
52+ ITEM_TYPE_MAGICFIELD,
53+ ITEM_TYPE_TELEPORT,
54+ ITEM_TYPE_BED,
55+ ITEM_TYPE_KEY,
56+ ITEM_TYPE_RUNE,
57+ ITEM_TYPE_LAST
58+};
59+
60+enum ItemParseAttributes_t {
61+ ITEM_PARSE_TYPE,
62+ ITEM_PARSE_DESCRIPTION,
63+ ITEM_PARSE_RUNESPELLNAME,
64+ ITEM_PARSE_WEIGHT,
65+ ITEM_PARSE_SHOWCOUNT,
66+ ITEM_PARSE_ARMOR,
67+ ITEM_PARSE_DEFENSE,
68+ ITEM_PARSE_EXTRADEF,
69+ ITEM_PARSE_ATTACK,
70+ ITEM_PARSE_ROTATETO,
71+ ITEM_PARSE_MOVEABLE,
72+ ITEM_PARSE_BLOCKPROJECTILE,
73+ ITEM_PARSE_PICKUPABLE,
74+ ITEM_PARSE_FORCESERIALIZE,
75+ ITEM_PARSE_FLOORCHANGE,
76+ ITEM_PARSE_CORPSETYPE,
77+ ITEM_PARSE_CONTAINERSIZE,
78+ ITEM_PARSE_FLUIDSOURCE,
79+ ITEM_PARSE_READABLE,
80+ ITEM_PARSE_WRITEABLE,
81+ ITEM_PARSE_MAXTEXTLEN,
82+ ITEM_PARSE_WRITEONCEITEMID,
83+ ITEM_PARSE_WEAPONTYPE,
84+ ITEM_PARSE_SLOTTYPE,
85+ ITEM_PARSE_AMMOTYPE,
86+ ITEM_PARSE_SHOOTTYPE,
87+ ITEM_PARSE_EFFECT,
88+ ITEM_PARSE_RANGE,
89+ ITEM_PARSE_STOPDURATION,
90+ ITEM_PARSE_DECAYTO,
91+ ITEM_PARSE_TRANSFORMEQUIPTO,
92+ ITEM_PARSE_TRANSFORMDEEQUIPTO,
93+ ITEM_PARSE_DURATION,
94+ ITEM_PARSE_SHOWDURATION,
95+ ITEM_PARSE_CHARGES,
96+ ITEM_PARSE_SHOWCHARGES,
97+ ITEM_PARSE_SHOWATTRIBUTES,
98+ ITEM_PARSE_HITCHANCE,
99+ ITEM_PARSE_MAXHITCHANCE,
100+ ITEM_PARSE_INVISIBLE,
101+ ITEM_PARSE_SPEED,
102+ ITEM_PARSE_HEALTHGAIN,
103+ ITEM_PARSE_HEALTHTICKS,
104+ ITEM_PARSE_MANAGAIN,
105+ ITEM_PARSE_MANATICKS,
106+ ITEM_PARSE_MANASHIELD,
107+ ITEM_PARSE_SKILLSWORD,
108+ ITEM_PARSE_SKILLAXE,
109+ ITEM_PARSE_SKILLCLUB,
110+ ITEM_PARSE_SKILLDIST,
111+ ITEM_PARSE_SKILLFISH,
112+ ITEM_PARSE_SKILLSHIELD,
113+ ITEM_PARSE_SKILLFIST,
114+ ITEM_PARSE_MAXHITPOINTS,
115+ ITEM_PARSE_MAXHITPOINTSPERCENT,
116+ ITEM_PARSE_MAXMANAPOINTS,
117+ ITEM_PARSE_MAXMANAPOINTSPERCENT,
118+ ITEM_PARSE_MAGICPOINTS,
119+ ITEM_PARSE_MAGICPOINTSPERCENT,
120+ ITEM_PARSE_CRITICALHITCHANCE,
121+ ITEM_PARSE_CRITICALHITAMOUNT,
122+ ITEM_PARSE_LIFELEECHCHANCE,
123+ ITEM_PARSE_LIFELEECHAMOUNT,
124+ ITEM_PARSE_MANALEECHCHANCE,
125+ ITEM_PARSE_MANALEECHAMOUNT,
126+ ITEM_PARSE_FIELDABSORBPERCENTENERGY,
127+ ITEM_PARSE_FIELDABSORBPERCENTFIRE,
128+ ITEM_PARSE_FIELDABSORBPERCENTPOISON,
129+ ITEM_PARSE_ABSORBPERCENTALL,
130+ ITEM_PARSE_ABSORBPERCENTELEMENTS,
131+ ITEM_PARSE_ABSORBPERCENTMAGIC,
132+ ITEM_PARSE_ABSORBPERCENTENERGY,
133+ ITEM_PARSE_ABSORBPERCENTFIRE,
134+ ITEM_PARSE_ABSORBPERCENTPOISON,
135+ ITEM_PARSE_ABSORBPERCENTICE,
136+ ITEM_PARSE_ABSORBPERCENTHOLY,
137+ ITEM_PARSE_ABSORBPERCENTDEATH,
138+ ITEM_PARSE_ABSORBPERCENTLIFEDRAIN,
139+ ITEM_PARSE_ABSORBPERCENTMANADRAIN,
140+ ITEM_PARSE_ABSORBPERCENTDROWN,
141+ ITEM_PARSE_ABSORBPERCENTPHYSICAL,
142+ ITEM_PARSE_ABSORBPERCENTHEALING,
143+ ITEM_PARSE_ABSORBPERCENTUNDEFINED,
144+ ITEM_PARSE_SUPPRESSDRUNK,
145+ ITEM_PARSE_SUPPRESSENERGY,
146+ ITEM_PARSE_SUPPRESSFIRE,
147+ ITEM_PARSE_SUPPRESSPOISON,
148+ ITEM_PARSE_SUPPRESSDROWN,
149+ ITEM_PARSE_SUPPRESSPHYSICAL,
150+ ITEM_PARSE_SUPPRESSFREEZE,
151+ ITEM_PARSE_SUPPRESSDAZZLE,
152+ ITEM_PARSE_SUPPRESSCURSE,
153+ ITEM_PARSE_FIELD,
154+ ITEM_PARSE_REPLACEABLE,
155+ ITEM_PARSE_PARTNERDIRECTION,
156+ ITEM_PARSE_LEVELDOOR,
157+ ITEM_PARSE_MALETRANSFORMTO,
158+ ITEM_PARSE_FEMALETRANSFORMTO,
159+ ITEM_PARSE_TRANSFORMTO,
160+ ITEM_PARSE_DESTROYTO,
161+ ITEM_PARSE_ELEMENTICE,
162+ ITEM_PARSE_ELEMENTEARTH,
163+ ITEM_PARSE_ELEMENTFIRE,
164+ ITEM_PARSE_ELEMENTENERGY,
165+ ITEM_PARSE_WALKSTACK,
166+ ITEM_PARSE_BLOCKING,
167+ ITEM_PARSE_ALLOWDISTREAD,
168+};
169+
170+struct Abilities {
171+ uint32_t healthGain = 0;
172+ uint32_t healthTicks = 0;
173+ uint32_t manaGain = 0;
174+ uint32_t manaTicks = 0;
175+
176+ uint32_t conditionImmunities = 0;
177+ uint32_t conditionSuppressions = 0;
178+
179+ //stats modifiers
180+ int32_t stats[STAT_LAST + 1] = { 0 };
181+ int32_t statsPercent[STAT_LAST + 1] = { 0 };
182+
183+ //extra skill modifiers
184+ int32_t skills[SKILL_LAST + 1] = { 0 };
185+ int32_t specialSkills[SPECIALSKILL_LAST + 1] = { 0 };
186+
187+ int32_t speed = 0;
188+
189+ // field damage abilities modifiers
190+ int16_t fieldAbsorbPercent[COMBAT_COUNT] = { 0 };
191+
192+ //damage abilities modifiers
193+ int16_t absorbPercent[COMBAT_COUNT] = { 0 };
194+
195+ //elemental damage
196+ uint16_t elementDamage = 0;
197+ CombatType_t elementType = COMBAT_NONE;
198+
199+ bool manaShield = false;
200+ bool invisible = false;
201+ bool regeneration = false;
202+};
203+
204+class ConditionDamage;
205+
206+class ItemType
207+{
208+ public:
209+ ItemType() = default;
210+
211+ //non-copyable
212+ ItemType(const ItemType& other) = delete;
213+ ItemType& operator=(const ItemType& other) = delete;
214+
215+ ItemType(ItemType&& other) = default;
216+ ItemType& operator=(ItemType&& other) = default;
217+
218+ bool isGroundTile() const {
219+ return group == ITEM_GROUP_GROUND;
220+ }
221+ bool isContainer() const {
222+ return group == ITEM_GROUP_CONTAINER;
223+ }
224+ bool isSplash() const {
225+ return group == ITEM_GROUP_SPLASH;
226+ }
227+ bool isFluidContainer() const {
228+ return group == ITEM_GROUP_FLUID;
229+ }
230+
231+ bool isDoor() const {
232+ return (type == ITEM_TYPE_DOOR);
233+ }
234+ bool isMagicField() const {
235+ return (type == ITEM_TYPE_MAGICFIELD);
236+ }
237+ bool isTeleport() const {
238+ return (type == ITEM_TYPE_TELEPORT);
239+ }
240+ bool isKey() const {
241+ return (type == ITEM_TYPE_KEY);
242+ }
243+ bool isDepot() const {
244+ return (type == ITEM_TYPE_DEPOT);
245+ }
246+ bool isMailbox() const {
247+ return (type == ITEM_TYPE_MAILBOX);
248+ }
249+ bool isTrashHolder() const {
250+ return (type == ITEM_TYPE_TRASHHOLDER);
251+ }
252+ bool isBed() const {
253+ return (type == ITEM_TYPE_BED);
254+ }
255+ bool isRune() const {
256+ return (type == ITEM_TYPE_RUNE);
257+ }
258+ bool isPickupable() const {
259+ return (allowPickupable || pickupable);
260+ }
261+ bool isUseable() const {
262+ return (useable);
263+ }
264+ bool hasSubType() const {
265+ return (isFluidContainer() || isSplash() || stackable || charges != 0);
266+ }
267+
268+ Abilities& getAbilities() {
269+ if (!abilities) {
270+ abilities.reset(new Abilities());
271+ }
272+ return *abilities;
273+ }
274+
275+ std::string getPluralName() const {
276+ if (!pluralName.empty()) {
277+ return pluralName;
278+ }
279+
280+ if (showCount == 0) {
281+ return name;
282+ }
283+
284+ std::string str;
285+ str.reserve(name.length() + 1);
286+ str.assign(name);
287+ str += 's';
288+ return str;
289+ }
290+
291+ itemgroup_t group = ITEM_GROUP_NONE;
292+ ItemTypes_t type = ITEM_TYPE_NONE;
293+ uint16_t id = 0;
294+ uint16_t clientId = 0;
295+ bool stackable = false;
296+ bool isAnimation = false;
297+
298+ std::string name;
299+ std::string article;
300+ std::string pluralName;
301+ std::string description;
302+ std::string runeSpellName;
303+ std::string vocationString;
304+
305+ std::unique_ptr<Abilities> abilities;
306+ std::unique_ptr<ConditionDamage> conditionDamage;
307+
308+ uint32_t weight = 0;
309+ uint32_t levelDoor = 0;
310+ uint32_t decayTime = 0;
311+ uint32_t wieldInfo = 0;
312+ uint32_t minReqLevel = 0;
313+ uint32_t minReqMagicLevel = 0;
314+ uint32_t charges = 0;
315+ int32_t maxHitChance = -1;
316+ int32_t decayTo = -1;
317+ int32_t attack = 0;
318+ int32_t defense = 0;
319+ int32_t extraDefense = 0;
320+ int32_t armor = 0;
321+ uint16_t rotateTo = 0;
322+ int32_t runeMagLevel = 0;
323+ int32_t runeLevel = 0;
324+
325+ CombatType_t combatType = COMBAT_NONE;
326+
327+ uint16_t transformToOnUse[2] = {0, 0};
328+ uint16_t transformToFree = 0;
329+ uint16_t destroyTo = 0;
330+ uint16_t maxTextLen = 0;
331+ uint16_t writeOnceItemId = 0;
332+ uint16_t transformEquipTo = 0;
333+ uint16_t transformDeEquipTo = 0;
334+ uint16_t maxItems = 8;
335+ uint16_t slotPosition = SLOTP_HAND;
336+ uint16_t speed = 0;
337+ uint16_t wareId = 0;
338+
339+ MagicEffectClasses magicEffect = CONST_ME_NONE;
340+ Direction bedPartnerDir = DIRECTION_NONE;
341+ WeaponType_t weaponType = WEAPON_NONE;
342+ Ammo_t ammoType = AMMO_NONE;
343+ ShootType_t shootType = CONST_ANI_NONE;
344+ RaceType_t corpseType = RACE_NONE;
345+ FluidTypes_t fluidSource = FLUID_NONE;
346+
347+ uint8_t floorChange = 0;
348+ uint8_t alwaysOnTopOrder = 0;
349+ uint8_t lightLevel = 0;
350+ uint8_t lightColor = 0;
351+ uint8_t shootRange = 1;
352+ int8_t hitChance = 0;
353+
354+ bool forceUse = false;
355+ bool forceSerialize = false;
356+ bool hasHeight = false;
357+ bool walkStack = true;
358+ bool blockSolid = false;
359+ bool blockPickupable = false;
360+ bool blockProjectile = false;
361+ bool blockPathFind = false;
362+ bool allowPickupable = false;
363+ bool showDuration = false;
364+ bool showCharges = false;
365+ bool showAttributes = false;
366+ bool replaceable = true;
367+ bool pickupable = false;
368+ bool rotatable = false;
369+ bool useable = false;
370+ bool moveable = false;
371+ bool alwaysOnTop = false;
372+ bool canReadText = false;
373+ bool canWriteText = false;
374+ bool isVertical = false;
375+ bool isHorizontal = false;
376+ bool isHangable = false;
377+ bool allowDistRead = false;
378+ bool lookThrough = false;
379+ bool stopTime = false;
380+ bool showCount = true;
381+};
382+
383+class Items
384+{
385+ public:
386+ using NameMap = std::unordered_multimap<std::string, uint16_t>;
387+ using InventoryVector = std::vector<uint16_t>;
388+
389+ Items();
390+
391+ // non-copyable
392+ Items(const Items&) = delete;
393+ Items& operator=(const Items&) = delete;
394+
395+ bool reload();
396+ void clear();
397+
398+ bool loadFromOtb(const std::string& file);
399+
400+ const ItemType& operator[](size_t id) const {
401+ return getItemType(id);
402+ }
403+ const ItemType& getItemType(size_t id) const;
404+ ItemType& getItemType(size_t id);
405+ const ItemType& getItemIdByClientId(uint16_t spriteId) const;
406+
407+ uint16_t getItemIdByName(const std::string& name);
408+
409+ uint32_t majorVersion = 0;
410+ uint32_t minorVersion = 0;
411+ uint32_t buildNumber = 0;
412+
413+ bool loadFromXml();
414+ void parseItemNode(const pugi::xml_node& itemNode, uint16_t id);
415+
416+ void buildInventoryList();
417+ const InventoryVector& getInventory() const {
418+ return inventory;
419+ }
420+
421+ size_t size() const {
422+ return items.size();
423+ }
424+
425+ NameMap nameToItems;
426+
427+ private:
428+ std::vector<ItemType> items;
429+ InventoryVector inventory;
430+ class ClientIdToServerIdMap
431+ {
432+ public:
433+ ClientIdToServerIdMap() {
434+ vec.reserve(30000);
435+ }
436+
437+ void emplace(uint16_t clientId, uint16_t serverId) {
438+ if (clientId >= vec.size()) {
439+ vec.resize(clientId + 1, 0);
440+ }
441+ if (vec[clientId] == 0) {
442+ vec[clientId] = serverId;
443+ }
444+ }
445+
446+ uint16_t getServerId(uint16_t clientId) const {
447+ uint16_t serverId = 0;
448+ if (clientId < vec.size()) {
449+ serverId = vec[clientId];
450+ }
451+ return serverId;
452+ }
453+
454+ void clear() {
455+ vec.clear();
456+ }
457+ private:
458+ std::vector<uint16_t> vec;
459+ } clientIdToServerIdMap;
460+};
461+#endif
A src/lockfree.h +77-0 View file
@@ -0,0 +1,77 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#ifndef FS_LOCKFREE_H_8C707AEB7C7235A2FBC5D4EDDF03B008
21+#define FS_LOCKFREE_H_8C707AEB7C7235A2FBC5D4EDDF03B008
22+
23+#if _MSC_FULL_VER >= 190023918 // Workaround for VS2015 Update 2. Boost.Lockfree is a header-only library, so this should be safe to do.
24+#define _ENABLE_ATOMIC_ALIGNMENT_FIX
25+#endif
26+
27+#include <boost/lockfree/stack.hpp>
28+
29+/*
30+ * we use this to avoid instantiating multiple free lists for objects of the
31+ * same size and it can be replaced by a variable template in C++14
32+ *
33+ * template <std::size_t TSize, size_t CAPACITY>
34+ * boost::lockfree::stack<void*, boost::lockfree::capacity<CAPACITY> lockfreeFreeList;
35+ */
36+template <std::size_t TSize, size_t CAPACITY>
37+struct LockfreeFreeList
38+{
39+ using FreeList = boost::lockfree::stack<void*, boost::lockfree::capacity<CAPACITY>>;
40+ static FreeList& get()
41+ {
42+ static FreeList freeList;
43+ return freeList;
44+ }
45+};
46+
47+template <typename T, size_t CAPACITY>
48+class LockfreePoolingAllocator : public std::allocator<T>
49+{
50+ public:
51+ LockfreePoolingAllocator() = default;
52+
53+ template <typename U, class = typename std::enable_if<!std::is_same<U, T>::value>::type>
54+ explicit constexpr LockfreePoolingAllocator(const U&) {}
55+ using value_type = T;
56+
57+ T* allocate(size_t) const {
58+ auto& inst = LockfreeFreeList<sizeof(T), CAPACITY>::get();
59+ void* p; // NOTE: p doesn't have to be initialized
60+ if (!inst.pop(p)) {
61+ //Acquire memory without calling the constructor of T
62+ p = operator new (sizeof(T));
63+ }
64+ return static_cast<T*>(p);
65+ }
66+
67+ void deallocate(T* p, size_t) const {
68+ auto& inst = LockfreeFreeList<sizeof(T), CAPACITY>::get();
69+ if (!inst.bounded_push(p)) {
70+ //Release memory without calling the destructor of T
71+ //(it has already been called at this point)
72+ operator delete(p);
73+ }
74+ }
75+};
76+
77+#endif
Top