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/tile.h +389-0 View file
@@ -0,0 +1,389 @@
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_TILE_H_96C7EE7CF8CD48E59D5D554A181F0C56
21+#define FS_TILE_H_96C7EE7CF8CD48E59D5D554A181F0C56
22+
23+#include "cylinder.h"
24+#include "item.h"
25+#include "tools.h"
26+#include "spectators.h"
27+
28+class Creature;
29+class Teleport;
30+class TrashHolder;
31+class Mailbox;
32+class MagicField;
33+class QTreeLeafNode;
34+class BedItem;
35+
36+using CreatureVector = std::vector<Creature*>;
37+using ItemVector = std::vector<Item*>;
38+
39+enum tileflags_t : uint32_t {
40+ TILESTATE_NONE = 0,
41+
42+ TILESTATE_FLOORCHANGE_DOWN = 1 << 0,
43+ TILESTATE_FLOORCHANGE_NORTH = 1 << 1,
44+ TILESTATE_FLOORCHANGE_SOUTH = 1 << 2,
45+ TILESTATE_FLOORCHANGE_EAST = 1 << 3,
46+ TILESTATE_FLOORCHANGE_WEST = 1 << 4,
47+ TILESTATE_FLOORCHANGE_SOUTH_ALT = 1 << 5,
48+ TILESTATE_FLOORCHANGE_EAST_ALT = 1 << 6,
49+ TILESTATE_PROTECTIONZONE = 1 << 7,
50+ TILESTATE_NOPVPZONE = 1 << 8,
51+ TILESTATE_NOLOGOUT = 1 << 9,
52+ TILESTATE_PVPZONE = 1 << 10,
53+ TILESTATE_TELEPORT = 1 << 11,
54+ TILESTATE_MAGICFIELD = 1 << 12,
55+ TILESTATE_MAILBOX = 1 << 13,
56+ TILESTATE_TRASHHOLDER = 1 << 14,
57+ TILESTATE_BED = 1 << 15,
58+ TILESTATE_DEPOT = 1 << 16,
59+ TILESTATE_BLOCKSOLID = 1 << 17,
60+ TILESTATE_BLOCKPATH = 1 << 18,
61+ TILESTATE_IMMOVABLEBLOCKSOLID = 1 << 19,
62+ TILESTATE_IMMOVABLEBLOCKPATH = 1 << 20,
63+ TILESTATE_IMMOVABLENOFIELDBLOCKPATH = 1 << 21,
64+ TILESTATE_NOFIELDBLOCKPATH = 1 << 22,
65+ TILESTATE_SUPPORTS_HANGABLE = 1 << 23,
66+
67+ TILESTATE_FLOORCHANGE = TILESTATE_FLOORCHANGE_DOWN | TILESTATE_FLOORCHANGE_NORTH | TILESTATE_FLOORCHANGE_SOUTH | TILESTATE_FLOORCHANGE_EAST | TILESTATE_FLOORCHANGE_WEST | TILESTATE_FLOORCHANGE_SOUTH_ALT | TILESTATE_FLOORCHANGE_EAST_ALT,
68+};
69+
70+enum ZoneType_t {
71+ ZONE_PROTECTION,
72+ ZONE_NOPVP,
73+ ZONE_PVP,
74+ ZONE_NOLOGOUT,
75+ ZONE_NORMAL,
76+};
77+
78+class TileItemVector : private ItemVector
79+{
80+ public:
81+ using ItemVector::begin;
82+ using ItemVector::end;
83+ using ItemVector::rbegin;
84+ using ItemVector::rend;
85+ using ItemVector::size;
86+ using ItemVector::clear;
87+ using ItemVector::at;
88+ using ItemVector::insert;
89+ using ItemVector::erase;
90+ using ItemVector::push_back;
91+ using ItemVector::value_type;
92+ using ItemVector::iterator;
93+ using ItemVector::const_iterator;
94+ using ItemVector::reverse_iterator;
95+ using ItemVector::const_reverse_iterator;
96+ using ItemVector::empty;
97+
98+ iterator getBeginDownItem() {
99+ return begin();
100+ }
101+ const_iterator getBeginDownItem() const {
102+ return begin();
103+ }
104+ iterator getEndDownItem() {
105+ return begin() + downItemCount;
106+ }
107+ const_iterator getEndDownItem() const {
108+ return begin() + downItemCount;
109+ }
110+ iterator getBeginTopItem() {
111+ return getEndDownItem();
112+ }
113+ const_iterator getBeginTopItem() const {
114+ return getEndDownItem();
115+ }
116+ iterator getEndTopItem() {
117+ return end();
118+ }
119+ const_iterator getEndTopItem() const {
120+ return end();
121+ }
122+
123+ uint32_t getTopItemCount() const {
124+ return size() - downItemCount;
125+ }
126+ uint32_t getDownItemCount() const {
127+ return downItemCount;
128+ }
129+ inline Item* getTopTopItem() const {
130+ if (getTopItemCount() == 0) {
131+ return nullptr;
132+ }
133+ return *(getEndTopItem() - 1);
134+ }
135+ inline Item* getTopDownItem() const {
136+ if (downItemCount == 0) {
137+ return nullptr;
138+ }
139+ return *getBeginDownItem();
140+ }
141+ void addDownItemCount(int32_t increment) {
142+ downItemCount += increment;
143+ }
144+
145+ private:
146+ uint16_t downItemCount = 0;
147+};
148+
149+class Tile : public Cylinder
150+{
151+ public:
152+ static Tile& nullptr_tile;
153+ Tile(uint16_t x, uint16_t y, uint8_t z) : tilePos(x, y, z) {}
154+ virtual ~Tile() {
155+ delete ground;
156+ };
157+
158+ // non-copyable
159+ Tile(const Tile&) = delete;
160+ Tile& operator=(const Tile&) = delete;
161+
162+ virtual TileItemVector* getItemList() = 0;
163+ virtual const TileItemVector* getItemList() const = 0;
164+ virtual TileItemVector* makeItemList() = 0;
165+
166+ virtual CreatureVector* getCreatures() = 0;
167+ virtual const CreatureVector* getCreatures() const = 0;
168+ virtual CreatureVector* makeCreatures() = 0;
169+
170+ int32_t getThrowRange() const override final {
171+ return 0;
172+ }
173+ bool isPushable() const override final {
174+ return false;
175+ }
176+
177+ MagicField* getFieldItem() const;
178+ Teleport* getTeleportItem() const;
179+ TrashHolder* getTrashHolder() const;
180+ Mailbox* getMailbox() const;
181+ BedItem* getBedItem() const;
182+
183+ Creature* getTopCreature() const;
184+ const Creature* getBottomCreature() const;
185+ Creature* getTopVisibleCreature(const Creature* creature) const;
186+ const Creature* getBottomVisibleCreature(const Creature* creature) const;
187+ Item* getTopTopItem() const;
188+ Item* getTopDownItem() const;
189+ bool isMoveableBlocking() const;
190+ Thing* getTopVisibleThing(const Creature* creature);
191+ Item* getItemByTopOrder(int32_t topOrder);
192+
193+ size_t getThingCount() const {
194+ size_t thingCount = getCreatureCount() + getItemCount();
195+ if (ground) {
196+ thingCount++;
197+ }
198+ return thingCount;
199+ }
200+ // If these return != 0 the associated vectors are guaranteed to exists
201+ size_t getCreatureCount() const;
202+ size_t getItemCount() const;
203+ uint32_t getTopItemCount() const;
204+ uint32_t getDownItemCount() const;
205+
206+ bool hasProperty(ITEMPROPERTY prop) const;
207+ bool hasProperty(const Item* exclude, ITEMPROPERTY prop) const;
208+
209+ bool hasFlag(uint32_t flag) const {
210+ return hasBitSet(flag, this->flags);
211+ }
212+ void setFlag(uint32_t flag) {
213+ this->flags |= flag;
214+ }
215+ void resetFlag(uint32_t flag) {
216+ this->flags &= ~flag;
217+ }
218+
219+ ZoneType_t getZone() const {
220+ if (hasFlag(TILESTATE_PROTECTIONZONE)) {
221+ return ZONE_PROTECTION;
222+ } else if (hasFlag(TILESTATE_NOPVPZONE)) {
223+ return ZONE_NOPVP;
224+ } else if (hasFlag(TILESTATE_PVPZONE)) {
225+ return ZONE_PVP;
226+ } else {
227+ return ZONE_NORMAL;
228+ }
229+ }
230+
231+ bool hasHeight(uint32_t n) const;
232+
233+ std::string getDescription(int32_t lookDistance) const override final;
234+
235+ int32_t getClientIndexOfCreature(const Player* player, const Creature* creature) const;
236+ int32_t getStackposOfCreature(const Player* player, const Creature* creature) const;
237+ int32_t getStackposOfItem(const Player* player, const Item* item) const;
238+
239+ //cylinder implementations
240+ ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
241+ uint32_t flags, Creature* actor = nullptr) const override;
242+ ReturnValue queryMaxCount(int32_t index, const Thing& thing, uint32_t count,
243+ uint32_t& maxQueryCount, uint32_t flags) const override final;
244+ ReturnValue queryRemove(const Thing& thing, uint32_t count, uint32_t flags) const override final;
245+ Tile* queryDestination(int32_t& index, const Thing& thing, Item** destItem, uint32_t& flags) override;
246+
247+ void addThing(Thing* thing) override final;
248+ void addThing(int32_t index, Thing* thing) override;
249+
250+ void updateThing(Thing* thing, uint16_t itemId, uint32_t count) override final;
251+ void replaceThing(uint32_t index, Thing* thing) override final;
252+
253+ void removeThing(Thing* thing, uint32_t count) override final;
254+
255+ void removeCreature(Creature* creature);
256+
257+ int32_t getThingIndex(const Thing* thing) const override final;
258+ size_t getFirstIndex() const override final;
259+ size_t getLastIndex() const override final;
260+ uint32_t getItemTypeCount(uint16_t itemId, int32_t subType = -1) const override final;
261+ Thing* getThing(size_t index) const override final;
262+
263+ void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override final;
264+ void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override final;
265+
266+ void internalAddThing(Thing* thing) override final;
267+ void internalAddThing(uint32_t index, Thing* thing) override;
268+
269+ const Position& getPosition() const override final {
270+ return tilePos;
271+ }
272+
273+ bool isRemoved() const override final {
274+ return false;
275+ }
276+
277+ Item* getUseItem(int32_t index) const;
278+
279+ Item* getGround() const {
280+ return ground;
281+ }
282+ void setGround(Item* item) {
283+ ground = item;
284+ }
285+
286+ private:
287+ void onAddTileItem(Item* item);
288+ void onUpdateTileItem(Item* oldItem, const ItemType& oldType, Item* newItem, const ItemType& newType);
289+ void onRemoveTileItem(const SpectatorVec& spectators, const std::vector<int32_t>& oldStackPosVector, Item* item);
290+ void onUpdateTile(const SpectatorVec& spectators);
291+
292+ void setTileFlags(const Item* item);
293+ void resetTileFlags(const Item* item);
294+
295+ Item* ground = nullptr;
296+ Position tilePos;
297+ uint32_t flags = 0;
298+};
299+
300+// Used for walkable tiles, where there is high likeliness of
301+// items being added/removed
302+class DynamicTile : public Tile
303+{
304+ // By allocating the vectors in-house, we avoid some memory fragmentation
305+ TileItemVector items;
306+ CreatureVector creatures;
307+
308+ public:
309+ DynamicTile(uint16_t x, uint16_t y, uint8_t z) : Tile(x, y, z) {}
310+ ~DynamicTile() {
311+ for (Item* item : items) {
312+ item->decrementReferenceCounter();
313+ }
314+ }
315+
316+ // non-copyable
317+ DynamicTile(const DynamicTile&) = delete;
318+ DynamicTile& operator=(const DynamicTile&) = delete;
319+
320+ TileItemVector* getItemList() override {
321+ return &items;
322+ }
323+ const TileItemVector* getItemList() const override {
324+ return &items;
325+ }
326+ TileItemVector* makeItemList() override {
327+ return &items;
328+ }
329+
330+ CreatureVector* getCreatures() override {
331+ return &creatures;
332+ }
333+ const CreatureVector* getCreatures() const override {
334+ return &creatures;
335+ }
336+ CreatureVector* makeCreatures() override {
337+ return &creatures;
338+ }
339+};
340+
341+// For blocking tiles, where we very rarely actually have items
342+class StaticTile final : public Tile
343+{
344+ // We very rarely even need the vectors, so don't keep them in memory
345+ std::unique_ptr<TileItemVector> items;
346+ std::unique_ptr<CreatureVector> creatures;
347+
348+ public:
349+ StaticTile(uint16_t x, uint16_t y, uint8_t z) : Tile(x, y, z) {}
350+ ~StaticTile() {
351+ if (items) {
352+ for (Item* item : *items) {
353+ item->decrementReferenceCounter();
354+ }
355+ }
356+ }
357+
358+ // non-copyable
359+ StaticTile(const StaticTile&) = delete;
360+ StaticTile& operator=(const StaticTile&) = delete;
361+
362+ TileItemVector* getItemList() override {
363+ return items.get();
364+ }
365+ const TileItemVector* getItemList() const override {
366+ return items.get();
367+ }
368+ TileItemVector* makeItemList() override {
369+ if (!items) {
370+ items.reset(new TileItemVector);
371+ }
372+ return items.get();
373+ }
374+
375+ CreatureVector* getCreatures() override {
376+ return creatures.get();
377+ }
378+ const CreatureVector* getCreatures() const override {
379+ return creatures.get();
380+ }
381+ CreatureVector* makeCreatures() override {
382+ if (!creatures) {
383+ creatures.reset(new CreatureVector);
384+ }
385+ return creatures.get();
386+ }
387+};
388+
389+#endif
A src/tools.h +99-0 View file
@@ -0,0 +1,99 @@
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_TOOLS_H_5F9A9742DA194628830AA1C64909AE43
21+#define FS_TOOLS_H_5F9A9742DA194628830AA1C64909AE43
22+
23+#include <random>
24+
25+#include "position.h"
26+#include "const.h"
27+#include "enums.h"
28+
29+void printXMLError(const std::string& where, const std::string& fileName, const pugi::xml_parse_result& result);
30+
31+std::string transformToSHA1(const std::string& input);
32+std::string generateToken(const std::string& key, uint32_t ticks);
33+
34+void replaceString(std::string& str, const std::string& sought, const std::string& replacement);
35+void trim_right(std::string& source, char t);
36+void trim_left(std::string& source, char t);
37+void toLowerCaseString(std::string& source);
38+std::string asLowerCaseString(std::string source);
39+std::string asUpperCaseString(std::string source);
40+
41+using StringVector = std::vector<std::string>;
42+using IntegerVector = std::vector<int32_t>;
43+
44+StringVector explodeString(const std::string& inString, const std::string& separator, int32_t limit = -1);
45+IntegerVector vectorAtoi(const StringVector& stringVector);
46+constexpr bool hasBitSet(uint32_t flag, uint32_t flags) {
47+ return (flags & flag) != 0;
48+}
49+
50+std::mt19937& getRandomGenerator();
51+int32_t uniform_random(int32_t minNumber, int32_t maxNumber);
52+int32_t normal_random(int32_t minNumber, int32_t maxNumber);
53+bool boolean_random(double probability = 0.5);
54+
55+Direction getDirection(const std::string& string);
56+Position getNextPosition(Direction direction, Position pos);
57+Direction getDirectionTo(const Position& from, const Position& to);
58+
59+std::string getFirstLine(const std::string& str);
60+
61+std::string formatDate(time_t time);
62+std::string formatDateShort(time_t time);
63+std::string convertIPToString(uint32_t ip);
64+
65+void trimString(std::string& str);
66+
67+MagicEffectClasses getMagicEffect(const std::string& strValue);
68+ShootType_t getShootType(const std::string& strValue);
69+Ammo_t getAmmoType(const std::string& strValue);
70+WeaponAction_t getWeaponAction(const std::string& strValue);
71+Skulls_t getSkullType(const std::string& strValue);
72+std::string getCombatName(CombatType_t combatType);
73+
74+std::string getSpecialSkillName(uint8_t skillid);
75+std::string getSkillName(uint8_t skillid);
76+
77+uint32_t adlerChecksum(const uint8_t* data, size_t length);
78+
79+std::string ucfirst(std::string str);
80+std::string ucwords(std::string str);
81+bool booleanString(const std::string& str);
82+
83+std::string getWeaponName(WeaponType_t weaponType);
84+
85+size_t combatTypeToIndex(CombatType_t combatType);
86+CombatType_t indexToCombatType(size_t v);
87+
88+uint8_t serverFluidToClient(uint8_t serverFluid);
89+uint8_t clientFluidToServer(uint8_t clientFluid);
90+
91+itemAttrTypes stringToItemAttribute(const std::string& str);
92+
93+const char* getReturnMessage(ReturnValue value);
94+
95+int64_t OTSYS_TIME();
96+
97+SpellGroup_t stringToSpellGroup(const std::string& value);
98+
99+#endif
A src/town.h +98-0 View file
@@ -0,0 +1,98 @@
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_TOWN_H_3BE21D2293B44AA4A3D22D25BE1B9350
21+#define FS_TOWN_H_3BE21D2293B44AA4A3D22D25BE1B9350
22+
23+#include "position.h"
24+
25+class Town
26+{
27+ public:
28+ explicit Town(uint32_t id) : id(id) {}
29+
30+ const Position& getTemplePosition() const {
31+ return templePosition;
32+ }
33+ const std::string& getName() const {
34+ return name;
35+ }
36+
37+ void setTemplePos(Position pos) {
38+ templePosition = pos;
39+ }
40+ void setName(std::string name) {
41+ this->name = std::move(name);
42+ }
43+ uint32_t getID() const {
44+ return id;
45+ }
46+
47+ private:
48+ uint32_t id;
49+ std::string name;
50+ Position templePosition;
51+};
52+
53+using TownMap = std::map<uint32_t, Town*>;
54+
55+class Towns
56+{
57+ public:
58+ Towns() = default;
59+ ~Towns() {
60+ for (const auto& it : townMap) {
61+ delete it.second;
62+ }
63+ }
64+
65+ // non-copyable
66+ Towns(const Towns&) = delete;
67+ Towns& operator=(const Towns&) = delete;
68+
69+ bool addTown(uint32_t townId, Town* town) {
70+ return townMap.emplace(townId, town).second;
71+ }
72+
73+ Town* getTown(const std::string& townName) const {
74+ for (const auto& it : townMap) {
75+ if (strcasecmp(townName.c_str(), it.second->getName().c_str()) == 0) {
76+ return it.second;
77+ }
78+ }
79+ return nullptr;
80+ }
81+
82+ Town* getTown(uint32_t townId) const {
83+ auto it = townMap.find(townId);
84+ if (it == townMap.end()) {
85+ return nullptr;
86+ }
87+ return it->second;
88+ }
89+
90+ const TownMap& getTowns() const {
91+ return townMap;
92+ }
93+
94+ private:
95+ TownMap townMap;
96+};
97+
98+#endif
A src/trashholder.cpp +102-0 View file
@@ -0,0 +1,102 @@
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+#include "otpch.h"
21+
22+#include "trashholder.h"
23+#include "game.h"
24+
25+extern Game g_game;
26+
27+ReturnValue TrashHolder::queryAdd(int32_t, const Thing&, uint32_t, uint32_t, Creature*) const
28+{
29+ return RETURNVALUE_NOERROR;
30+}
31+
32+ReturnValue TrashHolder::queryMaxCount(int32_t, const Thing&, uint32_t count, uint32_t& maxQueryCount, uint32_t) const
33+{
34+ maxQueryCount = std::max<uint32_t>(1, count);
35+ return RETURNVALUE_NOERROR;
36+}
37+
38+ReturnValue TrashHolder::queryRemove(const Thing&, uint32_t, uint32_t) const
39+{
40+ return RETURNVALUE_NOTPOSSIBLE;
41+}
42+
43+Cylinder* TrashHolder::queryDestination(int32_t&, const Thing&, Item**, uint32_t&)
44+{
45+ return this;
46+}
47+
48+void TrashHolder::addThing(Thing* thing)
49+{
50+ return addThing(0, thing);
51+}
52+
53+void TrashHolder::addThing(int32_t, Thing* thing)
54+{
55+ Item* item = thing->getItem();
56+ if (!item) {
57+ return;
58+ }
59+
60+ if (item == this || !item->hasProperty(CONST_PROP_MOVEABLE)) {
61+ return;
62+ }
63+
64+ const ItemType& it = Item::items[id];
65+ if (item->isHangable() && it.isGroundTile()) {
66+ Tile* tile = dynamic_cast<Tile*>(getParent());
67+ if (tile && tile->hasFlag(TILESTATE_SUPPORTS_HANGABLE)) {
68+ return;
69+ }
70+ }
71+
72+ g_game.internalRemoveItem(item);
73+
74+ if (it.magicEffect != CONST_ME_NONE) {
75+ g_game.addMagicEffect(getPosition(), it.magicEffect);
76+ }
77+}
78+
79+void TrashHolder::updateThing(Thing*, uint16_t, uint32_t)
80+{
81+ //
82+}
83+
84+void TrashHolder::replaceThing(uint32_t, Thing*)
85+{
86+ //
87+}
88+
89+void TrashHolder::removeThing(Thing*, uint32_t)
90+{
91+ //
92+}
93+
94+void TrashHolder::postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t)
95+{
96+ getParent()->postAddNotification(thing, oldParent, index, LINK_PARENT);
97+}
98+
99+void TrashHolder::postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t)
100+{
101+ getParent()->postRemoveNotification(thing, newParent, index, LINK_PARENT);
102+}
A src/trashholder.h +57-0 View file
@@ -0,0 +1,57 @@
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_TRASHHOLDER_H_BA162024D67B4D388147F5EE06F33098
21+#define FS_TRASHHOLDER_H_BA162024D67B4D388147F5EE06F33098
22+
23+#include "item.h"
24+#include "cylinder.h"
25+#include "const.h"
26+
27+class TrashHolder final : public Item, public Cylinder
28+{
29+ public:
30+ explicit TrashHolder(uint16_t itemId) : Item(itemId) {}
31+
32+ TrashHolder* getTrashHolder() override {
33+ return this;
34+ }
35+ const TrashHolder* getTrashHolder() const override {
36+ return this;
37+ }
38+
39+ //cylinder implementations
40+ ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count, uint32_t flags, Creature* actor = nullptr) const override;
41+ ReturnValue queryMaxCount(int32_t index, const Thing& thing, uint32_t count, uint32_t& maxQueryCount, uint32_t flags) const override;
42+ ReturnValue queryRemove(const Thing& thing, uint32_t count, uint32_t flags) const override;
43+ Cylinder* queryDestination(int32_t& index, const Thing& thing, Item** destItem, uint32_t& flags) override;
44+
45+ void addThing(Thing* thing) override;
46+ void addThing(int32_t index, Thing* thing) override;
47+
48+ void updateThing(Thing* thing, uint16_t itemId, uint32_t count) override;
49+ void replaceThing(uint32_t index, Thing* thing) override;
50+
51+ void removeThing(Thing* thing, uint32_t count) override;
52+
53+ void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
54+ void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
55+};
56+
57+#endif
A src/vocation.cpp +210-0 View file
@@ -0,0 +1,210 @@
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+#include "otpch.h"
21+
22+#include "vocation.h"
23+
24+#include "pugicast.h"
25+#include "tools.h"
26+
27+bool Vocations::loadFromXml()
28+{
29+ pugi::xml_document doc;
30+ pugi::xml_parse_result result = doc.load_file("data/XML/vocations.xml");
31+ if (!result) {
32+ printXMLError("Error - Vocations::loadFromXml", "data/XML/vocations.xml", result);
33+ return false;
34+ }
35+
36+ for (auto vocationNode : doc.child("vocations").children()) {
37+ pugi::xml_attribute attr;
38+ if (!(attr = vocationNode.attribute("id"))) {
39+ std::cout << "[Warning - Vocations::loadFromXml] Missing vocation id" << std::endl;
40+ continue;
41+ }
42+
43+ uint16_t id = pugi::cast<uint16_t>(attr.value());
44+
45+ auto res = vocationsMap.emplace(std::piecewise_construct,
46+ std::forward_as_tuple(id), std::forward_as_tuple(id));
47+ Vocation& voc = res.first->second;
48+
49+ if ((attr = vocationNode.attribute("name"))) {
50+ voc.name = attr.as_string();
51+ }
52+
53+ if ((attr = vocationNode.attribute("clientid"))) {
54+ voc.clientId = pugi::cast<uint16_t>(attr.value());
55+ }
56+
57+ if ((attr = vocationNode.attribute("description"))) {
58+ voc.description = attr.as_string();
59+ }
60+
61+ if ((attr = vocationNode.attribute("gaincap"))) {
62+ voc.gainCap = pugi::cast<uint32_t>(attr.value()) * 100;
63+ }
64+
65+ if ((attr = vocationNode.attribute("gainhp"))) {
66+ voc.gainHP = pugi::cast<uint32_t>(attr.value());
67+ }
68+
69+ if ((attr = vocationNode.attribute("gainmana"))) {
70+ voc.gainMana = pugi::cast<uint32_t>(attr.value());
71+ }
72+
73+ if ((attr = vocationNode.attribute("gainhpticks"))) {
74+ voc.gainHealthTicks = pugi::cast<uint32_t>(attr.value());
75+ }
76+
77+ if ((attr = vocationNode.attribute("gainhpamount"))) {
78+ voc.gainHealthAmount = pugi::cast<uint32_t>(attr.value());
79+ }
80+
81+ if ((attr = vocationNode.attribute("gainmanaticks"))) {
82+ voc.gainManaTicks = pugi::cast<uint32_t>(attr.value());
83+ }
84+
85+ if ((attr = vocationNode.attribute("gainmanaamount"))) {
86+ voc.gainManaAmount = pugi::cast<uint32_t>(attr.value());
87+ }
88+
89+ if ((attr = vocationNode.attribute("manamultiplier"))) {
90+ voc.manaMultiplier = pugi::cast<float>(attr.value());
91+ }
92+
93+ if ((attr = vocationNode.attribute("attackspeed"))) {
94+ voc.attackSpeed = pugi::cast<uint32_t>(attr.value());
95+ }
96+
97+ if ((attr = vocationNode.attribute("basespeed"))) {
98+ voc.baseSpeed = pugi::cast<uint32_t>(attr.value());
99+ }
100+
101+ if ((attr = vocationNode.attribute("soulmax"))) {
102+ voc.soulMax = pugi::cast<uint16_t>(attr.value());
103+ }
104+
105+ if ((attr = vocationNode.attribute("gainsoulticks"))) {
106+ voc.gainSoulTicks = pugi::cast<uint16_t>(attr.value());
107+ }
108+
109+ if ((attr = vocationNode.attribute("fromvoc"))) {
110+ voc.fromVocation = pugi::cast<uint32_t>(attr.value());
111+ }
112+
113+ for (auto childNode : vocationNode.children()) {
114+ if (strcasecmp(childNode.name(), "skill") == 0) {
115+ pugi::xml_attribute skillIdAttribute = childNode.attribute("id");
116+ if (skillIdAttribute) {
117+ uint16_t skill_id = pugi::cast<uint16_t>(skillIdAttribute.value());
118+ if (skill_id <= SKILL_LAST) {
119+ voc.skillMultipliers[skill_id] = pugi::cast<float>(childNode.attribute("multiplier").value());
120+ } else {
121+ std::cout << "[Notice - Vocations::loadFromXml] No valid skill id: " << skill_id << " for vocation: " << voc.id << std::endl;
122+ }
123+ } else {
124+ std::cout << "[Notice - Vocations::loadFromXml] Missing skill id for vocation: " << voc.id << std::endl;
125+ }
126+ } else if (strcasecmp(childNode.name(), "formula") == 0) {
127+ pugi::xml_attribute meleeDamageAttribute = childNode.attribute("meleeDamage");
128+ if (meleeDamageAttribute) {
129+ voc.meleeDamageMultiplier = pugi::cast<float>(meleeDamageAttribute.value());
130+ }
131+
132+ pugi::xml_attribute distDamageAttribute = childNode.attribute("distDamage");
133+ if (distDamageAttribute) {
134+ voc.distDamageMultiplier = pugi::cast<float>(distDamageAttribute.value());
135+ }
136+
137+ pugi::xml_attribute defenseAttribute = childNode.attribute("defense");
138+ if (defenseAttribute) {
139+ voc.defenseMultiplier = pugi::cast<float>(defenseAttribute.value());
140+ }
141+
142+ pugi::xml_attribute armorAttribute = childNode.attribute("armor");
143+ if (armorAttribute) {
144+ voc.armorMultiplier = pugi::cast<float>(armorAttribute.value());
145+ }
146+ }
147+ }
148+ }
149+ return true;
150+}
151+
152+Vocation* Vocations::getVocation(uint16_t id)
153+{
154+ auto it = vocationsMap.find(id);
155+ if (it == vocationsMap.end()) {
156+ std::cout << "[Warning - Vocations::getVocation] Vocation " << id << " not found." << std::endl;
157+ return nullptr;
158+ }
159+ return &it->second;
160+}
161+
162+int32_t Vocations::getVocationId(const std::string& name) const
163+{
164+ for (const auto& it : vocationsMap) {
165+ if (strcasecmp(it.second.name.c_str(), name.c_str()) == 0) {
166+ return it.first;
167+ }
168+ }
169+ return -1;
170+}
171+
172+uint16_t Vocations::getPromotedVocation(uint16_t vocationId) const
173+{
174+ for (const auto& it : vocationsMap) {
175+ if (it.second.fromVocation == vocationId && it.first != vocationId) {
176+ return it.first;
177+ }
178+ }
179+ return VOCATION_NONE;
180+}
181+
182+uint32_t Vocation::skillBase[SKILL_LAST + 1] = {50, 50, 50, 50, 30, 100, 20};
183+
184+uint64_t Vocation::getReqSkillTries(uint8_t skill, uint16_t level)
185+{
186+ if (skill > SKILL_LAST) {
187+ return 0;
188+ }
189+
190+ auto it = cacheSkill[skill].find(level);
191+ if (it != cacheSkill[skill].end()) {
192+ return it->second;
193+ }
194+
195+ uint64_t tries = static_cast<uint64_t>(skillBase[skill] * std::pow(static_cast<double>(skillMultipliers[skill]), level - 11));
196+ cacheSkill[skill][level] = tries;
197+ return tries;
198+}
199+
200+uint64_t Vocation::getReqMana(uint32_t magLevel)
201+{
202+ auto it = cacheMana.find(magLevel);
203+ if (it != cacheMana.end()) {
204+ return it->second;
205+ }
206+
207+ uint64_t reqMana = std::floor<uint64_t>(1600 * std::pow<double>(manaMultiplier, static_cast<int32_t>(magLevel) - 1));
208+ cacheMana[magLevel] = reqMana;
209+ return reqMana;
210+}
A src/vocation.h +139-0 View file
@@ -0,0 +1,139 @@
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_VOCATION_H_ADCAA356C0DB44CEBA994A0D678EC92D
21+#define FS_VOCATION_H_ADCAA356C0DB44CEBA994A0D678EC92D
22+
23+#include "enums.h"
24+#include "item.h"
25+
26+class Vocation
27+{
28+ public:
29+ explicit Vocation(uint16_t id) : id(id) {}
30+
31+ const std::string& getVocName() const {
32+ return name;
33+ }
34+ const std::string& getVocDescription() const {
35+ return description;
36+ }
37+ uint64_t getReqSkillTries(uint8_t skill, uint16_t level);
38+ uint64_t getReqMana(uint32_t magLevel);
39+
40+ uint16_t getId() const {
41+ return id;
42+ }
43+
44+ uint8_t getClientId() const {
45+ return clientId;
46+ }
47+
48+ uint32_t getHPGain() const {
49+ return gainHP;
50+ }
51+ uint32_t getManaGain() const {
52+ return gainMana;
53+ }
54+ uint32_t getCapGain() const {
55+ return gainCap;
56+ }
57+
58+ uint32_t getManaGainTicks() const {
59+ return gainManaTicks;
60+ }
61+ uint32_t getManaGainAmount() const {
62+ return gainManaAmount;
63+ }
64+ uint32_t getHealthGainTicks() const {
65+ return gainHealthTicks;
66+ }
67+ uint32_t getHealthGainAmount() const {
68+ return gainHealthAmount;
69+ }
70+
71+ uint8_t getSoulMax() const {
72+ return soulMax;
73+ }
74+ uint16_t getSoulGainTicks() const {
75+ return gainSoulTicks;
76+ }
77+
78+ uint32_t getAttackSpeed() const {
79+ return attackSpeed;
80+ }
81+ uint32_t getBaseSpeed() const {
82+ return baseSpeed;
83+ }
84+
85+ uint32_t getFromVocation() const {
86+ return fromVocation;
87+ }
88+
89+ float meleeDamageMultiplier = 1.0f;
90+ float distDamageMultiplier = 1.0f;
91+ float defenseMultiplier = 1.0f;
92+ float armorMultiplier = 1.0f;
93+
94+ private:
95+ friend class Vocations;
96+
97+ std::map<uint32_t, uint64_t> cacheMana;
98+ std::map<uint32_t, uint32_t> cacheSkill[SKILL_LAST + 1];
99+
100+ std::string name = "none";
101+ std::string description;
102+
103+ float skillMultipliers[SKILL_LAST + 1] = {1.5f, 2.0f, 2.0f, 2.0f, 2.0f, 1.5f, 1.1f};
104+ float manaMultiplier = 4.0f;
105+
106+ uint32_t gainHealthTicks = 6;
107+ uint32_t gainHealthAmount = 1;
108+ uint32_t gainManaTicks = 6;
109+ uint32_t gainManaAmount = 1;
110+ uint32_t gainCap = 500;
111+ uint32_t gainMana = 5;
112+ uint32_t gainHP = 5;
113+ uint32_t fromVocation = VOCATION_NONE;
114+ uint32_t attackSpeed = 1500;
115+ uint32_t baseSpeed = 220;
116+ uint16_t id;
117+
118+ uint16_t gainSoulTicks = 120;
119+
120+ uint8_t soulMax = 100;
121+ uint8_t clientId = 0;
122+
123+ static uint32_t skillBase[SKILL_LAST + 1];
124+};
125+
126+class Vocations
127+{
128+ public:
129+ bool loadFromXml();
130+
131+ Vocation* getVocation(uint16_t id);
132+ int32_t getVocationId(const std::string& name) const;
133+ uint16_t getPromotedVocation(uint16_t vocationId) const;
134+
135+ private:
136+ std::map<uint16_t, Vocation> vocationsMap;
137+};
138+
139+#endif
A src/waitlist.cpp +149-0 View file
@@ -0,0 +1,149 @@
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+#include "otpch.h"
21+
22+#include "configmanager.h"
23+#include "game.h"
24+#include "waitlist.h"
25+
26+#include <tuple>
27+
28+extern ConfigManager g_config;
29+extern Game g_game;
30+
31+namespace {
32+
33+struct Wait
34+{
35+ constexpr Wait(int64_t timeout, uint32_t playerGUID) :
36+ timeout(timeout), playerGUID(playerGUID) {}
37+
38+ int64_t timeout;
39+ uint32_t playerGUID;
40+};
41+
42+using WaitList = std::list<Wait>;
43+
44+void cleanupList(WaitList& list)
45+{
46+ int64_t time = OTSYS_TIME();
47+
48+ auto it = list.begin(), end = list.end();
49+ while (it != end) {
50+ if ((it->timeout - time) <= 0) {
51+ it = list.erase(it);
52+ } else {
53+ ++it;
54+ }
55+ }
56+}
57+
58+int64_t getTimeout(std::size_t slot)
59+{
60+ //timeout is set to 15 seconds longer than expected retry attempt
61+ return WaitingList::getTime(slot) + 15;
62+}
63+
64+} // namespace
65+
66+struct WaitListInfo
67+{
68+ WaitList priorityWaitList;
69+ WaitList waitList;
70+
71+ std::tuple<WaitList&, WaitList::iterator, WaitList::size_type> findClient(const Player *player) {
72+ std::size_t slot = 1;
73+ for (auto it = priorityWaitList.begin(), end = priorityWaitList.end(); it != end; ++it, ++slot) {
74+ if (it->playerGUID == player->getGUID()) {
75+ return std::make_tuple(std::ref(priorityWaitList), it, slot);
76+ }
77+ }
78+
79+ for (auto it = waitList.begin(), end = waitList.end(); it != end; ++it, ++slot) {
80+ if (it->playerGUID == player->getGUID()) {
81+ return std::make_tuple(std::ref(waitList), it, slot);
82+ }
83+ }
84+ return std::make_tuple(std::ref(waitList), waitList.end(), slot);
85+ }
86+};
87+
88+WaitingList& WaitingList::getInstance()
89+{
90+ static WaitingList waitingList;
91+ return waitingList;
92+}
93+
94+uint8_t WaitingList::getTime(std::size_t slot)
95+{
96+ if (slot < 5) {
97+ return 5;
98+ } else if (slot < 10) {
99+ return 10;
100+ } else if (slot < 20) {
101+ return 20;
102+ } else if (slot < 50) {
103+ return 60;
104+ } else {
105+ return 120;
106+ }
107+}
108+
109+std::size_t WaitingList::clientLogin(const Player* player)
110+{
111+ // Currentslot = position in wait list, 0 for direct access
112+ std::size_t currentSlot = 0;
113+ if (player->hasFlag(PlayerFlag_CanAlwaysLogin) || player->getAccountType() >= ACCOUNT_TYPE_GAMEMASTER) {
114+ return currentSlot;
115+ }
116+
117+ cleanupList(info->priorityWaitList);
118+ cleanupList(info->waitList);
119+
120+ uint32_t maxPlayers = static_cast<uint32_t>(g_config.getNumber(ConfigManager::MAX_PLAYERS));
121+ if (maxPlayers == 0 || (info->priorityWaitList.empty() && info->waitList.empty() && g_game.getPlayersOnline() < maxPlayers)) {
122+ return currentSlot;
123+ }
124+
125+ auto result = info->findClient(player);
126+ if (std::get<1>(result) != std::get<0>(result).end()) {
127+ currentSlot = std::get<2>(result);
128+ // If server has capacity for this client, let him in even though his current slot might be higher than 0.
129+ if ((g_game.getPlayersOnline() + currentSlot) <= maxPlayers) {
130+ std::get<0>(result).erase(std::get<1>(result));
131+ return 0;
132+ }
133+
134+ //let them wait a bit longer
135+ std::get<1>(result)->timeout = OTSYS_TIME() + (getTimeout(currentSlot) * 1000);
136+ return currentSlot;
137+ }
138+
139+ currentSlot = info->priorityWaitList.size();
140+ if (player->isPremium()) {
141+ info->priorityWaitList.emplace_back(OTSYS_TIME() + (getTimeout(++currentSlot) * 1000), player->getGUID());
142+ } else {
143+ currentSlot += info->waitList.size();
144+ info->waitList.emplace_back(OTSYS_TIME() + (getTimeout(++currentSlot) * 1000), player->getGUID());
145+ }
146+ return currentSlot;
147+}
148+
149+WaitingList::WaitingList() : info(new WaitListInfo) {}
A src/waitlist.h +41-0 View file
@@ -0,0 +1,41 @@
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_WAITLIST_H_7E4299E552E44F10BC4F4E50BF3D7241
21+#define FS_WAITLIST_H_7E4299E552E44F10BC4F4E50BF3D7241
22+
23+#include "player.h"
24+
25+struct WaitListInfo;
26+
27+class WaitingList
28+{
29+ public:
30+ static WaitingList& getInstance();
31+
32+ std::size_t clientLogin(const Player* player);
33+ static uint8_t getTime(std::size_t slot);
34+
35+ private:
36+ WaitingList();
37+
38+ std::unique_ptr<WaitListInfo> info;
39+};
40+
41+#endif
A src/walkmatrix.h +140-0 View file
@@ -0,0 +1,140 @@
1+#pragma once
2+
3+#include <cstdint>
4+#include <string>
5+#include <sstream>
6+
7+#include "position.h"
8+
9+class WalkMatrix {
10+public:
11+
12+ void updatePosition(const Position& newPos)
13+ {
14+ int32_t xdiff = pos.x - newPos.x;
15+ int32_t ydiff = pos.y - newPos.y;
16+ if (pos.z != newPos.z || std::abs(xdiff) > 6 || std::abs(ydiff) > 6) {
17+ pos = newPos;
18+ return clear();
19+ }
20+ pos = newPos;
21+
22+ if (xdiff < 0) {
23+ for (int x = 0; x < 7; ++x) {
24+ for (int y = 0; y < 7; ++y) {
25+ if (x - xdiff > 6) {
26+ matrix[x][y] = 0;
27+ } else {
28+ matrix[x][y] = matrix[x - xdiff][y];
29+ }
30+ }
31+ }
32+ }
33+ if (xdiff > 0) {
34+ for (int x = 6; x >= 0; --x) {
35+ for (int y = 6; y >= 0; --y) {
36+ if (x - xdiff < 0) {
37+ matrix[x][y] = 0;
38+ } else {
39+ matrix[x][y] = matrix[x - xdiff][y];
40+ }
41+ }
42+ }
43+ }
44+ if (ydiff < 0) {
45+ for (int x = 0; x < 7; ++x) {
46+ for (int y = 0; y < 7; ++y) {
47+ if (y - ydiff > 6) {
48+ matrix[x][y] = 0;
49+ } else {
50+ matrix[x][y] = matrix[x][y - ydiff];
51+ }
52+ }
53+ }
54+ }
55+ if (ydiff > 0) {
56+ for (int x = 6; x >= 0; --x) {
57+ for (int y = 6; y >= 0; --y) {
58+ if (y - ydiff < 0) {
59+ matrix[x][y] = 0;
60+ } else {
61+ matrix[x][y] = matrix[x][y - ydiff];
62+ }
63+ }
64+ }
65+ }
66+ }
67+
68+ bool inRange(const Position& pos2)
69+ {
70+ if (pos.z != pos2.z) return false;
71+ int32_t xdiff = pos.x - pos2.x;
72+ int32_t ydiff = pos.y - pos2.y;
73+ if (std::abs(xdiff) > 3 || std::abs(ydiff) > 3) return false;
74+ return true;
75+ }
76+
77+ int32_t update(const Position& pos2, int32_t value = 0)
78+ {
79+ if (pos.z != pos2.z) return 0;
80+ int32_t xdiff = pos.x - pos2.x;
81+ int32_t ydiff = pos.y - pos2.y;
82+ if (std::abs(xdiff) > 3 || std::abs(ydiff) > 3) return 0;
83+ if (value != 0) {
84+ matrix[3 - xdiff][3 - ydiff] = value;
85+ return value;
86+ }
87+ counter += 1;
88+ matrix[3 - xdiff][3 - ydiff] = counter;
89+ return counter;
90+ }
91+
92+ int32_t get(const Position& pos2)
93+ {
94+ if (pos.z != pos2.z) return 0;
95+ int32_t xdiff = pos.x - pos2.x;
96+ int32_t ydiff = pos.y - pos2.y;
97+ if (std::abs(xdiff) > 3 || std::abs(ydiff) > 3) return 0;
98+ return matrix[3 - xdiff][3 - ydiff];
99+ }
100+
101+ void clear()
102+ {
103+ for (auto& x : matrix) {
104+ for (auto& y : x) {
105+ y = 0;
106+ }
107+ }
108+ }
109+
110+ uint32_t reset(uint32_t value = 0)
111+ {
112+ if (value == 0) {
113+ counter += 1;
114+ value = counter;
115+ }
116+ for (auto& x : matrix) {
117+ for (auto& y : x) {
118+ y = value;
119+ }
120+ }
121+ return value;
122+ }
123+
124+ std::string dump()
125+ {
126+ std::stringstream ss;
127+ for (int y = 0; y < 7; ++y) {
128+ for (int x = 0; x < 7; ++x) {
129+ ss << matrix[x][y] << "\t";
130+ }
131+ ss << "\n";
132+ }
133+ return ss.str();
134+ }
135+
136+private:
137+ Position pos;
138+ int32_t matrix[7][7] = { { 0 } };
139+ int32_t counter = 0;
140+};
Top