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/game.h +597-0 View file
@@ -0,0 +1,597 @@
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_GAME_H_3EC96D67DD024E6093B3BAC29B7A6D7F
21+#define FS_GAME_H_3EC96D67DD024E6093B3BAC29B7A6D7F
22+
23+#include "account.h"
24+#include "combat.h"
25+#include "groups.h"
26+#include "map.h"
27+#include "position.h"
28+#include "item.h"
29+#include "container.h"
30+#include "player.h"
31+#include "runeeffects.h"
32+#include "raids.h"
33+#include "npc.h"
34+#include "wildcardtree.h"
35+#include "quests.h"
36+#include "shaders.h"
37+
38+class ServiceManager;
39+class Creature;
40+class Monster;
41+class Npc;
42+class CombatInfo;
43+
44+enum stackPosType_t {
45+ STACKPOS_MOVE,
46+ STACKPOS_LOOK,
47+ STACKPOS_TOPDOWN_ITEM,
48+ STACKPOS_USEITEM,
49+ STACKPOS_USETARGET,
50+};
51+
52+enum WorldType_t {
53+ WORLD_TYPE_NO_PVP = 1,
54+ WORLD_TYPE_PVP = 2,
55+ WORLD_TYPE_PVP_ENFORCED = 3,
56+};
57+
58+enum GameState_t {
59+ GAME_STATE_STARTUP,
60+ GAME_STATE_INIT,
61+ GAME_STATE_NORMAL,
62+ GAME_STATE_CLOSED,
63+ GAME_STATE_SHUTDOWN,
64+ GAME_STATE_CLOSING,
65+ GAME_STATE_MAINTAIN,
66+};
67+
68+enum LightState_t {
69+ LIGHT_STATE_DAY,
70+ LIGHT_STATE_NIGHT,
71+ LIGHT_STATE_SUNSET,
72+ LIGHT_STATE_SUNRISE,
73+};
74+
75+static constexpr int32_t EVENT_LIGHTINTERVAL = 10000;
76+static constexpr int32_t EVENT_DECAYINTERVAL = 250;
77+static constexpr int32_t EVENT_DECAY_BUCKETS = 4;
78+
79+/**
80+ * Main Game class.
81+ * This class is responsible to control everything that happens
82+ */
83+
84+class Game
85+{
86+ public:
87+ Game();
88+ ~Game();
89+
90+ // non-copyable
91+ Game(const Game&) = delete;
92+ Game& operator=(const Game&) = delete;
93+
94+ void start(ServiceManager* manager);
95+
96+ void forceAddCondition(uint32_t creatureId, Condition* condition);
97+ void forceRemoveCondition(uint32_t creatureId, ConditionType_t type);
98+
99+ bool loadMainMap(const std::string& filename);
100+ void loadMap(const std::string& path);
101+
102+ /**
103+ * Get the map size - info purpose only
104+ * \param width width of the map
105+ * \param height height of the map
106+ */
107+ void getMapDimensions(uint32_t& width, uint32_t& height) const {
108+ width = map.width;
109+ height = map.height;
110+ }
111+
112+ void setWorldType(WorldType_t type);
113+ WorldType_t getWorldType() const {
114+ return worldType;
115+ }
116+
117+ Cylinder* internalGetCylinder(Player* player, const Position& pos) const;
118+ Thing* internalGetThing(Player* player, const Position& pos, int32_t index,
119+ uint32_t spriteId, stackPosType_t type) const;
120+ static void internalGetPosition(Item* item, Position& pos, uint8_t& stackpos);
121+
122+ static std::string getTradeErrorDescription(ReturnValue ret, Item* item);
123+
124+ /**
125+ * Returns a creature based on the unique creature identifier
126+ * \param id is the unique creature id to get a creature pointer to
127+ * \returns A Creature pointer to the creature
128+ */
129+ Creature* getCreatureByID(uint32_t id);
130+
131+ /**
132+ * Returns a monster based on the unique creature identifier
133+ * \param id is the unique monster id to get a monster pointer to
134+ * \returns A Monster pointer to the monster
135+ */
136+ Monster* getMonsterByID(uint32_t id);
137+
138+ /**
139+ * Returns a npc based on the unique creature identifier
140+ * \param id is the unique npc id to get a npc pointer to
141+ * \returns A NPC pointer to the npc
142+ */
143+ Npc* getNpcByID(uint32_t id);
144+
145+ /**
146+ * Returns a player based on the unique creature identifier
147+ * \param id is the unique player id to get a player pointer to
148+ * \returns A Pointer to the player
149+ */
150+ Player* getPlayerByID(uint32_t id);
151+
152+ /**
153+ * Returns a creature based on a string name identifier
154+ * \param s is the name identifier
155+ * \returns A Pointer to the creature
156+ */
157+ Creature* getCreatureByName(const std::string& s);
158+
159+ /**
160+ * Returns a npc based on a string name identifier
161+ * \param s is the name identifier
162+ * \returns A Pointer to the npc
163+ */
164+ Npc* getNpcByName(const std::string& s);
165+
166+ /**
167+ * Returns a player based on a string name identifier
168+ * \param s is the name identifier
169+ * \returns A Pointer to the player
170+ */
171+ Player* getPlayerByName(const std::string& s);
172+
173+ /**
174+ * Returns a player based on guid
175+ * \returns A Pointer to the player
176+ */
177+ Player* getPlayerByGUID(const uint32_t& guid);
178+
179+ /**
180+ * Returns a player based on a string name identifier, with support for the "~" wildcard.
181+ * \param s is the name identifier, with or without wildcard
182+ * \param player will point to the found player (if any)
183+ * \return "RETURNVALUE_PLAYERWITHTHISNAMEISNOTONLINE" or "RETURNVALUE_NAMEISTOOAMBIGIOUS"
184+ */
185+ ReturnValue getPlayerByNameWildcard(const std::string& s, Player*& player);
186+
187+ /**
188+ * Returns a player based on an account number identifier
189+ * \param acc is the account identifier
190+ * \returns A Pointer to the player
191+ */
192+ Player* getPlayerByAccount(uint32_t acc);
193+
194+ /* Place Creature on the map without sending out events to the surrounding.
195+ * \param creature Creature to place on the map
196+ * \param pos The position to place the creature
197+ * \param extendedPos If true, the creature will in first-hand be placed 2 tiles away
198+ * \param forced If true, placing the creature will not fail because of obstacles (creatures/items)
199+ */
200+ bool internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false);
201+
202+ /**
203+ * Place Creature on the map.
204+ * \param creature Creature to place on the map
205+ * \param pos The position to place the creature
206+ * \param extendedPos If true, the creature will in first-hand be placed 2 tiles away
207+ * \param force If true, placing the creature will not fail because of obstacles (creatures/items)
208+ */
209+ bool placeCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false);
210+
211+ /**
212+ * Remove Creature from the map.
213+ * Removes the Creature the map
214+ * \param c Creature to remove
215+ */
216+ bool removeCreature(Creature* creature, bool isLogout = true);
217+
218+ void addCreatureCheck(Creature* creature);
219+ static void removeCreatureCheck(Creature* creature);
220+
221+ size_t getPlayersOnline() const {
222+ return players.size();
223+ }
224+ size_t getMonstersOnline() const {
225+ return monsters.size();
226+ }
227+ size_t getNpcsOnline() const {
228+ return npcs.size();
229+ }
230+ uint32_t getPlayersRecord() const {
231+ return playersRecord;
232+ }
233+
234+ LightInfo getWorldLightInfo() const;
235+
236+ ReturnValue internalMoveCreature(Creature* creature, Direction direction, uint32_t flags = 0);
237+ ReturnValue internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags = 0);
238+
239+ ReturnValue internalMoveItem(Cylinder* fromCylinder, Cylinder* toCylinder, int32_t index,
240+ Item* item, uint32_t count, Item** _moveItem, uint32_t flags = 0, Creature* actor = nullptr, Item* tradeItem = nullptr, const Position* fromPos = nullptr, const Position* toPos = nullptr);
241+
242+ ReturnValue internalAddItem(Cylinder* toCylinder, Item* item, int32_t index = INDEX_WHEREEVER,
243+ uint32_t flags = 0, bool test = false);
244+ ReturnValue internalAddItem(Cylinder* toCylinder, Item* item, int32_t index,
245+ uint32_t flags, bool test, uint32_t& remainderCount);
246+ ReturnValue internalRemoveItem(Item* item, int32_t count = -1, bool test = false, uint32_t flags = 0);
247+
248+ ReturnValue internalPlayerAddItem(Player* player, Item* item, bool dropOnMap = true, slots_t slot = CONST_SLOT_WHEREEVER);
249+
250+ /**
251+ * Find an item of a certain type
252+ * \param cylinder to search the item
253+ * \param itemId is the item to remove
254+ * \param subType is the extra type an item can have such as charges/fluidtype, default is -1
255+ * meaning it's not used
256+ * \param depthSearch if true it will check child containers aswell
257+ * \returns A pointer to the item to an item and nullptr if not found
258+ */
259+ Item* findItemOfType(Cylinder* cylinder, uint16_t itemId,
260+ bool depthSearch = true, int32_t subType = -1) const;
261+
262+ /**
263+ * Remove/Add item(s) with a monetary value
264+ * \param cylinder to remove the money from
265+ * \param money is the amount to remove
266+ * \param flags optional flags to modifiy the default behaviour
267+ * \returns true if the removal was successful
268+ */
269+ bool removeMoney(Cylinder* cylinder, uint64_t money, uint32_t flags = 0);
270+
271+ /**
272+ * Add item(s) with monetary value
273+ * \param cylinder which will receive money
274+ * \param money the amount to give
275+ * \param flags optional flags to modify default behavior
276+ */
277+ void addMoney(Cylinder* cylinder, uint64_t money, uint32_t flags = 0);
278+
279+ /**
280+ * Transform one item to another type/count
281+ * \param item is the item to transform
282+ * \param newId is the new itemid
283+ * \param newCount is the new count value, use default value (-1) to not change it
284+ * \returns true if the tranformation was successful
285+ */
286+ Item* transformItem(Item* item, uint16_t newId, int32_t newCount = -1);
287+
288+ /**
289+ * Teleports an object to another position
290+ * \param thing is the object to teleport
291+ * \param newPos is the new position
292+ * \param pushMove force teleport if false
293+ * \param flags optional flags to modify default behavior
294+ * \returns true if the teleportation was successful
295+ */
296+ ReturnValue internalTeleport(Thing* thing, const Position& newPos, bool pushMove = true, uint32_t flags = 0);
297+
298+ /**
299+ * Turn a creature to a different direction.
300+ * \param creature Creature to change the direction
301+ * \param dir Direction to turn to
302+ */
303+ bool internalCreatureTurn(Creature* creature, Direction dir);
304+
305+ /**
306+ * Creature wants to say something.
307+ * \param creature Creature pointer
308+ * \param type Type of message
309+ * \param text The text to say
310+ */
311+ bool internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
312+ bool ghostMode, SpectatorVec* spectatorsPtr = nullptr, const Position* pos = nullptr);
313+
314+ void loadPlayersRecord();
315+ void checkPlayersRecord();
316+
317+ void sendGuildMotd(uint32_t playerId);
318+ void kickPlayer(uint32_t playerId, bool displayEffect);
319+ void playerReportBug(uint32_t playerId, const std::string& message, const Position& position, uint8_t category);
320+ void playerDebugAssert(uint32_t playerId, const std::string& assertLine, const std::string& date, const std::string& description, const std::string& comment);
321+ void playerAnswerModalWindow(uint32_t playerId, uint32_t modalWindowId, uint8_t button, uint8_t choice);
322+ void playerReportRuleViolation(uint32_t playerId, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation);
323+
324+ bool internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem);
325+ void internalCloseTrade(Player* player);
326+ bool playerBroadcastMessage(Player* player, const std::string& text) const;
327+ void broadcastMessage(const std::string& text, MessageClasses type) const;
328+
329+ //Implementation of player invoked events
330+ void playerMoveThing(uint32_t playerId, const Position& fromPos, uint16_t spriteId, uint8_t fromStackPos,
331+ const Position& toPos, uint8_t count);
332+ void playerMoveCreatureByID(uint32_t playerId, uint32_t movingCreatureId, const Position& movingCreatureOrigPos, const Position& toPos);
333+ void playerMoveCreature(Player* player, Creature* movingCreature, const Position& movingCreatureOrigPos, Tile* toTile);
334+ void playerMoveItemByPlayerID(uint32_t playerId, const Position& fromPos, uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count);
335+ void playerMoveItem(Player* player, const Position& fromPos,
336+ uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count, Item* item, Cylinder* toCylinder);
337+ void playerEquipItem(uint32_t playerId, uint16_t spriteId);
338+ void playerMove(uint32_t playerId, Direction direction);
339+ void playerCreatePrivateChannel(uint32_t playerId);
340+ void playerChannelInvite(uint32_t playerId, const std::string& name);
341+ void playerChannelExclude(uint32_t playerId, const std::string& name);
342+ void playerRequestChannels(uint32_t playerId);
343+ void playerOpenChannel(uint32_t playerId, uint16_t channelId);
344+ void playerCloseChannel(uint32_t playerId, uint16_t channelId);
345+ void playerOpenPrivateChannel(uint32_t playerId, std::string& receiver);
346+ void playerCloseNpcChannel(uint32_t playerId);
347+ void playerReceivePing(uint32_t playerId);
348+ void playerReceivePingBack(uint32_t playerId);
349+ void playerReceiveNewPing(uint32_t playerId, uint16_t ping, uint16_t fps);
350+ void playerAutoWalk(uint32_t playerId, const std::list<Direction>& listDir);
351+ void playerNewWalk(uint32_t playerId, Position pos, uint8_t flags, std::list<Direction> listDir);
352+ void playerStopAutoWalk(uint32_t playerId);
353+ void playerUseItemEx(uint32_t playerId, const Position& fromPos, uint8_t fromStackPos,
354+ uint16_t fromSpriteId, const Position& toPos, uint8_t toStackPos, uint16_t toSpriteId);
355+ void playerUseItem(uint32_t playerId, const Position& pos, uint8_t stackPos, uint8_t index, uint16_t spriteId);
356+ void playerUseWithCreature(uint32_t playerId, const Position& fromPos, uint8_t fromStackPos, uint32_t creatureId, uint16_t spriteId);
357+ void playerCloseContainer(uint32_t playerId, uint8_t cid);
358+ void playerMoveUpContainer(uint32_t playerId, uint8_t cid);
359+ void playerUpdateContainer(uint32_t playerId, uint8_t cid);
360+ void playerRotateItem(uint32_t playerId, const Position& pos, uint8_t stackPos, const uint16_t spriteId);
361+ void playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text);
362+ void playerBrowseField(uint32_t playerId, const Position& pos);
363+ void playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index);
364+ void playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text);
365+ void playerWrapItem(uint32_t playerId, const Position& position, uint8_t stackPos, const uint16_t spriteId);
366+ void playerRequestTrade(uint32_t playerId, const Position& pos, uint8_t stackPos,
367+ uint32_t tradePlayerId, uint16_t spriteId);
368+ void playerAcceptTrade(uint32_t playerId);
369+ void playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t index);
370+ void playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
371+ bool ignoreCap = false, bool inBackpacks = false);
372+ void playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count,
373+ uint8_t amount, bool ignoreEquipped = false);
374+ void playerCloseShop(uint32_t playerId);
375+ void playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count);
376+ void playerCloseTrade(uint32_t playerId);
377+ void playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId);
378+ void playerFollowCreature(uint32_t playerId, uint32_t creatureId);
379+ void playerCancelAttackAndFollow(uint32_t playerId);
380+ void playerSetFightModes(uint32_t playerId, fightMode_t fightMode, bool chaseMode, bool secureMode);
381+ void playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos);
382+ void playerLookInBattleList(uint32_t playerId, uint32_t creatureId);
383+ void playerRequestAddVip(uint32_t playerId, const std::string& name);
384+ void playerRequestRemoveVip(uint32_t playerId, uint32_t guid);
385+ void playerRequestEditVip(uint32_t playerId, uint32_t guid, const std::string& description, uint32_t icon, bool notify);
386+ void playerTurn(uint32_t playerId, Direction dir);
387+ void playerRequestOutfit(uint32_t playerId);
388+ void playerShowQuestLog(uint32_t playerId);
389+ void playerShowQuestLine(uint32_t playerId, uint16_t questId);
390+ void playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
391+ const std::string& receiver, const std::string& text);
392+ void playerChangeOutfit(uint32_t playerId, Outfit_t outfit);
393+ void playerInviteToParty(uint32_t playerId, uint32_t invitedId);
394+ void playerJoinParty(uint32_t playerId, uint32_t leaderId);
395+ void playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId);
396+ void playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId);
397+ void playerLeaveParty(uint32_t playerId);
398+ void playerEnableSharedPartyExperience(uint32_t playerId, bool sharedExpActive);
399+ void playerToggleOutfitExtension(uint32_t playerId, int mount, int wings, int aura, int shader, int runeeffect);
400+ void playerLeaveMarket(uint32_t playerId);
401+ void playerBrowseMarket(uint32_t playerId, uint16_t spriteId);
402+ void playerBrowseMarketOwnOffers(uint32_t playerId);
403+ void playerBrowseMarketOwnHistory(uint32_t playerId);
404+ void playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t spriteId, uint16_t amount, uint32_t price, bool anonymous);
405+ void playerCancelMarketOffer(uint32_t playerId, uint32_t timestamp, uint16_t counter);
406+ void playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16_t counter, uint16_t amount);
407+
408+ void parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer);
409+
410+ std::forward_list<Item*> getMarketItemList(uint16_t wareId, uint16_t sufficientCount, DepotChest* depotChest, Inbox* inbox);
411+
412+ static void updatePremium(Account& account);
413+
414+ void cleanup();
415+ void shutdown();
416+ void ReleaseCreature(Creature* creature);
417+ void ReleaseItem(Item* item);
418+
419+ bool canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight = true,
420+ int32_t rangex = Map::maxClientViewportX, int32_t rangey = Map::maxClientViewportY) const;
421+ bool isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck) const;
422+
423+ void changeSpeed(Creature* creature, int32_t varSpeedDelta);
424+ void internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit);
425+ void internalCreatureChangeVisible(Creature* creature, bool visible);
426+ void changeLight(const Creature* creature);
427+ void updateCreatureSkull(const Creature* creature);
428+ void updatePlayerShield(Player* player);
429+ void updatePlayerHelpers(const Player& player);
430+ void updateCreatureType(Creature* creature);
431+ void updateCreatureWalkthrough(const Creature* creature);
432+
433+ GameState_t getGameState() const;
434+ void setGameState(GameState_t newState);
435+ void saveGameState();
436+
437+ //Events
438+ void checkCreatureWalk(uint32_t creatureId);
439+ void updateCreatureWalk(uint32_t creatureId);
440+ void checkCreatureAttack(uint32_t creatureId);
441+ void checkCreatures(size_t index);
442+ void checkLight();
443+
444+ bool combatBlockHit(CombatDamage& damage, Creature* attacker, Creature* target, bool checkDefense, bool checkArmor, bool field);
445+
446+ void combatGetTypeInfo(CombatType_t combatType, Creature* target, TextColor_t& color, uint8_t& effect);
447+
448+ bool combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage);
449+ bool combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage);
450+
451+ //animation help functions
452+ void addCreatureHealth(const Creature* target);
453+ static void addCreatureHealth(const SpectatorVec& spectators, const Creature* target);
454+ void addMagicEffect(const Position& pos, uint16_t effect); // Cambiado de uint8_t a uint16_t
455+ static void addMagicEffect(const SpectatorVec& spectators, const Position& pos, uint16_t effect); // Cambiado de uint8_t a uint16_t
456+ void addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect);
457+ static void addDistanceEffect(const SpectatorVec& spectators, const Position& fromPos, const Position& toPos, uint8_t effect);
458+
459+ void startDecay(Item* item);
460+ int32_t getLightHour() const {
461+ return lightHour;
462+ }
463+
464+ bool loadExperienceStages();
465+ uint64_t getExperienceStage(uint32_t level);
466+
467+ void loadMotdNum();
468+ void saveMotdNum() const;
469+ const std::string& getMotdHash() const { return motdHash; }
470+ uint32_t getMotdNum() const { return motdNum; }
471+ void incrementMotdNum() { motdNum++; }
472+
473+ void sendOfflineTrainingDialog(Player* player);
474+
475+ const std::unordered_map<uint32_t, Player*>& getPlayers() const { return players; }
476+ const std::map<uint32_t, Npc*>& getNpcs() const { return npcs; }
477+
478+ void addPlayer(Player* player);
479+ void removePlayer(Player* player);
480+
481+ void addNpc(Npc* npc);
482+ void removeNpc(Npc* npc);
483+
484+ void addMonster(Monster* monster);
485+ void removeMonster(Monster* monster);
486+
487+ Guild* getGuild(uint32_t id) const;
488+ void addGuild(Guild* guild);
489+ void removeGuild(uint32_t guildId);
490+ void decreaseBrowseFieldRef(const Position& pos);
491+
492+ std::unordered_map<Tile*, Container*> browseFields;
493+
494+ void internalRemoveItems(std::vector<Item*> itemList, uint32_t amount, bool stackable);
495+
496+ BedItem* getBedBySleeper(uint32_t guid) const;
497+ void setBedSleeper(BedItem* bed, uint32_t guid);
498+ void removeBedSleeper(uint32_t guid);
499+
500+ Item* getUniqueItem(uint16_t uniqueId);
501+ bool addUniqueItem(uint16_t uniqueId, Item* item);
502+ void removeUniqueItem(uint16_t uniqueId);
503+
504+ bool reload(ReloadTypes_t reloadType);
505+
506+ Auras auras;
507+ Groups groups;
508+ Map map;
509+ Mounts mounts;
510+ Raids raids;
511+ RuneEffects runeEffects;
512+ Quests quests;
513+ Wings wings;
514+ Shaders shaders;
515+
516+ std::forward_list<Item*> toDecayItems;
517+
518+ std::unordered_set<Tile*> getTilesToClean() const {
519+ return tilesToClean;
520+ }
521+ void addTileToClean(Tile* tile) {
522+ tilesToClean.emplace(tile);
523+ }
524+ void removeTileToClean(Tile* tile) {
525+ tilesToClean.erase(tile);
526+ }
527+ void clearTilesToClean() {
528+ tilesToClean.clear();
529+ }
530+
531+ private:
532+ bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
533+ void playerWhisper(Player* player, const std::string& text);
534+ bool playerYell(Player* player, const std::string& text);
535+ bool playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver, const std::string& text);
536+ void playerSpeakToNpc(Player* player, const std::string& text);
537+
538+ void checkDecay();
539+ void internalDecayItem(Item* item);
540+
541+ std::unordered_map<uint32_t, Player*> players;
542+ std::unordered_map<std::string, Player*> mappedPlayerNames;
543+ std::unordered_map<uint32_t, Player*> mappedPlayerGuids;
544+ std::unordered_map<uint32_t, Guild*> guilds;
545+ std::unordered_map<uint16_t, Item*> uniqueItems;
546+ std::map<uint32_t, uint32_t> stages;
547+
548+ std::list<Item*> decayItems[EVENT_DECAY_BUCKETS];
549+ std::list<Creature*> checkCreatureLists[EVENT_CREATURECOUNT];
550+
551+ std::vector<Creature*> ToReleaseCreatures;
552+ std::vector<Item*> ToReleaseItems;
553+
554+ size_t lastBucket = 0;
555+
556+ WildcardTreeNode wildcardTree { false };
557+
558+ std::map<uint32_t, Npc*> npcs;
559+ std::map<uint32_t, Monster*> monsters;
560+
561+ //list of items that are in trading state, mapped to the player
562+ std::map<Item*, uint32_t> tradeItems;
563+
564+ std::map<uint32_t, BedItem*> bedSleepersMap;
565+
566+ std::unordered_set<Tile*> tilesToClean;
567+
568+ ModalWindow offlineTrainingWindow { std::numeric_limits<uint32_t>::max(), "Choose a Skill", "Please choose a skill:" };
569+
570+ static constexpr int32_t LIGHT_LEVEL_DAY = 250;
571+ static constexpr int32_t LIGHT_LEVEL_NIGHT = 40;
572+ static constexpr int32_t SUNSET = 1305;
573+ static constexpr int32_t SUNRISE = 430;
574+
575+ GameState_t gameState = GAME_STATE_NORMAL;
576+ WorldType_t worldType = WORLD_TYPE_PVP;
577+
578+ LightState_t lightState = LIGHT_STATE_DAY;
579+ uint8_t lightLevel = LIGHT_LEVEL_DAY;
580+ int32_t lightHour = SUNRISE + (SUNSET - SUNRISE) / 2;
581+ // (1440 minutes/day)/(3600 seconds/day)*10 seconds event interval
582+ int32_t lightHourDelta = 1400 * 10 / 3600;
583+
584+ ServiceManager* serviceManager = nullptr;
585+
586+ void updatePlayersRecord() const;
587+ uint32_t playersRecord = 0;
588+
589+ std::string motdHash;
590+ uint32_t motdNum = 0;
591+
592+ uint32_t lastStageLevel = 0;
593+ bool stagesEnabled = false;
594+ bool useLastStageLevel = false;
595+};
596+
597+#endif
A src/globalevent.cpp +371-0 View file
@@ -0,0 +1,371 @@
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 "globalevent.h"
24+#include "tools.h"
25+#include "scheduler.h"
26+#include "pugicast.h"
27+
28+extern ConfigManager g_config;
29+
30+GlobalEvents::GlobalEvents() :
31+ scriptInterface("GlobalEvent Interface")
32+{
33+ scriptInterface.initState();
34+}
35+
36+GlobalEvents::~GlobalEvents()
37+{
38+ clear(false);
39+}
40+
41+void GlobalEvents::clearMap(GlobalEventMap& map, bool fromLua)
42+{
43+ for (auto it = map.begin(); it != map.end(); ) {
44+ if (fromLua == it->second.fromLua) {
45+ it = map.erase(it);
46+ } else {
47+ ++it;
48+ }
49+ }
50+}
51+
52+void GlobalEvents::clear(bool fromLua)
53+{
54+ g_scheduler.stopEvent(thinkEventId);
55+ thinkEventId = 0;
56+ g_scheduler.stopEvent(timerEventId);
57+ timerEventId = 0;
58+
59+ clearMap(thinkMap, fromLua);
60+ clearMap(serverMap, fromLua);
61+ clearMap(timerMap, fromLua);
62+
63+ reInitState(fromLua);
64+}
65+
66+Event_ptr GlobalEvents::getEvent(const std::string& nodeName)
67+{
68+ if (strcasecmp(nodeName.c_str(), "globalevent") != 0) {
69+ return nullptr;
70+ }
71+ return Event_ptr(new GlobalEvent(&scriptInterface));
72+}
73+
74+bool GlobalEvents::registerEvent(Event_ptr event, const pugi::xml_node&)
75+{
76+ GlobalEvent_ptr globalEvent{static_cast<GlobalEvent*>(event.release())}; //event is guaranteed to be a GlobalEvent
77+ if (globalEvent->getEventType() == GLOBALEVENT_TIMER) {
78+ auto result = timerMap.emplace(globalEvent->getName(), std::move(*globalEvent));
79+ if (result.second) {
80+ if (timerEventId == 0) {
81+ timerEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::timer, this)));
82+ }
83+ return true;
84+ }
85+ } else if (globalEvent->getEventType() != GLOBALEVENT_NONE) {
86+ auto result = serverMap.emplace(globalEvent->getName(), std::move(*globalEvent));
87+ if (result.second) {
88+ return true;
89+ }
90+ } else { // think event
91+ auto result = thinkMap.emplace(globalEvent->getName(), std::move(*globalEvent));
92+ if (result.second) {
93+ if (thinkEventId == 0) {
94+ thinkEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::think, this)));
95+ }
96+ return true;
97+ }
98+ }
99+
100+ std::cout << "[Warning - GlobalEvents::configureEvent] Duplicate registered globalevent with name: " << globalEvent->getName() << std::endl;
101+ return false;
102+}
103+
104+bool GlobalEvents::registerLuaEvent(GlobalEvent* event)
105+{
106+ GlobalEvent_ptr globalEvent{ event };
107+ if (globalEvent->getEventType() == GLOBALEVENT_TIMER) {
108+ auto result = timerMap.emplace(globalEvent->getName(), std::move(*globalEvent));
109+ if (result.second) {
110+ if (timerEventId == 0) {
111+ timerEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::timer, this)));
112+ }
113+ return true;
114+ }
115+ } else if (globalEvent->getEventType() != GLOBALEVENT_NONE) {
116+ auto result = serverMap.emplace(globalEvent->getName(), std::move(*globalEvent));
117+ if (result.second) {
118+ return true;
119+ }
120+ } else { // think event
121+ auto result = thinkMap.emplace(globalEvent->getName(), std::move(*globalEvent));
122+ if (result.second) {
123+ if (thinkEventId == 0) {
124+ thinkEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::think, this)));
125+ }
126+ return true;
127+ }
128+ }
129+
130+ std::cout << "[Warning - GlobalEvents::configureEvent] Duplicate registered globalevent with name: " << globalEvent->getName() << std::endl;
131+ return false;
132+}
133+
134+void GlobalEvents::startup() const
135+{
136+ execute(GLOBALEVENT_STARTUP);
137+}
138+
139+void GlobalEvents::timer()
140+{
141+ time_t now = time(nullptr);
142+
143+ int64_t nextScheduledTime = std::numeric_limits<int64_t>::max();
144+
145+ auto it = timerMap.begin();
146+ while (it != timerMap.end()) {
147+ GlobalEvent& globalEvent = it->second;
148+
149+ int64_t nextExecutionTime = globalEvent.getNextExecution() - now;
150+ if (nextExecutionTime > 0) {
151+ if (nextExecutionTime < nextScheduledTime) {
152+ nextScheduledTime = nextExecutionTime;
153+ }
154+
155+ ++it;
156+ continue;
157+ }
158+
159+ if (!globalEvent.executeEvent()) {
160+ it = timerMap.erase(it);
161+ continue;
162+ }
163+
164+ nextExecutionTime = 86400;
165+ if (nextExecutionTime < nextScheduledTime) {
166+ nextScheduledTime = nextExecutionTime;
167+ }
168+
169+ globalEvent.setNextExecution(globalEvent.getNextExecution() + nextExecutionTime);
170+
171+ ++it;
172+ }
173+
174+ if (nextScheduledTime != std::numeric_limits<int64_t>::max()) {
175+ timerEventId = g_scheduler.addEvent(createSchedulerTask(std::max<int64_t>(1000, nextScheduledTime * 1000),
176+ std::bind(&GlobalEvents::timer, this)));
177+ }
178+}
179+
180+void GlobalEvents::think()
181+{
182+ int64_t now = OTSYS_TIME();
183+
184+ int64_t nextScheduledTime = std::numeric_limits<int64_t>::max();
185+ for (auto& it : thinkMap) {
186+ GlobalEvent& globalEvent = it.second;
187+
188+ int64_t nextExecutionTime = globalEvent.getNextExecution() - now;
189+ if (nextExecutionTime > 0) {
190+ if (nextExecutionTime < nextScheduledTime) {
191+ nextScheduledTime = nextExecutionTime;
192+ }
193+ continue;
194+ }
195+
196+ if (!globalEvent.executeEvent()) {
197+ std::cout << "[Error - GlobalEvents::think] Failed to execute event: " << globalEvent.getName() << std::endl;
198+ }
199+
200+ nextExecutionTime = globalEvent.getInterval();
201+ if (nextExecutionTime < nextScheduledTime) {
202+ nextScheduledTime = nextExecutionTime;
203+ }
204+
205+ globalEvent.setNextExecution(globalEvent.getNextExecution() + nextExecutionTime);
206+ }
207+
208+ if (nextScheduledTime != std::numeric_limits<int64_t>::max()) {
209+ thinkEventId = g_scheduler.addEvent(createSchedulerTask(nextScheduledTime, std::bind(&GlobalEvents::think, this)));
210+ }
211+}
212+
213+void GlobalEvents::execute(GlobalEvent_t type) const
214+{
215+ for (const auto& it : serverMap) {
216+ const GlobalEvent& globalEvent = it.second;
217+ if (globalEvent.getEventType() == type) {
218+ globalEvent.executeEvent();
219+ }
220+ }
221+}
222+
223+GlobalEventMap GlobalEvents::getEventMap(GlobalEvent_t type)
224+{
225+ // TODO: This should be better implemented. Maybe have a map for every type.
226+ switch (type) {
227+ case GLOBALEVENT_NONE: return thinkMap;
228+ case GLOBALEVENT_TIMER: return timerMap;
229+ case GLOBALEVENT_STARTUP:
230+ case GLOBALEVENT_SHUTDOWN:
231+ case GLOBALEVENT_RECORD: {
232+ GlobalEventMap retMap;
233+ for (const auto& it : serverMap) {
234+ if (it.second.getEventType() == type) {
235+ retMap.emplace(it.first, it.second);
236+ }
237+ }
238+ return retMap;
239+ }
240+ default: return GlobalEventMap();
241+ }
242+}
243+
244+GlobalEvent::GlobalEvent(LuaScriptInterface* interface) : Event(interface) {}
245+
246+bool GlobalEvent::configureEvent(const pugi::xml_node& node)
247+{
248+ pugi::xml_attribute nameAttribute = node.attribute("name");
249+ if (!nameAttribute) {
250+ std::cout << "[Error - GlobalEvent::configureEvent] Missing name for a globalevent" << std::endl;
251+ return false;
252+ }
253+
254+ name = nameAttribute.as_string();
255+ eventType = GLOBALEVENT_NONE;
256+
257+ pugi::xml_attribute attr;
258+ if ((attr = node.attribute("time"))) {
259+ std::vector<int32_t> params = vectorAtoi(explodeString(attr.as_string(), ":"));
260+
261+ int32_t hour = params.front();
262+ if (hour < 0 || hour > 23) {
263+ std::cout << "[Error - GlobalEvent::configureEvent] Invalid hour \"" << attr.as_string() << "\" for globalevent with name: " << name << std::endl;
264+ return false;
265+ }
266+
267+ interval |= hour << 16;
268+
269+ int32_t min = 0;
270+ int32_t sec = 0;
271+ if (params.size() > 1) {
272+ min = params[1];
273+ if (min < 0 || min > 59) {
274+ std::cout << "[Error - GlobalEvent::configureEvent] Invalid minute \"" << attr.as_string() << "\" for globalevent with name: " << name << std::endl;
275+ return false;
276+ }
277+
278+ if (params.size() > 2) {
279+ sec = params[2];
280+ if (sec < 0 || sec > 59) {
281+ std::cout << "[Error - GlobalEvent::configureEvent] Invalid second \"" << attr.as_string() << "\" for globalevent with name: " << name << std::endl;
282+ return false;
283+ }
284+ }
285+ }
286+
287+ time_t current_time = time(nullptr);
288+ tm* timeinfo = localtime(&current_time);
289+ timeinfo->tm_hour = hour;
290+ timeinfo->tm_min = min;
291+ timeinfo->tm_sec = sec;
292+
293+ time_t difference = static_cast<time_t>(difftime(mktime(timeinfo), current_time));
294+ if (difference < 0) {
295+ difference += 86400;
296+ }
297+
298+ nextExecution = current_time + difference;
299+ eventType = GLOBALEVENT_TIMER;
300+ } else if ((attr = node.attribute("type"))) {
301+ const char* value = attr.value();
302+ if (strcasecmp(value, "startup") == 0) {
303+ eventType = GLOBALEVENT_STARTUP;
304+ } else if (strcasecmp(value, "shutdown") == 0) {
305+ eventType = GLOBALEVENT_SHUTDOWN;
306+ } else if (strcasecmp(value, "record") == 0) {
307+ eventType = GLOBALEVENT_RECORD;
308+ } else {
309+ std::cout << "[Error - GlobalEvent::configureEvent] No valid type \"" << attr.as_string() << "\" for globalevent with name " << name << std::endl;
310+ return false;
311+ }
312+ } else if ((attr = node.attribute("interval"))) {
313+ interval = std::max<int32_t>(SCHEDULER_MINTICKS, pugi::cast<int32_t>(attr.value()));
314+ nextExecution = OTSYS_TIME() + interval;
315+ } else {
316+ std::cout << "[Error - GlobalEvent::configureEvent] No interval for globalevent with name " << name << std::endl;
317+ return false;
318+ }
319+ return true;
320+}
321+
322+std::string GlobalEvent::getScriptEventName() const
323+{
324+ switch (eventType) {
325+ case GLOBALEVENT_STARTUP: return "onStartup";
326+ case GLOBALEVENT_SHUTDOWN: return "onShutdown";
327+ case GLOBALEVENT_RECORD: return "onRecord";
328+ case GLOBALEVENT_TIMER: return "onTime";
329+ default: return "onThink";
330+ }
331+}
332+
333+bool GlobalEvent::executeRecord(uint32_t current, uint32_t old)
334+{
335+ //onRecord(current, old)
336+ if (!scriptInterface->reserveScriptEnv()) {
337+ std::cout << "[Error - GlobalEvent::executeRecord] Call stack overflow" << std::endl;
338+ return false;
339+ }
340+
341+ ScriptEnvironment* env = scriptInterface->getScriptEnv();
342+ env->setScriptId(scriptId, scriptInterface);
343+
344+ lua_State* L = scriptInterface->getLuaState();
345+ scriptInterface->pushFunction(scriptId);
346+
347+ lua_pushnumber(L, current);
348+ lua_pushnumber(L, old);
349+ return scriptInterface->callFunction(2);
350+}
351+
352+bool GlobalEvent::executeEvent() const
353+{
354+ if (!scriptInterface->reserveScriptEnv()) {
355+ std::cout << "[Error - GlobalEvent::executeEvent] Call stack overflow" << std::endl;
356+ return false;
357+ }
358+
359+ ScriptEnvironment* env = scriptInterface->getScriptEnv();
360+ env->setScriptId(scriptId, scriptInterface);
361+ lua_State* L = scriptInterface->getLuaState();
362+ scriptInterface->pushFunction(scriptId);
363+
364+ int32_t params = 0;
365+ if (eventType == GLOBALEVENT_NONE || eventType == GLOBALEVENT_TIMER) {
366+ lua_pushnumber(L, interval);
367+ params = 1;
368+ }
369+
370+ return scriptInterface->callFunction(params);
371+}
A src/globalevent.h +126-0 View file
@@ -0,0 +1,126 @@
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_GLOBALEVENT_H_B3FB9B848EA3474B9AFC326873947E3C
21+#define FS_GLOBALEVENT_H_B3FB9B848EA3474B9AFC326873947E3C
22+#include "baseevents.h"
23+
24+#include "const.h"
25+
26+enum GlobalEvent_t {
27+ GLOBALEVENT_NONE,
28+ GLOBALEVENT_TIMER,
29+
30+ GLOBALEVENT_STARTUP,
31+ GLOBALEVENT_SHUTDOWN,
32+ GLOBALEVENT_RECORD,
33+};
34+
35+class GlobalEvent;
36+using GlobalEvent_ptr = std::unique_ptr<GlobalEvent>;
37+using GlobalEventMap = std::map<std::string, GlobalEvent>;
38+
39+class GlobalEvents final : public BaseEvents
40+{
41+ public:
42+ GlobalEvents();
43+ ~GlobalEvents();
44+
45+ // non-copyable
46+ GlobalEvents(const GlobalEvents&) = delete;
47+ GlobalEvents& operator=(const GlobalEvents&) = delete;
48+
49+ void startup() const;
50+
51+ void timer();
52+ void think();
53+ void execute(GlobalEvent_t type) const;
54+
55+ GlobalEventMap getEventMap(GlobalEvent_t type);
56+ static void clearMap(GlobalEventMap& map, bool fromLua);
57+
58+ bool registerLuaEvent(GlobalEvent* event);
59+ void clear(bool fromLua) override final;
60+
61+ private:
62+ std::string getScriptBaseName() const override {
63+ return "globalevents";
64+ }
65+
66+ Event_ptr getEvent(const std::string& nodeName) override;
67+ bool registerEvent(Event_ptr event, const pugi::xml_node& node) override;
68+
69+ LuaScriptInterface& getScriptInterface() override {
70+ return scriptInterface;
71+ }
72+ LuaScriptInterface scriptInterface;
73+
74+ GlobalEventMap thinkMap, serverMap, timerMap;
75+ int32_t thinkEventId = 0, timerEventId = 0;
76+};
77+
78+class GlobalEvent final : public Event
79+{
80+ public:
81+ explicit GlobalEvent(LuaScriptInterface* interface);
82+
83+ bool configureEvent(const pugi::xml_node& node) override;
84+
85+ bool executeRecord(uint32_t current, uint32_t old);
86+ bool executeEvent() const;
87+
88+ GlobalEvent_t getEventType() const {
89+ return eventType;
90+ }
91+ void setEventType(GlobalEvent_t type) {
92+ eventType = type;
93+ }
94+
95+ const std::string& getName() const {
96+ return name;
97+ }
98+ void setName(std::string eventName) {
99+ name = eventName;
100+ }
101+
102+ uint32_t getInterval() const {
103+ return interval;
104+ }
105+ void setInterval(uint32_t eventInterval) {
106+ interval |= eventInterval;
107+ }
108+
109+ int64_t getNextExecution() const {
110+ return nextExecution;
111+ }
112+ void setNextExecution(int64_t time) {
113+ nextExecution = time;
114+ }
115+
116+ private:
117+ GlobalEvent_t eventType = GLOBALEVENT_NONE;
118+
119+ std::string getScriptEventName() const override;
120+
121+ std::string name;
122+ int64_t nextExecution = 0;
123+ uint32_t interval = 0;
124+};
125+
126+#endif
A src/groups.cpp +112-0 View file
@@ -0,0 +1,112 @@
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 "groups.h"
23+
24+#include "pugicast.h"
25+#include "tools.h"
26+
27+const std::unordered_map<std::string, PlayerFlags> ParsePlayerFlagMap = {
28+ {"cannotusecombat", PlayerFlag_CannotUseCombat},
29+ {"cannotattackplayer", PlayerFlag_CannotAttackPlayer},
30+ {"cannotattackmonster", PlayerFlag_CannotAttackMonster},
31+ {"cannotbeattacked", PlayerFlag_CannotBeAttacked},
32+ {"canconvinceall", PlayerFlag_CanConvinceAll},
33+ {"cansummonall", PlayerFlag_CanSummonAll},
34+ {"canillusionall", PlayerFlag_CanIllusionAll},
35+ {"cansenseinvisibility", PlayerFlag_CanSenseInvisibility},
36+ {"ignoredbymonsters", PlayerFlag_IgnoredByMonsters},
37+ {"notgaininfight", PlayerFlag_NotGainInFight},
38+ {"hasinfinitemana", PlayerFlag_HasInfiniteMana},
39+ {"hasinfinitesoul", PlayerFlag_HasInfiniteSoul},
40+ {"hasnoexhaustion", PlayerFlag_HasNoExhaustion},
41+ {"cannotusespells", PlayerFlag_CannotUseSpells},
42+ {"cannotpickupitem", PlayerFlag_CannotPickupItem},
43+ {"canalwayslogin", PlayerFlag_CanAlwaysLogin},
44+ {"canbroadcast", PlayerFlag_CanBroadcast},
45+ {"canedithouses", PlayerFlag_CanEditHouses},
46+ {"cannotbebanned", PlayerFlag_CannotBeBanned},
47+ {"cannotbepushed", PlayerFlag_CannotBePushed},
48+ {"hasinfinitecapacity", PlayerFlag_HasInfiniteCapacity},
49+ {"cannotpushallcreatures", PlayerFlag_CanPushAllCreatures},
50+ {"cantalkredprivate", PlayerFlag_CanTalkRedPrivate},
51+ {"cantalkredchannel", PlayerFlag_CanTalkRedChannel},
52+ {"talkorangehelpchannel", PlayerFlag_TalkOrangeHelpChannel},
53+ {"notgainexperience", PlayerFlag_NotGainExperience},
54+ {"notgainmana", PlayerFlag_NotGainMana},
55+ {"notgainhealth", PlayerFlag_NotGainHealth},
56+ {"notgainskill", PlayerFlag_NotGainSkill},
57+ {"setmaxspeed", PlayerFlag_SetMaxSpeed},
58+ {"specialvip", PlayerFlag_SpecialVIP},
59+ {"notgenerateloot", PlayerFlag_NotGenerateLoot},
60+ {"cantalkredchannelanonymous", PlayerFlag_CanTalkRedChannelAnonymous},
61+ {"ignoreprotectionzone", PlayerFlag_IgnoreProtectionZone},
62+ {"ignorespellcheck", PlayerFlag_IgnoreSpellCheck},
63+ {"ignoreweaponcheck", PlayerFlag_IgnoreWeaponCheck},
64+ {"cannotbemuted", PlayerFlag_CannotBeMuted},
65+ {"isalwayspremium", PlayerFlag_IsAlwaysPremium}
66+};
67+
68+bool Groups::load()
69+{
70+ pugi::xml_document doc;
71+ pugi::xml_parse_result result = doc.load_file("data/XML/groups.xml");
72+ if (!result) {
73+ printXMLError("Error - Groups::load", "data/XML/groups.xml", result);
74+ return false;
75+ }
76+
77+ for (auto groupNode : doc.child("groups").children()) {
78+ Group group;
79+ group.id = pugi::cast<uint32_t>(groupNode.attribute("id").value());
80+ group.name = groupNode.attribute("name").as_string();
81+ group.access = groupNode.attribute("access").as_bool();
82+ group.maxDepotItems = pugi::cast<uint32_t>(groupNode.attribute("maxdepotitems").value());
83+ group.maxVipEntries = pugi::cast<uint32_t>(groupNode.attribute("maxvipentries").value());
84+ group.flags = pugi::cast<uint64_t>(groupNode.attribute("flags").value());
85+ if (pugi::xml_node node = groupNode.child("flags")) {
86+ for (auto flagNode : node.children()) {
87+ pugi::xml_attribute attr = flagNode.first_attribute();
88+ if (!attr || (attr && !attr.as_bool())) {
89+ continue;
90+ }
91+
92+ auto parseFlag = ParsePlayerFlagMap.find(attr.name());
93+ if (parseFlag != ParsePlayerFlagMap.end()) {
94+ group.flags |= parseFlag->second;
95+ }
96+ }
97+ }
98+
99+ groups.push_back(group);
100+ }
101+ return true;
102+}
103+
104+Group* Groups::getGroup(uint16_t id)
105+{
106+ for (Group& group : groups) {
107+ if (group.id == id) {
108+ return &group;
109+ }
110+ }
111+ return nullptr;
112+}
A src/groups.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_GROUPS_H_EE39438337D148E1983FB79D936DD8F3
21+#define FS_GROUPS_H_EE39438337D148E1983FB79D936DD8F3
22+
23+struct Group {
24+ std::string name;
25+ uint64_t flags;
26+ uint32_t maxDepotItems;
27+ uint32_t maxVipEntries;
28+ uint16_t id;
29+ bool access;
30+};
31+
32+class Groups {
33+ public:
34+ bool load();
35+ Group* getGroup(uint16_t id);
36+
37+ private:
38+ std::vector<Group> groups;
39+};
40+
41+#endif
A src/guild.cpp +83-0 View file
@@ -0,0 +1,83 @@
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 "guild.h"
23+
24+#include "game.h"
25+
26+extern Game g_game;
27+
28+void Guild::addMember(Player* player)
29+{
30+ membersOnline.push_back(player);
31+ for (Player* member : membersOnline) {
32+ g_game.updatePlayerHelpers(*member);
33+ }
34+}
35+
36+void Guild::removeMember(Player* player)
37+{
38+ membersOnline.remove(player);
39+ for (Player* member : membersOnline) {
40+ g_game.updatePlayerHelpers(*member);
41+ }
42+ g_game.updatePlayerHelpers(*player);
43+
44+ if (membersOnline.empty()) {
45+ g_game.removeGuild(id);
46+ delete this;
47+ }
48+}
49+
50+GuildRank_ptr Guild::getRankById(uint32_t rankId)
51+{
52+ for (auto rank : ranks) {
53+ if (rank->id == rankId) {
54+ return rank;
55+ }
56+ }
57+ return nullptr;
58+}
59+
60+GuildRank_ptr Guild::getRankByName(const std::string& name) const
61+{
62+ for (auto rank : ranks) {
63+ if (rank->name == name) {
64+ return rank;
65+ }
66+ }
67+ return nullptr;
68+}
69+
70+GuildRank_ptr Guild::getRankByLevel(uint8_t level) const
71+{
72+ for (auto rank : ranks) {
73+ if (rank->level == level) {
74+ return rank;
75+ }
76+ }
77+ return nullptr;
78+}
79+
80+void Guild::addRank(uint32_t rankId, const std::string& rankName, uint8_t level)
81+{
82+ ranks.emplace_back(std::make_shared<GuildRank>(rankId, rankName, level));
83+}
A src/guild.h +84-0 View file
@@ -0,0 +1,84 @@
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_GUILD_H_C00F0A1D732E4BA88FF62ACBE74D76BC
21+#define FS_GUILD_H_C00F0A1D732E4BA88FF62ACBE74D76BC
22+
23+class Player;
24+
25+struct GuildRank {
26+ uint32_t id;
27+ std::string name;
28+ uint8_t level;
29+
30+ GuildRank(uint32_t id, std::string name, uint8_t level) :
31+ id(id), name(std::move(name)), level(level) {}
32+};
33+
34+using GuildRank_ptr = std::shared_ptr<GuildRank>;
35+
36+class Guild
37+{
38+ public:
39+ Guild(uint32_t id, std::string name) : name(std::move(name)), id(id) {}
40+
41+ void addMember(Player* player);
42+ void removeMember(Player* player);
43+
44+ uint32_t getId() const {
45+ return id;
46+ }
47+ const std::string& getName() const {
48+ return name;
49+ }
50+ const std::list<Player*>& getMembersOnline() const {
51+ return membersOnline;
52+ }
53+ uint32_t getMemberCount() const {
54+ return memberCount;
55+ }
56+ void setMemberCount(uint32_t count) {
57+ memberCount = count;
58+ }
59+
60+ const std::vector<GuildRank_ptr>& getRanks() const {
61+ return ranks;
62+ }
63+ GuildRank_ptr getRankById(uint32_t rankId);
64+ GuildRank_ptr getRankByName(const std::string& name) const;
65+ GuildRank_ptr getRankByLevel(uint8_t level) const;
66+ void addRank(uint32_t rankId, const std::string& rankName, uint8_t level);
67+
68+ const std::string& getMotd() const {
69+ return motd;
70+ }
71+ void setMotd(const std::string& motd) {
72+ this->motd = motd;
73+ }
74+
75+ private:
76+ std::list<Player*> membersOnline;
77+ std::vector<GuildRank_ptr> ranks;
78+ std::string name;
79+ std::string motd;
80+ uint32_t id;
81+ uint32_t memberCount = 0;
82+};
83+
84+#endif
A src/house.h +315-0 View file
@@ -0,0 +1,315 @@
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_HOUSE_H_EB9732E7771A438F9CD0EFA8CB4C58C4
21+#define FS_HOUSE_H_EB9732E7771A438F9CD0EFA8CB4C58C4
22+
23+#include <set>
24+#include <unordered_set>
25+
26+#include "container.h"
27+#include "housetile.h"
28+#include "position.h"
29+
30+class House;
31+class BedItem;
32+class Player;
33+
34+class AccessList
35+{
36+ public:
37+ void parseList(const std::string& list);
38+ void addPlayer(const std::string& name);
39+ void addGuild(const std::string& name);
40+ void addGuildRank(const std::string& name, const std::string& rankName);
41+
42+ bool isInList(const Player* player);
43+
44+ void getList(std::string& list) const;
45+
46+ private:
47+ std::string list;
48+ std::unordered_set<uint32_t> playerList;
49+ std::unordered_set<uint32_t> guildRankList;
50+ bool allowEveryone = false;
51+};
52+
53+class Door final : public Item
54+{
55+ public:
56+ explicit Door(uint16_t type);
57+
58+ // non-copyable
59+ Door(const Door&) = delete;
60+ Door& operator=(const Door&) = delete;
61+
62+ Door* getDoor() override {
63+ return this;
64+ }
65+ const Door* getDoor() const override {
66+ return this;
67+ }
68+
69+ House* getHouse() {
70+ return house;
71+ }
72+
73+ //serialization
74+ Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
75+ void serializeAttr(PropWriteStream&) const override {}
76+
77+ void setDoorId(uint32_t doorId) {
78+ setIntAttr(ITEM_ATTRIBUTE_DOORID, doorId);
79+ }
80+ uint32_t getDoorId() const {
81+ return getIntAttr(ITEM_ATTRIBUTE_DOORID);
82+ }
83+
84+ bool canUse(const Player* player);
85+
86+ void setAccessList(const std::string& textlist);
87+ bool getAccessList(std::string& list) const;
88+
89+ void onRemoved() override;
90+
91+ private:
92+ void setHouse(House* house);
93+
94+ House* house = nullptr;
95+ std::unique_ptr<AccessList> accessList;
96+ friend class House;
97+};
98+
99+enum AccessList_t {
100+ GUEST_LIST = 0x100,
101+ SUBOWNER_LIST = 0x101,
102+};
103+
104+enum AccessHouseLevel_t {
105+ HOUSE_NOT_INVITED = 0,
106+ HOUSE_GUEST = 1,
107+ HOUSE_SUBOWNER = 2,
108+ HOUSE_OWNER = 3,
109+};
110+
111+using HouseTileList = std::list<HouseTile*>;
112+using HouseBedItemList = std::list<BedItem*>;
113+
114+class HouseTransferItem final : public Item
115+{
116+ public:
117+ static HouseTransferItem* createHouseTransferItem(House* house);
118+
119+ explicit HouseTransferItem(House* house) : Item(0), house(house) {}
120+
121+ void onTradeEvent(TradeEvents_t event, Player* owner) override;
122+ bool canTransform() const override {
123+ return false;
124+ }
125+
126+ private:
127+ House* house;
128+};
129+
130+class House
131+{
132+ public:
133+ explicit House(uint32_t houseId);
134+
135+ void addTile(HouseTile* tile);
136+ void updateDoorDescription() const;
137+
138+ bool canEditAccessList(uint32_t listId, const Player* player);
139+ // listId special values:
140+ // GUEST_LIST guest list
141+ // SUBOWNER_LIST subowner list
142+ void setAccessList(uint32_t listId, const std::string& textlist);
143+ bool getAccessList(uint32_t listId, std::string& list) const;
144+
145+ bool isInvited(const Player* player);
146+
147+ AccessHouseLevel_t getHouseAccessLevel(const Player* player);
148+ bool kickPlayer(Player* player, Player* target);
149+
150+ void setEntryPos(Position pos) {
151+ posEntry = pos;
152+ }
153+ const Position& getEntryPosition() const {
154+ return posEntry;
155+ }
156+
157+ void setName(std::string houseName) {
158+ this->houseName = houseName;
159+ }
160+ const std::string& getName() const {
161+ return houseName;
162+ }
163+
164+ void setOwner(uint32_t guid, bool updateDatabase = true, Player* player = nullptr);
165+ uint32_t getOwner() const {
166+ return owner;
167+ }
168+
169+ void setPaidUntil(time_t paid) {
170+ paidUntil = paid;
171+ }
172+ time_t getPaidUntil() const {
173+ return paidUntil;
174+ }
175+
176+ void setRent(uint32_t rent) {
177+ this->rent = rent;
178+ }
179+ uint32_t getRent() const {
180+ return rent;
181+ }
182+
183+ void setPayRentWarnings(uint32_t warnings) {
184+ rentWarnings = warnings;
185+ }
186+ uint32_t getPayRentWarnings() const {
187+ return rentWarnings;
188+ }
189+
190+ void setTownId(uint32_t townId) {
191+ this->townId = townId;
192+ }
193+ uint32_t getTownId() const {
194+ return townId;
195+ }
196+
197+ uint32_t getId() const {
198+ return id;
199+ }
200+
201+ void addDoor(Door* door);
202+ void removeDoor(Door* door);
203+ Door* getDoorByNumber(uint32_t doorId) const;
204+ Door* getDoorByPosition(const Position& pos);
205+
206+ HouseTransferItem* getTransferItem();
207+ void resetTransferItem();
208+ bool executeTransfer(HouseTransferItem* item, Player* newOwner);
209+
210+ const HouseTileList& getTiles() const {
211+ return houseTiles;
212+ }
213+
214+ const std::set<Door*>& getDoors() const {
215+ return doorSet;
216+ }
217+
218+ void addBed(BedItem* bed);
219+ const HouseBedItemList& getBeds() const {
220+ return bedsList;
221+ }
222+ uint32_t getBedCount() {
223+ return static_cast<uint32_t>(std::ceil(bedsList.size() / 2.)); //each bed takes 2 sqms of space, ceil is just for bad maps
224+ }
225+
226+ private:
227+ bool transferToDepot() const;
228+ bool transferToDepot(Player* player) const;
229+
230+ AccessList guestList;
231+ AccessList subOwnerList;
232+
233+ Container transfer_container{ITEM_LOCKER1};
234+
235+ HouseTileList houseTiles;
236+ std::set<Door*> doorSet;
237+ HouseBedItemList bedsList;
238+
239+ std::string houseName;
240+ std::string ownerName;
241+
242+ HouseTransferItem* transferItem = nullptr;
243+
244+ time_t paidUntil = 0;
245+
246+ uint32_t id;
247+ uint32_t owner = 0;
248+ uint32_t ownerAccountId = 0;
249+ uint32_t rentWarnings = 0;
250+ uint32_t rent = 0;
251+ uint32_t townId = 0;
252+
253+ Position posEntry = {};
254+
255+ bool isLoaded = false;
256+};
257+
258+using HouseMap = std::map<uint32_t, House*>;
259+
260+enum RentPeriod_t {
261+ RENTPERIOD_DAILY,
262+ RENTPERIOD_WEEKLY,
263+ RENTPERIOD_MONTHLY,
264+ RENTPERIOD_YEARLY,
265+ RENTPERIOD_NEVER,
266+};
267+
268+class Houses
269+{
270+ public:
271+ Houses() = default;
272+ ~Houses() {
273+ for (const auto& it : houseMap) {
274+ delete it.second;
275+ }
276+ }
277+
278+ // non-copyable
279+ Houses(const Houses&) = delete;
280+ Houses& operator=(const Houses&) = delete;
281+
282+ House* addHouse(uint32_t id) {
283+ auto it = houseMap.find(id);
284+ if (it != houseMap.end()) {
285+ return it->second;
286+ }
287+
288+ House* house = new House(id);
289+ houseMap[id] = house;
290+ return house;
291+ }
292+
293+ House* getHouse(uint32_t houseId) {
294+ auto it = houseMap.find(houseId);
295+ if (it == houseMap.end()) {
296+ return nullptr;
297+ }
298+ return it->second;
299+ }
300+
301+ House* getHouseByPlayerId(uint32_t playerId);
302+
303+ bool loadHousesXML(const std::string& filename);
304+
305+ void payHouses(RentPeriod_t rentPeriod) const;
306+
307+ const HouseMap& getHouses() const {
308+ return houseMap;
309+ }
310+
311+ private:
312+ HouseMap houseMap;
313+};
314+
315+#endif
A src/housetile.cpp +122-0 View file
@@ -0,0 +1,122 @@
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 "housetile.h"
23+#include "house.h"
24+#include "game.h"
25+
26+extern Game g_game;
27+
28+HouseTile::HouseTile(int32_t x, int32_t y, int32_t z, House* house) :
29+ DynamicTile(x, y, z), house(house) {}
30+
31+void HouseTile::addThing(int32_t index, Thing* thing)
32+{
33+ Tile::addThing(index, thing);
34+
35+ if (!thing->getParent()) {
36+ return;
37+ }
38+
39+ if (Item* item = thing->getItem()) {
40+ updateHouse(item);
41+ }
42+}
43+
44+void HouseTile::internalAddThing(uint32_t index, Thing* thing)
45+{
46+ Tile::internalAddThing(index, thing);
47+
48+ if (!thing->getParent()) {
49+ return;
50+ }
51+
52+ if (Item* item = thing->getItem()) {
53+ updateHouse(item);
54+ }
55+}
56+
57+void HouseTile::updateHouse(Item* item)
58+{
59+ if (item->getParent() != this) {
60+ return;
61+ }
62+
63+ Door* door = item->getDoor();
64+ if (door) {
65+ if (door->getDoorId() != 0) {
66+ house->addDoor(door);
67+ }
68+ } else {
69+ BedItem* bed = item->getBed();
70+ if (bed) {
71+ house->addBed(bed);
72+ }
73+ }
74+}
75+
76+ReturnValue HouseTile::queryAdd(int32_t index, const Thing& thing, uint32_t count, uint32_t flags, Creature* actor/* = nullptr*/) const
77+{
78+ if (const Creature* creature = thing.getCreature()) {
79+ if (const Player* player = creature->getPlayer()) {
80+ if (!house->isInvited(player)) {
81+ return RETURNVALUE_PLAYERISNOTINVITED;
82+ }
83+ } else {
84+ return RETURNVALUE_NOTPOSSIBLE;
85+ }
86+ } else if (thing.getItem() && actor) {
87+ Player* actorPlayer = actor->getPlayer();
88+ if (!house->isInvited(actorPlayer)) {
89+ return RETURNVALUE_CANNOTTHROW;
90+ }
91+ }
92+ return Tile::queryAdd(index, thing, count, flags, actor);
93+}
94+
95+Tile* HouseTile::queryDestination(int32_t& index, const Thing& thing, Item** destItem, uint32_t& flags)
96+{
97+ if (const Creature* creature = thing.getCreature()) {
98+ if (const Player* player = creature->getPlayer()) {
99+ if (!house->isInvited(player)) {
100+ const Position& entryPos = house->getEntryPosition();
101+ Tile* destTile = g_game.map.getTile(entryPos);
102+ if (!destTile) {
103+ std::cout << "Error: [HouseTile::queryDestination] House entry not correct"
104+ << " - Name: " << house->getName()
105+ << " - House id: " << house->getId()
106+ << " - Tile not found: " << entryPos << std::endl;
107+
108+ destTile = g_game.map.getTile(player->getTemplePosition());
109+ if (!destTile) {
110+ destTile = &(Tile::nullptr_tile);
111+ }
112+ }
113+
114+ index = -1;
115+ *destItem = nullptr;
116+ return destTile;
117+ }
118+ }
119+ }
120+
121+ return Tile::queryDestination(index, thing, destItem, flags);
122+}
A src/housetile.h +52-0 View file
@@ -0,0 +1,52 @@
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_HOUSETILE_H_57D59BEC1CE741D9B142BFC54634505B
21+#define FS_HOUSETILE_H_57D59BEC1CE741D9B142BFC54634505B
22+
23+#include "tile.h"
24+
25+class House;
26+
27+class HouseTile final : public DynamicTile
28+{
29+ public:
30+ HouseTile(int32_t x, int32_t y, int32_t z, House* house);
31+
32+ //cylinder implementations
33+ ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
34+ uint32_t flags, Creature* actor = nullptr) const override;
35+
36+ Tile* queryDestination(int32_t& index, const Thing& thing, Item** destItem,
37+ uint32_t& flags) override;
38+
39+ void addThing(int32_t index, Thing* thing) override;
40+ void internalAddThing(uint32_t index, Thing* thing) override;
41+
42+ House* getHouse() {
43+ return house;
44+ }
45+
46+ private:
47+ void updateHouse(Item* item);
48+
49+ House* house;
50+};
51+
52+#endif
A src/inbox.cpp +72-0 View file
@@ -0,0 +1,72 @@
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 "inbox.h"
23+#include "tools.h"
24+
25+Inbox::Inbox(uint16_t type) : Container(type, 30, false, true) {}
26+
27+ReturnValue Inbox::queryAdd(int32_t, const Thing& thing, uint32_t,
28+ uint32_t flags, Creature*) const
29+{
30+ if (!hasBitSet(FLAG_NOLIMIT, flags)) {
31+ return RETURNVALUE_CONTAINERNOTENOUGHROOM;
32+ }
33+
34+ const Item* item = thing.getItem();
35+ if (!item) {
36+ return RETURNVALUE_NOTPOSSIBLE;
37+ }
38+
39+ if (item == this) {
40+ return RETURNVALUE_THISISIMPOSSIBLE;
41+ }
42+
43+ if (!item->isPickupable()) {
44+ return RETURNVALUE_CANNOTPICKUP;
45+ }
46+
47+ return RETURNVALUE_NOERROR;
48+}
49+
50+void Inbox::postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t)
51+{
52+ Cylinder* parent = getParent();
53+ if (parent != nullptr) {
54+ parent->postAddNotification(thing, oldParent, index, LINK_PARENT);
55+ }
56+}
57+
58+void Inbox::postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t)
59+{
60+ Cylinder* parent = getParent();
61+ if (parent != nullptr) {
62+ parent->postRemoveNotification(thing, newParent, index, LINK_PARENT);
63+ }
64+}
65+
66+Cylinder* Inbox::getParent() const
67+{
68+ if (parent) {
69+ return parent->getParent();
70+ }
71+ return nullptr;
72+}
A src/inbox.h +49-0 View file
@@ -0,0 +1,49 @@
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_INBOX_H_C3EF10190329447883B9C3479234EE5C
21+#define FS_INBOX_H_C3EF10190329447883B9C3479234EE5C
22+
23+#include "container.h"
24+
25+class Inbox final : public Container
26+{
27+ public:
28+ explicit Inbox(uint16_t type);
29+
30+ //cylinder implementations
31+ ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
32+ uint32_t flags, Creature* actor = nullptr) const override;
33+
34+ void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
35+ void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
36+
37+ //overrides
38+ bool canRemove() const override {
39+ return false;
40+ }
41+
42+ Cylinder* getParent() const override;
43+ Cylinder* getRealParent() const override {
44+ return parent;
45+ }
46+};
47+
48+#endif
49+
A src/ioguild.cpp +79-0 View file
@@ -0,0 +1,79 @@
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 "database.h"
23+#include "guild.h"
24+#include "ioguild.h"
25+
26+Guild* IOGuild::loadGuild(uint32_t guildId)
27+{
28+ Database& db = Database::getInstance();
29+ std::ostringstream query;
30+ query << "SELECT `name` FROM `guilds` WHERE `id` = " << guildId;
31+ if (DBResult_ptr result = db.storeQuery(query.str())) {
32+ Guild* guild = new Guild(guildId, result->getString("name"));
33+
34+ query.str(std::string());
35+ query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `guild_id` = " << guildId;
36+
37+ if ((result = db.storeQuery(query.str()))) {
38+ do {
39+ guild->addRank(result->getNumber<uint32_t>("id"), result->getString("name"), result->getNumber<uint16_t>("level"));
40+ } while (result->next());
41+ }
42+ return guild;
43+ }
44+ return nullptr;
45+}
46+
47+uint32_t IOGuild::getGuildIdByName(const std::string& name)
48+{
49+ Database& db = Database::getInstance();
50+
51+ std::ostringstream query;
52+ query << "SELECT `id` FROM `guilds` WHERE `name` = " << db.escapeString(name);
53+
54+ DBResult_ptr result = db.storeQuery(query.str());
55+ if (!result) {
56+ return 0;
57+ }
58+ return result->getNumber<uint32_t>("id");
59+}
60+
61+void IOGuild::getWarList(uint32_t guildId, GuildWarVector& guildWarVector)
62+{
63+ std::ostringstream query;
64+ query << "SELECT `guild1`, `guild2` FROM `guild_wars` WHERE (`guild1` = " << guildId << " OR `guild2` = " << guildId << ") AND `ended` = 0 AND `status` = 1";
65+
66+ DBResult_ptr result = Database::getInstance().storeQuery(query.str());
67+ if (!result) {
68+ return;
69+ }
70+
71+ do {
72+ uint32_t guild1 = result->getNumber<uint32_t>("guild1");
73+ if (guildId != guild1) {
74+ guildWarVector.push_back(guild1);
75+ } else {
76+ guildWarVector.push_back(result->getNumber<uint32_t>("guild2"));
77+ }
78+ } while (result->next());
79+}
A src/ioguild.h +34-0 View file
@@ -0,0 +1,34 @@
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_IOGUILD_H_EF9ACEBA0B844C388B70FF52E69F1AFF
21+#define FS_IOGUILD_H_EF9ACEBA0B844C388B70FF52E69F1AFF
22+
23+class Guild;
24+using GuildWarVector = std::vector<uint32_t>;
25+
26+class IOGuild
27+{
28+ public:
29+ static Guild* loadGuild(uint32_t guildId);
30+ static uint32_t getGuildIdByName(const std::string& name);
31+ static void getWarList(uint32_t guildId, GuildWarVector& guildWarVector);
32+};
33+
34+#endif
Top