| @@ -0,0 +1,125 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef CLIENT_DECLARATIONS_H | |
| 24 | + | #define CLIENT_DECLARATIONS_H | |
| 25 | + | ||
| 26 | + | #include "global.h" | |
| 27 | + | #include <framework/net/declarations.h> | |
| 28 | + | #include <framework/ui/declarations.h> | |
| 29 | + | ||
| 30 | + | // core | |
| 31 | + | class Map; | |
| 32 | + | class Game; | |
| 33 | + | class MapView; | |
| 34 | + | class LightView; | |
| 35 | + | class Tile; | |
| 36 | + | class Thing; | |
| 37 | + | class Item; | |
| 38 | + | class Container; | |
| 39 | + | class Creature; | |
| 40 | + | class Monster; | |
| 41 | + | class Npc; | |
| 42 | + | class Player; | |
| 43 | + | class LocalPlayer; | |
| 44 | + | class Effect; | |
| 45 | + | class Missile; | |
| 46 | + | class AnimatedText; | |
| 47 | + | class StaticText; | |
| 48 | + | class Animator; | |
| 49 | + | class ThingType; | |
| 50 | + | class ItemType; | |
| 51 | + | class House; | |
| 52 | + | class Town; | |
| 53 | + | class CreatureType; | |
| 54 | + | class Spawn; | |
| 55 | + | class TileBlock; | |
| 56 | + | ||
| 57 | + | typedef stdext::shared_object_ptr<MapView> MapViewPtr; | |
| 58 | + | typedef stdext::shared_object_ptr<LightView> LightViewPtr; | |
| 59 | + | typedef stdext::shared_object_ptr<Tile> TilePtr; | |
| 60 | + | typedef stdext::shared_object_ptr<Thing> ThingPtr; | |
| 61 | + | typedef stdext::shared_object_ptr<Item> ItemPtr; | |
| 62 | + | typedef stdext::shared_object_ptr<Container> ContainerPtr; | |
| 63 | + | typedef stdext::shared_object_ptr<Creature> CreaturePtr; | |
| 64 | + | typedef stdext::shared_object_ptr<Monster> MonsterPtr; | |
| 65 | + | typedef stdext::shared_object_ptr<Npc> NpcPtr; | |
| 66 | + | typedef stdext::shared_object_ptr<Player> PlayerPtr; | |
| 67 | + | typedef stdext::shared_object_ptr<LocalPlayer> LocalPlayerPtr; | |
| 68 | + | typedef stdext::shared_object_ptr<Effect> EffectPtr; | |
| 69 | + | typedef stdext::shared_object_ptr<Missile> MissilePtr; | |
| 70 | + | typedef stdext::shared_object_ptr<AnimatedText> AnimatedTextPtr; | |
| 71 | + | typedef stdext::shared_object_ptr<StaticText> StaticTextPtr; | |
| 72 | + | typedef stdext::shared_object_ptr<Animator> AnimatorPtr; | |
| 73 | + | typedef stdext::shared_object_ptr<ThingType> ThingTypePtr; | |
| 74 | + | typedef stdext::shared_object_ptr<ItemType> ItemTypePtr; | |
| 75 | + | typedef stdext::shared_object_ptr<House> HousePtr; | |
| 76 | + | typedef stdext::shared_object_ptr<Town> TownPtr; | |
| 77 | + | typedef stdext::shared_object_ptr<CreatureType> CreatureTypePtr; | |
| 78 | + | typedef stdext::shared_object_ptr<Spawn> SpawnPtr; | |
| 79 | + | ||
| 80 | + | typedef std::vector<ThingPtr> ThingList; | |
| 81 | + | typedef std::vector<ThingTypePtr> ThingTypeList; | |
| 82 | + | typedef std::vector<ItemTypePtr> ItemTypeList; | |
| 83 | + | typedef std::list<HousePtr> HouseList; | |
| 84 | + | typedef std::list<TownPtr> TownList; | |
| 85 | + | typedef std::list<ItemPtr> ItemList; | |
| 86 | + | typedef std::list<TilePtr> TileList; | |
| 87 | + | typedef std::vector<ItemPtr> ItemVector; | |
| 88 | + | typedef std::unordered_map<Position, TilePtr, PositionHasher> TileMap; | |
| 89 | + | typedef std::unordered_map<Position, CreatureTypePtr, PositionHasher> CreatureMap; | |
| 90 | + | typedef std::unordered_map<Position, SpawnPtr, PositionHasher> SpawnMap; | |
| 91 | + | ||
| 92 | + | // net | |
| 93 | + | class ProtocolLogin; | |
| 94 | + | class ProtocolGame; | |
| 95 | + | ||
| 96 | + | typedef stdext::shared_object_ptr<ProtocolGame> ProtocolGamePtr; | |
| 97 | + | typedef stdext::shared_object_ptr<ProtocolLogin> ProtocolLoginPtr; | |
| 98 | + | ||
| 99 | + | // ui | |
| 100 | + | class UIItem; | |
| 101 | + | class UICreature; | |
| 102 | + | class UIGraph; | |
| 103 | + | class UIMap; | |
| 104 | + | class UIMinimap; | |
| 105 | + | class UIProgressRect; | |
| 106 | + | class UIMapAnchorLayout; | |
| 107 | + | class UIPositionAnchor; | |
| 108 | + | class UISprite; | |
| 109 | + | ||
| 110 | + | typedef stdext::shared_object_ptr<UIItem> UIItemPtr; | |
| 111 | + | typedef stdext::shared_object_ptr<UICreature> UICreaturePtr; | |
| 112 | + | typedef stdext::shared_object_ptr<UIGraph> UIGraphPtr; | |
| 113 | + | typedef stdext::shared_object_ptr<UISprite> UISpritePtr; | |
| 114 | + | typedef stdext::shared_object_ptr<UIMap> UIMapPtr; | |
| 115 | + | typedef stdext::shared_object_ptr<UIMinimap> UIMinimapPtr; | |
| 116 | + | typedef stdext::shared_object_ptr<UIProgressRect> UIProgressRectPtr; | |
| 117 | + | typedef stdext::shared_object_ptr<UIMapAnchorLayout> UIMapAnchorLayoutPtr; | |
| 118 | + | typedef stdext::shared_object_ptr<UIPositionAnchor> UIPositionAnchorPtr; | |
| 119 | + | ||
| 120 | + | // custom | |
| 121 | + | class HealthBar; | |
| 122 | + | ||
| 123 | + | typedef stdext::shared_object_ptr<HealthBar> HealthBarPtr; | |
| 124 | + | ||
| 125 | + | #endif |
| @@ -0,0 +1,98 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #include "effect.h" | |
| 24 | + | #include "map.h" | |
| 25 | + | #include "game.h" | |
| 26 | + | #include <framework/core/eventdispatcher.h> | |
| 27 | + | #include <framework/util/extras.h> | |
| 28 | + | ||
| 29 | + | void Effect::draw(const Point& dest, int offsetX, int offsetY, bool animate, LightView* lightView) | |
| 30 | + | { | |
| 31 | + | if(m_id == 0) | |
| 32 | + | return; | |
| 33 | + | ||
| 34 | + | if(animate) { | |
| 35 | + | if(g_game.getFeature(Otc::GameEnhancedAnimations) && rawGetThingType()->getAnimator()) { | |
| 36 | + | // This requires a separate getPhaseAt method as using getPhase would make all magic effects use the same phase regardless of their appearance time | |
| 37 | + | m_animationPhase = std::max<int>(0, rawGetThingType()->getAnimator()->getPhaseAt(m_animationTimer, m_animationPhase)); | |
| 38 | + | } else { | |
| 39 | + | // hack to fix some animation phases duration, currently there is no better solution | |
| 40 | + | int ticks = EFFECT_TICKS_PER_FRAME; | |
| 41 | + | if (m_id == 33) { | |
| 42 | + | ticks <<= 2; | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | m_animationPhase = std::max<int>(0, std::min<int>((int)(m_animationTimer.ticksElapsed() / ticks), getAnimationPhases() - 1)); | |
| 46 | + | } | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | int xPattern = m_position.x % getNumPatternX(); | |
| 50 | + | if(xPattern < 0) | |
| 51 | + | xPattern += getNumPatternX(); | |
| 52 | + | ||
| 53 | + | int yPattern = m_position.y % getNumPatternY(); | |
| 54 | + | if(yPattern < 0) | |
| 55 | + | yPattern += getNumPatternY(); | |
| 56 | + | ||
| 57 | + | rawGetThingType()->draw(dest, 0, xPattern, yPattern, 0, m_animationPhase, Color::white, lightView); | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | void Effect::onAppear() | |
| 61 | + | { | |
| 62 | + | m_animationTimer.restart(); | |
| 63 | + | ||
| 64 | + | int duration = 0; | |
| 65 | + | if(g_game.getFeature(Otc::GameEnhancedAnimations)) { | |
| 66 | + | duration = getThingType()->getAnimator() ? getThingType()->getAnimator()->getTotalDuration() : 1000; | |
| 67 | + | } else { | |
| 68 | + | duration = EFFECT_TICKS_PER_FRAME; | |
| 69 | + | ||
| 70 | + | // hack to fix some animation phases duration, currently there is no better solution | |
| 71 | + | if(m_id == 33) { | |
| 72 | + | duration <<= 2; | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | duration *= getAnimationPhases(); | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // schedule removal | |
| 79 | + | auto self = asEffect(); | |
| 80 | + | g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, duration); | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | void Effect::setId(uint32 id) | |
| 84 | + | { | |
| 85 | + | if(!g_things.isValidDatId(id, ThingCategoryEffect)) | |
| 86 | + | id = 0; | |
| 87 | + | m_id = id; | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | const ThingTypePtr& Effect::getThingType() | |
| 91 | + | { | |
| 92 | + | return g_things.getThingType(m_id, ThingCategoryEffect); | |
| 93 | + | } | |
| 94 | + | ||
| 95 | + | ThingType *Effect::rawGetThingType() | |
| 96 | + | { | |
| 97 | + | return g_things.rawGetThingType(m_id, ThingCategoryEffect); | |
| 98 | + | } |
| @@ -0,0 +1,59 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef EFFECT_H | |
| 24 | + | #define EFFECT_H | |
| 25 | + | ||
| 26 | + | #include <framework/global.h> | |
| 27 | + | #include <framework/core/timer.h> | |
| 28 | + | #include "thing.h" | |
| 29 | + | ||
| 30 | + | // @bindclass | |
| 31 | + | class Effect : public Thing | |
| 32 | + | { | |
| 33 | + | enum { | |
| 34 | + | EFFECT_TICKS_PER_FRAME = 75 | |
| 35 | + | }; | |
| 36 | + | ||
| 37 | + | public: | |
| 38 | + | void draw(const Point& dest, bool animate = true, LightView* lightView = nullptr) override {} | |
| 39 | + | void draw(const Point& dest, int offsetX = 0, int offsetY = 0, bool animate = true, LightView* lightView = nullptr); | |
| 40 | + | ||
| 41 | + | void setId(uint32 id) override; | |
| 42 | + | uint32 getId() override { return m_id; } | |
| 43 | + | ||
| 44 | + | EffectPtr asEffect() { return static_self_cast<Effect>(); } | |
| 45 | + | bool isEffect() override { return true; } | |
| 46 | + | ||
| 47 | + | const ThingTypePtr& getThingType() override; | |
| 48 | + | ThingType *rawGetThingType() override; | |
| 49 | + | ||
| 50 | + | protected: | |
| 51 | + | void onAppear() override; | |
| 52 | + | ||
| 53 | + | private: | |
| 54 | + | uint16 m_id; | |
| 55 | + | Timer m_animationTimer; | |
| 56 | + | int m_animationPhase = 0; | |
| 57 | + | }; | |
| 58 | + | ||
| 59 | + | #endif |
| @@ -0,0 +1,1673 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #include "game.h" | |
| 24 | + | #include "localplayer.h" | |
| 25 | + | #include "map.h" | |
| 26 | + | #include "tile.h" | |
| 27 | + | #include "creature.h" | |
| 28 | + | #include "container.h" | |
| 29 | + | #include "statictext.h" | |
| 30 | + | #include <framework/core/eventdispatcher.h> | |
| 31 | + | #include <framework/ui/uimanager.h> | |
| 32 | + | #include <framework/core/application.h> | |
| 33 | + | #include "luavaluecasts_client.h" | |
| 34 | + | #include "protocolgame.h" | |
| 35 | + | #include "protocolcodes.h" | |
| 36 | + | ||
| 37 | + | #include <framework/util/extras.h> | |
| 38 | + | #include <framework/graphics/graph.h> | |
| 39 | + | #include <framework/net/packet_player.h> | |
| 40 | + | #include <framework/net/packet_recorder.h> | |
| 41 | + | ||
| 42 | + | Game g_game; | |
| 43 | + | ||
| 44 | + | Game::Game() | |
| 45 | + | { | |
| 46 | + | m_protocolVersion = 0; | |
| 47 | + | m_clientCustomOs = -1; | |
| 48 | + | m_clientVersion = 0; | |
| 49 | + | m_online = false; | |
| 50 | + | m_denyBotCall = false; | |
| 51 | + | m_dead = false; | |
| 52 | + | m_serverBeat = 50; | |
| 53 | + | m_seq = 0; | |
| 54 | + | m_ping = -1; | |
| 55 | + | m_pingDelay = 1000; | |
| 56 | + | m_newPingDelay = 250; | |
| 57 | + | m_canReportBugs = false; | |
| 58 | + | m_fightMode = Otc::FightBalanced; | |
| 59 | + | m_chaseMode = Otc::DontChase; | |
| 60 | + | m_pvpMode = Otc::WhiteDove; | |
| 61 | + | m_safeFight = true; | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | void Game::init() | |
| 65 | + | { | |
| 66 | + | resetGameStates(); | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | void Game::terminate() | |
| 70 | + | { | |
| 71 | + | resetGameStates(); | |
| 72 | + | m_protocolGame = nullptr; | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | void Game::resetGameStates() | |
| 76 | + | { | |
| 77 | + | m_online = false; | |
| 78 | + | m_denyBotCall = false; | |
| 79 | + | m_dead = false; | |
| 80 | + | m_serverBeat = 50; | |
| 81 | + | m_seq = 0; | |
| 82 | + | m_ping = -1; | |
| 83 | + | m_canReportBugs = false; | |
| 84 | + | m_fightMode = Otc::FightBalanced; | |
| 85 | + | m_chaseMode = Otc::DontChase; | |
| 86 | + | m_pvpMode = Otc::WhiteDove; | |
| 87 | + | m_safeFight = true; | |
| 88 | + | m_followingCreature = nullptr; | |
| 89 | + | m_attackingCreature = nullptr; | |
| 90 | + | m_localPlayer = nullptr; | |
| 91 | + | m_pingSent = 0; | |
| 92 | + | m_pingReceived = 0; | |
| 93 | + | m_walkId = 0; | |
| 94 | + | m_walkPrediction = 0; | |
| 95 | + | m_coins = 0; | |
| 96 | + | m_transferableCoins = 0; | |
| 97 | + | m_newPingIds.clear(); | |
| 98 | + | m_unjustifiedPoints = UnjustifiedPoints(); | |
| 99 | + | ||
| 100 | + | for(auto& it : m_containers) { | |
| 101 | + | const ContainerPtr& container = it.second; | |
| 102 | + | if(container) | |
| 103 | + | container->onClose(); | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | if(m_pingEvent) { | |
| 107 | + | m_pingEvent->cancel(); | |
| 108 | + | m_pingEvent = nullptr; | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | if (m_newPingEvent) { | |
| 112 | + | m_newPingEvent->cancel(); | |
| 113 | + | m_newPingEvent = nullptr; | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | if(m_checkConnectionEvent) { | |
| 117 | + | m_checkConnectionEvent->cancel(); | |
| 118 | + | m_checkConnectionEvent = nullptr; | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | m_containers.clear(); | |
| 122 | + | m_vips.clear(); | |
| 123 | + | m_gmActions.clear(); | |
| 124 | + | g_map.resetAwareRange(); | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | void Game::processConnectionError(const boost::system::error_code& ec) | |
| 128 | + | { | |
| 129 | + | // connection errors only have meaning if we still have a protocol | |
| 130 | + | if(m_protocolGame) { | |
| 131 | + | g_lua.callGlobalField("g_game", "onConnectionError", ec.message(), ec.value()); | |
| 132 | + | processDisconnect(); | |
| 133 | + | } | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | void Game::processDisconnect() | |
| 137 | + | { | |
| 138 | + | if(isOnline()) | |
| 139 | + | processGameEnd(); | |
| 140 | + | ||
| 141 | + | if(m_protocolGame) { | |
| 142 | + | m_protocolGame->disconnect(); | |
| 143 | + | m_protocolGame = nullptr; | |
| 144 | + | } | |
| 145 | + | } | |
| 146 | + | ||
| 147 | + | void Game::processUpdateNeeded(const std::string& signature) | |
| 148 | + | { | |
| 149 | + | g_lua.callGlobalField("g_game", "onUpdateNeeded", signature); | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | void Game::processLoginError(const std::string& error) | |
| 153 | + | { | |
| 154 | + | g_lua.callGlobalField("g_game", "onLoginError", error); | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | void Game::processLoginAdvice(const std::string& message) | |
| 158 | + | { | |
| 159 | + | g_lua.callGlobalField("g_game", "onLoginAdvice", message); | |
| 160 | + | } | |
| 161 | + | ||
| 162 | + | void Game::processLoginWait(const std::string& message, int time) | |
| 163 | + | { | |
| 164 | + | g_lua.callGlobalField("g_game", "onLoginWait", message, time); | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | void Game::processLoginToken(bool unknown) | |
| 168 | + | { | |
| 169 | + | g_lua.callGlobalField("g_game", "onLoginToken", unknown); | |
| 170 | + | } | |
| 171 | + | ||
| 172 | + | void Game::processLogin() | |
| 173 | + | { | |
| 174 | + | g_lua.callGlobalField("g_game", "onLogin"); | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | void Game::processPendingGame() | |
| 178 | + | { | |
| 179 | + | m_localPlayer->setPendingGame(true); | |
| 180 | + | g_lua.callGlobalField("g_game", "onPendingGame"); | |
| 181 | + | m_protocolGame->sendEnterGame(); | |
| 182 | + | } | |
| 183 | + | ||
| 184 | + | void Game::processEnterGame() | |
| 185 | + | { | |
| 186 | + | m_localPlayer->setPendingGame(false); | |
| 187 | + | g_lua.callGlobalField("g_game", "onEnterGame"); | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | void Game::processGameStart() | |
| 191 | + | { | |
| 192 | + | m_online = true; | |
| 193 | + | ||
| 194 | + | // synchronize fight modes with the server | |
| 195 | + | m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); | |
| 196 | + | ||
| 197 | + | // NOTE: the entire map description and local player information is not known yet (bot call is allowed here) | |
| 198 | + | enableBotCall(); | |
| 199 | + | g_lua.callGlobalField("g_game", "onGameStart"); | |
| 200 | + | disableBotCall(); | |
| 201 | + | ||
| 202 | + | if (g_game.getFeature(Otc::GameExtendedClientPing)) { | |
| 203 | + | m_newPingEvent = g_dispatcher.scheduleEvent([] { | |
| 204 | + | g_game.newPing(); | |
| 205 | + | }, m_newPingDelay); | |
| 206 | + | } | |
| 207 | + | if(g_game.getFeature(Otc::GameClientPing)) { | |
| 208 | + | m_pingEvent = g_dispatcher.scheduleEvent([] { | |
| 209 | + | g_game.ping(); | |
| 210 | + | }, m_pingDelay); | |
| 211 | + | } | |
| 212 | + | ||
| 213 | + | m_checkConnectionEvent = g_dispatcher.cycleEvent([this] { | |
| 214 | + | if(!g_game.isConnectionOk() && !m_connectionFailWarned) { | |
| 215 | + | g_lua.callGlobalField("g_game", "onConnectionFailing", true); | |
| 216 | + | m_connectionFailWarned = true; | |
| 217 | + | } else if(g_game.isConnectionOk() && m_connectionFailWarned) { | |
| 218 | + | g_lua.callGlobalField("g_game", "onConnectionFailing", false); | |
| 219 | + | m_connectionFailWarned = false; | |
| 220 | + | } | |
| 221 | + | }, 1000); | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | void Game::processGameEnd() | |
| 225 | + | { | |
| 226 | + | m_online = false; | |
| 227 | + | g_lua.callGlobalField("g_game", "onGameEnd"); | |
| 228 | + | ||
| 229 | + | if(m_connectionFailWarned) { | |
| 230 | + | g_lua.callGlobalField("g_game", "onConnectionFailing", false); | |
| 231 | + | m_connectionFailWarned = false; | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // reset game state | |
| 235 | + | resetGameStates(); | |
| 236 | + | ||
| 237 | + | m_worldName = ""; | |
| 238 | + | m_characterName = ""; | |
| 239 | + | ||
| 240 | + | // clean map creatures | |
| 241 | + | g_map.cleanDynamicThings(); | |
| 242 | + | } | |
| 243 | + | ||
| 244 | + | void Game::processDeath(int deathType, int penality) | |
| 245 | + | { | |
| 246 | + | m_dead = true; | |
| 247 | + | m_localPlayer->stopWalk(); | |
| 248 | + | ||
| 249 | + | g_lua.callGlobalField("g_game", "onDeath", deathType, penality); | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | void Game::processGMActions(const std::vector<uint8>& actions) | |
| 253 | + | { | |
| 254 | + | m_gmActions = actions; | |
| 255 | + | g_lua.callGlobalField("g_game", "onGMActions", actions); | |
| 256 | + | } | |
| 257 | + | ||
| 258 | + | void Game::processPlayerHelpers(int helpers) | |
| 259 | + | { | |
| 260 | + | g_lua.callGlobalField("g_game", "onPlayerHelpersUpdate", helpers); | |
| 261 | + | } | |
| 262 | + | ||
| 263 | + | void Game::processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode, Otc::PVPModes pvpMode) | |
| 264 | + | { | |
| 265 | + | m_fightMode = fightMode; | |
| 266 | + | m_chaseMode = chaseMode; | |
| 267 | + | m_safeFight = safeMode; | |
| 268 | + | m_pvpMode = pvpMode; | |
| 269 | + | ||
| 270 | + | g_lua.callGlobalField("g_game", "onFightModeChange", fightMode); | |
| 271 | + | g_lua.callGlobalField("g_game", "onChaseModeChange", chaseMode); | |
| 272 | + | g_lua.callGlobalField("g_game", "onSafeFightChange", safeMode); | |
| 273 | + | g_lua.callGlobalField("g_game", "onPVPModeChange", pvpMode); | |
| 274 | + | } | |
| 275 | + | ||
| 276 | + | void Game::processPing() | |
| 277 | + | { | |
| 278 | + | g_lua.callGlobalField("g_game", "onPing"); | |
| 279 | + | enableBotCall(); | |
| 280 | + | m_protocolGame->sendPingBack(); | |
| 281 | + | disableBotCall(); | |
| 282 | + | } | |
| 283 | + | ||
| 284 | + | void Game::processPingBack() | |
| 285 | + | { | |
| 286 | + | m_pingReceived++; | |
| 287 | + | ||
| 288 | + | if (!g_game.getFeature(Otc::GameExtendedClientPing)) { | |
| 289 | + | if (m_pingReceived == m_pingSent) { | |
| 290 | + | m_ping = m_pingTimer.elapsed_millis(); | |
| 291 | + | g_graphs[GRAPH_LATENCY].addValue(m_ping); | |
| 292 | + | } | |
| 293 | + | ||
| 294 | + | g_lua.callGlobalField("g_game", "onPingBack", m_ping); | |
| 295 | + | } | |
| 296 | + | ||
| 297 | + | m_pingEvent = g_dispatcher.scheduleEvent([] { | |
| 298 | + | g_game.ping(); | |
| 299 | + | }, m_pingDelay); | |
| 300 | + | } | |
| 301 | + | ||
| 302 | + | void Game::processNewPing(uint32_t pingId) | |
| 303 | + | { | |
| 304 | + | auto it = m_newPingIds.find(pingId); | |
| 305 | + | ||
| 306 | + | if (it == m_newPingIds.end()) | |
| 307 | + | return; | |
| 308 | + | ||
| 309 | + | m_ping = it->second.elapsed_millis(); | |
| 310 | + | g_graphs[GRAPH_LATENCY].addValue(m_ping); | |
| 311 | + | g_lua.callGlobalField("g_game", "onPingBack", m_ping); | |
| 312 | + | } | |
| 313 | + | ||
| 314 | + | void Game::processTextMessage(Otc::MessageMode mode, const std::string& text) | |
| 315 | + | { | |
| 316 | + | g_lua.callGlobalField("g_game", "onTextMessage", mode, text); | |
| 317 | + | } | |
| 318 | + | ||
| 319 | + | void Game::processTalk(const std::string& name, int level, Otc::MessageMode mode, const std::string& text, int channelId, const Position& pos) | |
| 320 | + | { | |
| 321 | + | g_lua.callGlobalField("g_game", "onTalk", name, level, mode, text, channelId, pos); | |
| 322 | + | } | |
| 323 | + | ||
| 324 | + | void Game::processOpenContainer(int containerId, const ItemPtr& containerItem, const std::string& name, int capacity, bool hasParent, const std::vector<ItemPtr>& items, bool isUnlocked, bool hasPages, int containerSize, int firstIndex) | |
| 325 | + | { | |
| 326 | + | ContainerPtr previousContainer = getContainer(containerId); | |
| 327 | + | ContainerPtr container = ContainerPtr(new Container(containerId, capacity, name, containerItem, hasParent, isUnlocked, hasPages, containerSize, firstIndex)); | |
| 328 | + | m_containers[containerId] = container; | |
| 329 | + | container->onAddItems(items); | |
| 330 | + | ||
| 331 | + | // we might want to close a container here | |
| 332 | + | enableBotCall(); | |
| 333 | + | container->onOpen(previousContainer); | |
| 334 | + | disableBotCall(); | |
| 335 | + | ||
| 336 | + | if(previousContainer) | |
| 337 | + | previousContainer->onClose(); | |
| 338 | + | } | |
| 339 | + | ||
| 340 | + | void Game::processCloseContainer(int containerId) | |
| 341 | + | { | |
| 342 | + | ContainerPtr container = getContainer(containerId); | |
| 343 | + | if(!container) { | |
| 344 | + | return; | |
| 345 | + | } | |
| 346 | + | ||
| 347 | + | m_containers[containerId] = nullptr; | |
| 348 | + | container->onClose(); | |
| 349 | + | } | |
| 350 | + | ||
| 351 | + | void Game::processContainerAddItem(int containerId, const ItemPtr& item, int slot) | |
| 352 | + | { | |
| 353 | + | ContainerPtr container = getContainer(containerId); | |
| 354 | + | if(!container) { | |
| 355 | + | return; | |
| 356 | + | } | |
| 357 | + | ||
| 358 | + | container->onAddItem(item, slot); | |
| 359 | + | } | |
| 360 | + | ||
| 361 | + | void Game::processContainerUpdateItem(int containerId, int slot, const ItemPtr& item) | |
| 362 | + | { | |
| 363 | + | ContainerPtr container = getContainer(containerId); | |
| 364 | + | if(!container) { | |
| 365 | + | return; | |
| 366 | + | } | |
| 367 | + | ||
| 368 | + | container->onUpdateItem(slot, item); | |
| 369 | + | } | |
| 370 | + | ||
| 371 | + | void Game::processContainerRemoveItem(int containerId, int slot, const ItemPtr& lastItem) | |
| 372 | + | { | |
| 373 | + | ContainerPtr container = getContainer(containerId); | |
| 374 | + | if(!container) { | |
| 375 | + | return; | |
| 376 | + | } | |
| 377 | + | ||
| 378 | + | container->onRemoveItem(slot, lastItem); | |
| 379 | + | } | |
| 380 | + | ||
| 381 | + | void Game::processInventoryChange(int slot, const ItemPtr& item) | |
| 382 | + | { | |
| 383 | + | if(item) | |
| 384 | + | item->setPosition(Position(65535, slot, 0)); | |
| 385 | + | ||
| 386 | + | m_localPlayer->setInventoryItem((Otc::InventorySlot)slot, item); | |
| 387 | + | } | |
| 388 | + | ||
| 389 | + | void Game::processChannelList(const std::vector<std::tuple<int, std::string> >& channelList) | |
| 390 | + | { | |
| 391 | + | g_lua.callGlobalField("g_game", "onChannelList", channelList); | |
| 392 | + | } | |
| 393 | + | ||
| 394 | + | void Game::processOpenChannel(int channelId, const std::string& name) | |
| 395 | + | { | |
| 396 | + | g_lua.callGlobalField("g_game", "onOpenChannel", channelId, name); | |
| 397 | + | } | |
| 398 | + | ||
| 399 | + | void Game::processOpenPrivateChannel(const std::string& name) | |
| 400 | + | { | |
| 401 | + | g_lua.callGlobalField("g_game", "onOpenPrivateChannel", name); | |
| 402 | + | } | |
| 403 | + | ||
| 404 | + | void Game::processOpenOwnPrivateChannel(int channelId, const std::string& name) | |
| 405 | + | { | |
| 406 | + | g_lua.callGlobalField("g_game", "onOpenOwnPrivateChannel", channelId, name); | |
| 407 | + | } | |
| 408 | + | ||
| 409 | + | void Game::processCloseChannel(int channelId) | |
| 410 | + | { | |
| 411 | + | g_lua.callGlobalField("g_game", "onCloseChannel", channelId); | |
| 412 | + | } | |
| 413 | + | ||
| 414 | + | void Game::processRuleViolationChannel(int channelId) | |
| 415 | + | { | |
| 416 | + | g_lua.callGlobalField("g_game", "onRuleViolationChannel", channelId); | |
| 417 | + | } | |
| 418 | + | ||
| 419 | + | void Game::processRuleViolationRemove(const std::string& name) | |
| 420 | + | { | |
| 421 | + | g_lua.callGlobalField("g_game", "onRuleViolationRemove", name); | |
| 422 | + | } | |
| 423 | + | ||
| 424 | + | void Game::processRuleViolationCancel(const std::string& name) | |
| 425 | + | { | |
| 426 | + | g_lua.callGlobalField("g_game", "onRuleViolationCancel", name); | |
| 427 | + | } | |
| 428 | + | ||
| 429 | + | void Game::processRuleViolationLock() | |
| 430 | + | { | |
| 431 | + | g_lua.callGlobalField("g_game", "onRuleViolationLock"); | |
| 432 | + | } | |
| 433 | + | ||
| 434 | + | void Game::processVipAdd(uint id, const std::string& name, uint status, const std::string& description, int iconId, bool notifyLogin) | |
| 435 | + | { | |
| 436 | + | m_vips[id] = Vip(name, status, description, iconId, notifyLogin); | |
| 437 | + | g_lua.callGlobalField("g_game", "onAddVip", id, name, status, description, iconId, notifyLogin); | |
| 438 | + | } | |
| 439 | + | ||
| 440 | + | void Game::processVipStateChange(uint id, uint status) | |
| 441 | + | { | |
| 442 | + | if (m_vips.find(id) == m_vips.end()) return; | |
| 443 | + | std::get<1>(m_vips[id]) = status; | |
| 444 | + | g_lua.callGlobalField("g_game", "onVipStateChange", id, status); | |
| 445 | + | } | |
| 446 | + | ||
| 447 | + | void Game::processTutorialHint(int id) | |
| 448 | + | { | |
| 449 | + | g_lua.callGlobalField("g_game", "onTutorialHint", id); | |
| 450 | + | } | |
| 451 | + | ||
| 452 | + | void Game::processAddAutomapFlag(const Position& pos, int icon, const std::string& message) | |
| 453 | + | { | |
| 454 | + | g_lua.callGlobalField("g_game", "onAddAutomapFlag", pos, icon, message); | |
| 455 | + | } | |
| 456 | + | ||
| 457 | + | void Game::processRemoveAutomapFlag(const Position& pos, int icon, const std::string& message) | |
| 458 | + | { | |
| 459 | + | g_lua.callGlobalField("g_game", "onRemoveAutomapFlag", pos, icon, message); | |
| 460 | + | } | |
| 461 | + | ||
| 462 | + | void Game::processOpenOutfitWindow(const Outfit& currentOutfit, const std::vector<std::tuple<int, std::string, int>>& outfitList, | |
| 463 | + | const std::vector<std::tuple<int, std::string>>& mountList, | |
| 464 | + | const std::vector<std::tuple<int, std::string>>& wingList, | |
| 465 | + | const std::vector<std::tuple<int, std::string>>& auraList, | |
| 466 | + | const std::vector<std::tuple<int, std::string>>& shaderList, | |
| 467 | + | const std::vector<std::tuple<int, std::string>>& healthBarList, | |
| 468 | + | const std::vector<std::tuple<int, std::string>>& manaBarList) | |
| 469 | + | { | |
| 470 | + | g_lua.callGlobalField("g_game", "onOpenOutfitWindow", currentOutfit, outfitList, mountList, wingList, auraList, shaderList, healthBarList, manaBarList); | |
| 471 | + | } | |
| 472 | + | ||
| 473 | + | void Game::processOpenNpcTrade(const std::vector<std::tuple<ItemPtr, std::string, int, int64_t, int64_t> >& items) | |
| 474 | + | { | |
| 475 | + | g_lua.callGlobalField("g_game", "onOpenNpcTrade", items); | |
| 476 | + | } | |
| 477 | + | ||
| 478 | + | void Game::processPlayerGoods(uint64_t money, const std::vector<std::tuple<ItemPtr, int> >& goods) | |
| 479 | + | { | |
| 480 | + | g_lua.callGlobalField("g_game", "onPlayerGoods", money, goods); | |
| 481 | + | } | |
| 482 | + | ||
| 483 | + | void Game::processCloseNpcTrade() | |
| 484 | + | { | |
| 485 | + | g_lua.callGlobalField("g_game", "onCloseNpcTrade"); | |
| 486 | + | } | |
| 487 | + | ||
| 488 | + | void Game::processOwnTrade(const std::string& name, const std::vector<ItemPtr>& items) | |
| 489 | + | { | |
| 490 | + | g_lua.callGlobalField("g_game", "onOwnTrade", name, items); | |
| 491 | + | } | |
| 492 | + | ||
| 493 | + | void Game::processCounterTrade(const std::string& name, const std::vector<ItemPtr>& items) | |
| 494 | + | { | |
| 495 | + | g_lua.callGlobalField("g_game", "onCounterTrade", name, items); | |
| 496 | + | } | |
| 497 | + | ||
| 498 | + | void Game::processCloseTrade() | |
| 499 | + | { | |
| 500 | + | g_lua.callGlobalField("g_game", "onCloseTrade"); | |
| 501 | + | } | |
| 502 | + | ||
| 503 | + | void Game::processEditText(uint id, int itemId, int maxLength, const std::string& text, const std::string& writer, const std::string& date) | |
| 504 | + | { | |
| 505 | + | g_lua.callGlobalField("g_game", "onEditText", id, itemId, maxLength, text, writer, date); | |
| 506 | + | } | |
| 507 | + | ||
| 508 | + | void Game::processEditList(uint id, int doorId, const std::string& text) | |
| 509 | + | { | |
| 510 | + | g_lua.callGlobalField("g_game", "onEditList", id, doorId, text); | |
| 511 | + | } | |
| 512 | + | ||
| 513 | + | void Game::processQuestLog(const std::vector<std::tuple<int, std::string, bool> >& questList) | |
| 514 | + | { | |
| 515 | + | g_lua.callGlobalField("g_game", "onQuestLog", questList); | |
| 516 | + | } | |
| 517 | + | ||
| 518 | + | void Game::processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string, int> >& questMissions) | |
| 519 | + | { | |
| 520 | + | g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions); | |
| 521 | + | } | |
| 522 | + | ||
| 523 | + | void Game::processModalDialog(uint32 id, std::string title, std::string message, std::vector<std::tuple<int, std::string> > buttonList, int enterButton, int escapeButton, std::vector<std::tuple<int, std::string> > choiceList, bool priority) | |
| 524 | + | { | |
| 525 | + | g_lua.callGlobalField("g_game", "onModalDialog", id, title, message, buttonList, enterButton, escapeButton, choiceList, priority); | |
| 526 | + | } | |
| 527 | + | ||
| 528 | + | void Game::processAttackCancel(uint seq) | |
| 529 | + | { | |
| 530 | + | if(seq == 0 || m_seq == seq) | |
| 531 | + | cancelAttack(); | |
| 532 | + | } | |
| 533 | + | ||
| 534 | + | void Game::processWalkCancel(Otc::Direction direction) | |
| 535 | + | { | |
| 536 | + | m_localPlayer->cancelWalk(direction); | |
| 537 | + | } | |
| 538 | + | ||
| 539 | + | void Game::processNewWalkCancel(Otc::Direction dir) | |
| 540 | + | { | |
| 541 | + | m_walkId += 1; | |
| 542 | + | m_localPlayer->cancelNewWalk(dir); | |
| 543 | + | } | |
| 544 | + | ||
| 545 | + | void Game::processPredictiveWalkCancel(const Position& pos, Otc::Direction dir) | |
| 546 | + | { | |
| 547 | + | m_walkPrediction += 1; | |
| 548 | + | if (m_localPlayer->predictiveCancelWalk(pos, m_walkPrediction, dir)) { | |
| 549 | + | m_walkId += 1; | |
| 550 | + | } | |
| 551 | + | } | |
| 552 | + | ||
| 553 | + | void Game::processWalkId(uint32_t walkId) | |
| 554 | + | { | |
| 555 | + | m_walkId = std::max(m_walkId, walkId); // fixes desync | |
| 556 | + | } | |
| 557 | + | ||
| 558 | + | void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName, const std::string& authenticatorToken, const std::string& sessionKey, const std::string& recordTo) | |
| 559 | + | { | |
| 560 | + | if(m_protocolGame || isOnline()) | |
| 561 | + | stdext::throw_exception("Unable to login into a world while already online or logging."); | |
| 562 | + | ||
| 563 | + | if(m_protocolVersion == 0) | |
| 564 | + | stdext::throw_exception("Must set a valid game protocol version before logging."); | |
| 565 | + | ||
| 566 | + | // reset the new game state | |
| 567 | + | resetGameStates(); | |
| 568 | + | ||
| 569 | + | m_localPlayer = LocalPlayerPtr(new LocalPlayer); | |
| 570 | + | m_localPlayer->setName(characterName); | |
| 571 | + | ||
| 572 | + | m_protocolGame = ProtocolGamePtr(new ProtocolGame); | |
| 573 | + | if (!recordTo.empty()) { | |
| 574 | + | m_protocolGame->setRecorder(PacketRecorderPtr(new PacketRecorder(recordTo))); | |
| 575 | + | } | |
| 576 | + | m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName, authenticatorToken, sessionKey, worldName); | |
| 577 | + | m_characterName = characterName; | |
| 578 | + | m_worldName = worldName; | |
| 579 | + | } | |
| 580 | + | ||
| 581 | + | void Game::playRecord(const std::string& file) | |
| 582 | + | { | |
| 583 | + | if (m_protocolGame || isOnline()) | |
| 584 | + | stdext::throw_exception("Unable to login into a world while already online or logging."); | |
| 585 | + | ||
| 586 | + | if (m_protocolVersion == 0) | |
| 587 | + | stdext::throw_exception("Must set a valid game protocol version before logging."); | |
| 588 | + | ||
| 589 | + | auto packetPlayer = PacketPlayerPtr(new PacketPlayer(file)); | |
| 590 | + | if (!packetPlayer) | |
| 591 | + | stdext::throw_exception("Invalid record file."); | |
| 592 | + | ||
| 593 | + | // reset the new game state | |
| 594 | + | resetGameStates(); | |
| 595 | + | ||
| 596 | + | m_localPlayer = LocalPlayerPtr(new LocalPlayer); | |
| 597 | + | m_localPlayer->setName("Player"); | |
| 598 | + | ||
| 599 | + | m_protocolGame = ProtocolGamePtr(new ProtocolGame); | |
| 600 | + | m_protocolGame->playRecord(packetPlayer); | |
| 601 | + | m_characterName = "Player"; | |
| 602 | + | m_worldName = "Record"; | |
| 603 | + | } | |
| 604 | + | ||
| 605 | + | void Game::cancelLogin() | |
| 606 | + | { | |
| 607 | + | // send logout even if the game has not started yet, to make sure that the player doesn't stay logged there | |
| 608 | + | if(m_protocolGame) | |
| 609 | + | m_protocolGame->sendLogout(); | |
| 610 | + | ||
| 611 | + | g_lua.callGlobalField("g_game", "onLogout"); | |
| 612 | + | processDisconnect(); | |
| 613 | + | } | |
| 614 | + | ||
| 615 | + | void Game::forceLogout() | |
| 616 | + | { | |
| 617 | + | if(!isOnline()) | |
| 618 | + | return; | |
| 619 | + | ||
| 620 | + | g_lua.callGlobalField("g_game", "onLogout"); | |
| 621 | + | m_protocolGame->sendLogout(); | |
| 622 | + | processDisconnect(); | |
| 623 | + | } | |
| 624 | + | ||
| 625 | + | void Game::safeLogout() | |
| 626 | + | { | |
| 627 | + | if(!isOnline()) | |
| 628 | + | return; | |
| 629 | + | ||
| 630 | + | g_lua.callGlobalField("g_game", "onLogout"); | |
| 631 | + | m_protocolGame->sendLogout(); | |
| 632 | + | } | |
| 633 | + | ||
| 634 | + | void Game::autoWalk(const std::vector<Otc::Direction>& dirs, Position startPos) | |
| 635 | + | { | |
| 636 | + | if(!canPerformGameAction()) | |
| 637 | + | return; | |
| 638 | + | ||
| 639 | + | if (dirs.size() == 0) | |
| 640 | + | return; | |
| 641 | + | ||
| 642 | + | // protocol limits walk path | |
| 643 | + | if((!g_game.getFeature(Otc::GameNewWalking) || dirs.size() > 4097) && dirs.size() > 127) { | |
| 644 | + | g_logger.error("Auto walk path too great"); | |
| 645 | + | return; | |
| 646 | + | } | |
| 647 | + | ||
| 648 | + | if (g_extras.debugWalking) { | |
| 649 | + | g_logger.info(stdext::format("[%i] Game::autoWalk", (int)g_clock.millis())); | |
| 650 | + | } | |
| 651 | + | ||
| 652 | + | // must cancel follow before any new walk | |
| 653 | + | if (isFollowing()) { | |
| 654 | + | cancelFollow(); | |
| 655 | + | } | |
| 656 | + | ||
| 657 | + | auto it = dirs.begin(); | |
| 658 | + | Otc::Direction direction = *it; | |
| 659 | + | ||
| 660 | + | uint8_t flags = 0x04; // auto walk flag | |
| 661 | + | ||
| 662 | + | TilePtr toTile = g_map.getTile(startPos.translatedToDirection(direction)); | |
| 663 | + | if(startPos == m_localPlayer->getPrewalkingPosition() && toTile && toTile->isWalkable() && !m_localPlayer->isWalking() && m_localPlayer->canWalk(direction, true)) { | |
| 664 | + | m_localPlayer->preWalk(direction); | |
| 665 | + | m_localPlayer->startServerWalking(); | |
| 666 | + | flags |= 0x01; // prewalk flag | |
| 667 | + | } | |
| 668 | + | ||
| 669 | + | g_lua.callGlobalField("g_game", "onAutoWalk", dirs); | |
| 670 | + | ||
| 671 | + | if (g_game.getFeature(Otc::GameNewWalking)) | |
| 672 | + | m_protocolGame->sendNewWalk(m_walkId, m_walkPrediction, startPos, flags, dirs); | |
| 673 | + | else | |
| 674 | + | m_protocolGame->sendAutoWalk(dirs); | |
| 675 | + | } | |
| 676 | + | ||
| 677 | + | void Game::walk(Otc::Direction direction, bool withPreWalk) | |
| 678 | + | { | |
| 679 | + | m_denyBotCall = false; | |
| 680 | + | if (!canPerformGameAction()) { | |
| 681 | + | m_denyBotCall = true; | |
| 682 | + | return; | |
| 683 | + | } | |
| 684 | + | if (g_extras.debugWalking) { | |
| 685 | + | g_logger.info(stdext::format("[%i] Game::walk", (int)g_clock.millis())); | |
| 686 | + | } | |
| 687 | + | ||
| 688 | + | g_lua.callGlobalField("g_game", "onWalk", direction, withPreWalk); | |
| 689 | + | ||
| 690 | + | if (g_game.getFeature(Otc::GameNewWalking)) { | |
| 691 | + | Position pos = m_localPlayer->getPrewalkingPosition(); | |
| 692 | + | uint8_t flags = 0; | |
| 693 | + | if (withPreWalk) { | |
| 694 | + | flags |= 0x01; | |
| 695 | + | } | |
| 696 | + | m_protocolGame->sendNewWalk(m_walkId, m_walkPrediction, pos, flags, { direction }); | |
| 697 | + | m_denyBotCall = true; | |
| 698 | + | return; | |
| 699 | + | } | |
| 700 | + | ||
| 701 | + | switch(direction) { | |
| 702 | + | case Otc::North: | |
| 703 | + | m_protocolGame->sendWalkNorth(); | |
| 704 | + | break; | |
| 705 | + | case Otc::East: | |
| 706 | + | m_protocolGame->sendWalkEast(); | |
| 707 | + | break; | |
| 708 | + | case Otc::South: | |
| 709 | + | m_protocolGame->sendWalkSouth(); | |
| 710 | + | break; | |
| 711 | + | case Otc::West: | |
| 712 | + | m_protocolGame->sendWalkWest(); | |
| 713 | + | break; | |
| 714 | + | case Otc::NorthEast: | |
| 715 | + | m_protocolGame->sendWalkNorthEast(); | |
| 716 | + | break; | |
| 717 | + | case Otc::SouthEast: | |
| 718 | + | m_protocolGame->sendWalkSouthEast(); | |
| 719 | + | break; | |
| 720 | + | case Otc::SouthWest: | |
| 721 | + | m_protocolGame->sendWalkSouthWest(); | |
| 722 | + | break; | |
| 723 | + | case Otc::NorthWest: | |
| 724 | + | m_protocolGame->sendWalkNorthWest(); | |
| 725 | + | break; | |
| 726 | + | default: | |
| 727 | + | break; | |
| 728 | + | } | |
| 729 | + | m_denyBotCall = true; | |
| 730 | + | } | |
| 731 | + | ||
| 732 | + | void Game::turn(Otc::Direction direction) | |
| 733 | + | { | |
| 734 | + | m_denyBotCall = false; | |
| 735 | + | if (!canPerformGameAction()) { | |
| 736 | + | m_denyBotCall = true; | |
| 737 | + | return; | |
| 738 | + | } | |
| 739 | + | ||
| 740 | + | if (g_game.getFeature(Otc::GameNewWalking)) { | |
| 741 | + | m_localPlayer->setDirection(direction); | |
| 742 | + | } | |
| 743 | + | ||
| 744 | + | switch(direction) { | |
| 745 | + | case Otc::North: | |
| 746 | + | m_protocolGame->sendTurnNorth(); | |
| 747 | + | break; | |
| 748 | + | case Otc::East: | |
| 749 | + | m_protocolGame->sendTurnEast(); | |
| 750 | + | break; | |
| 751 | + | case Otc::South: | |
| 752 | + | m_protocolGame->sendTurnSouth(); | |
| 753 | + | break; | |
| 754 | + | case Otc::West: | |
| 755 | + | m_protocolGame->sendTurnWest(); | |
| 756 | + | break; | |
| 757 | + | default: | |
| 758 | + | break; | |
| 759 | + | } | |
| 760 | + | m_denyBotCall = true; | |
| 761 | + | } | |
| 762 | + | ||
| 763 | + | void Game::stop() | |
| 764 | + | { | |
| 765 | + | if (g_extras.debugWalking) { | |
| 766 | + | g_logger.info(stdext::format("[%i] Game::stop", (int)g_clock.millis())); | |
| 767 | + | } | |
| 768 | + | ||
| 769 | + | m_denyBotCall = false; | |
| 770 | + | if (!canPerformGameAction()) { | |
| 771 | + | m_denyBotCall = true; | |
| 772 | + | return; | |
| 773 | + | } | |
| 774 | + | ||
| 775 | + | if(isFollowing()) | |
| 776 | + | cancelFollow(); // can change m_denyBotCall | |
| 777 | + | m_denyBotCall = false; | |
| 778 | + | ||
| 779 | + | m_protocolGame->sendStop(); | |
| 780 | + | m_denyBotCall = true; | |
| 781 | + | } | |
| 782 | + | ||
| 783 | + | void Game::look(const ThingPtr& thing, bool isBattleList) | |
| 784 | + | { | |
| 785 | + | if(!canPerformGameAction() || !thing) | |
| 786 | + | return; | |
| 787 | + | ||
| 788 | + | if(thing->isCreature() && isBattleList && m_protocolVersion >= 961) | |
| 789 | + | m_protocolGame->sendLookCreature(thing->getId()); | |
| 790 | + | else | |
| 791 | + | m_protocolGame->sendLook(thing->getPosition(), thing->getId(), thing->getStackPos()); | |
| 792 | + | } | |
| 793 | + | ||
| 794 | + | void Game::move(const ThingPtr& thing, const Position& toPos, int count) | |
| 795 | + | { | |
| 796 | + | if (count <= 0) | |
| 797 | + | count = 1; | |
| 798 | + | ||
| 799 | + | if (!canPerformGameAction() || !thing || thing->getPosition() == toPos) | |
| 800 | + | return; | |
| 801 | + | ||
| 802 | + | uint id = thing->getId(); | |
| 803 | + | if (thing->isCreature()) { | |
| 804 | + | CreaturePtr creature = thing->static_self_cast<Creature>(); | |
| 805 | + | id = Proto::Creature; | |
| 806 | + | } | |
| 807 | + | ||
| 808 | + | m_protocolGame->sendMove(thing->getPosition(), id, thing->getStackPos(), toPos, count); | |
| 809 | + | } | |
| 810 | + | ||
| 811 | + | void Game::moveRaw(const Position& pos, int id, int stackpos, const Position& toPos, int count) | |
| 812 | + | { | |
| 813 | + | if (!canPerformGameAction()) | |
| 814 | + | return; | |
| 815 | + | ||
| 816 | + | m_protocolGame->sendMove(pos, id, stackpos, toPos, count); | |
| 817 | + | } | |
| 818 | + | ||
| 819 | + | void Game::moveToParentContainer(const ThingPtr& thing, int count) | |
| 820 | + | { | |
| 821 | + | if(!canPerformGameAction() || !thing || count <= 0) | |
| 822 | + | return; | |
| 823 | + | ||
| 824 | + | Position position = thing->getPosition(); | |
| 825 | + | move(thing, Position(position.x, position.y, 254), count); | |
| 826 | + | } | |
| 827 | + | ||
| 828 | + | void Game::rotate(const ThingPtr& thing) | |
| 829 | + | { | |
| 830 | + | if(!canPerformGameAction() || !thing) | |
| 831 | + | return; | |
| 832 | + | ||
| 833 | + | m_protocolGame->sendRotateItem(thing->getPosition(), thing->getId(), thing->getStackPos()); | |
| 834 | + | } | |
| 835 | + | ||
| 836 | + | void Game::wrap(const ThingPtr& thing) | |
| 837 | + | { | |
| 838 | + | if (!canPerformGameAction() || !thing) | |
| 839 | + | return; | |
| 840 | + | ||
| 841 | + | m_protocolGame->sendWrapableItem(thing->getPosition(), thing->getId(), thing->getStackPos()); | |
| 842 | + | } | |
| 843 | + | ||
| 844 | + | void Game::use(const ThingPtr& thing) | |
| 845 | + | { | |
| 846 | + | if(!canPerformGameAction() || !thing) | |
| 847 | + | return; | |
| 848 | + | ||
| 849 | + | Position pos = thing->getPosition(); | |
| 850 | + | if(!pos.isValid()) // virtual item | |
| 851 | + | pos = Position(0xFFFF, 0, 0); // inventory item | |
| 852 | + | ||
| 853 | + | // some items, e.g. parcel, are not set as containers but they are. | |
| 854 | + | // always try to use these items in free container slots. | |
| 855 | + | m_protocolGame->sendUseItem(pos, thing->getId(), thing->getStackPos(), findEmptyContainerId()); | |
| 856 | + | ||
| 857 | + | g_lua.callGlobalField("g_game", "onUse", pos, thing->getId(), thing->getStackPos(), 0); | |
| 858 | + | } | |
| 859 | + | ||
| 860 | + | void Game::useInventoryItem(int itemId, int subType) | |
| 861 | + | { | |
| 862 | + | if(!canPerformGameAction() || !g_things.isValidDatId(itemId, ThingCategoryItem)) | |
| 863 | + | return; | |
| 864 | + | ||
| 865 | + | Position pos = Position(0xFFFF, 0, 0); // means that is a item in inventory | |
| 866 | + | ||
| 867 | + | m_protocolGame->sendUseItem(pos, itemId, 0, subType); | |
| 868 | + | ||
| 869 | + | g_lua.callGlobalField("g_game", "onUse", pos, itemId, 0, subType); | |
| 870 | + | } | |
| 871 | + | ||
| 872 | + | void Game::useWith(const ItemPtr& item, const ThingPtr& toThing, int subType) | |
| 873 | + | { | |
| 874 | + | if(!canPerformGameAction() || !item || !toThing) | |
| 875 | + | return; | |
| 876 | + | ||
| 877 | + | Position pos = item->getPosition(); | |
| 878 | + | if(!pos.isValid()) // virtual item | |
| 879 | + | pos = Position(0xFFFF, 0, 0); // means that is an item in inventory | |
| 880 | + | ||
| 881 | + | if(toThing->isCreature() && (g_game.getProtocolVersion() >= 780 || g_game.getFeature(Otc::GameForceAllowItemHotkeys))) | |
| 882 | + | m_protocolGame->sendUseOnCreature(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getId()); | |
| 883 | + | else | |
| 884 | + | m_protocolGame->sendUseItemWith(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getPosition(), toThing->getId(), toThing->getStackPos()); | |
| 885 | + | ||
| 886 | + | g_lua.callGlobalField("g_game", "onUseWith", pos, item->getId(), toThing, subType); | |
| 887 | + | } | |
| 888 | + | ||
| 889 | + | void Game::useInventoryItemWith(int itemId, const ThingPtr& toThing, int subType) | |
| 890 | + | { | |
| 891 | + | if(!canPerformGameAction() || !toThing) | |
| 892 | + | return; | |
| 893 | + | ||
| 894 | + | Position pos = Position(0xFFFF, 0, 0); // means that is a item in inventory | |
| 895 | + | ||
| 896 | + | if(toThing->isCreature()) | |
| 897 | + | m_protocolGame->sendUseOnCreature(pos, itemId, subType, toThing->getId()); | |
| 898 | + | else | |
| 899 | + | m_protocolGame->sendUseItemWith(pos, itemId, subType, toThing->getPosition(), toThing->getId(), toThing->getStackPos()); | |
| 900 | + | ||
| 901 | + | g_lua.callGlobalField("g_game", "onUseWith", pos, itemId, toThing, subType); | |
| 902 | + | } | |
| 903 | + | ||
| 904 | + | ItemPtr Game::findItemInContainers(uint itemId, int subType) | |
| 905 | + | { | |
| 906 | + | for(auto& it : m_containers) { | |
| 907 | + | const ContainerPtr& container = it.second; | |
| 908 | + | ||
| 909 | + | if(container) { | |
| 910 | + | ItemPtr item = container->findItemById(itemId, subType); | |
| 911 | + | if(item != nullptr) | |
| 912 | + | return item; | |
| 913 | + | } | |
| 914 | + | } | |
| 915 | + | return nullptr; | |
| 916 | + | } | |
| 917 | + | ||
| 918 | + | int Game::open(const ItemPtr& item, const ContainerPtr& previousContainer) | |
| 919 | + | { | |
| 920 | + | if(!canPerformGameAction() || !item) | |
| 921 | + | return -1; | |
| 922 | + | ||
| 923 | + | int id = 0; | |
| 924 | + | if(!previousContainer) | |
| 925 | + | id = findEmptyContainerId(); | |
| 926 | + | else | |
| 927 | + | id = previousContainer->getId(); | |
| 928 | + | ||
| 929 | + | m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackPos(), id); | |
| 930 | + | return id; | |
| 931 | + | } | |
| 932 | + | ||
| 933 | + | void Game::openParent(const ContainerPtr& container) | |
| 934 | + | { | |
| 935 | + | if(!canPerformGameAction() || !container) | |
| 936 | + | return; | |
| 937 | + | ||
| 938 | + | m_protocolGame->sendUpContainer(container->getId()); | |
| 939 | + | } | |
| 940 | + | ||
| 941 | + | void Game::close(const ContainerPtr& container) | |
| 942 | + | { | |
| 943 | + | if(!canPerformGameAction() || !container) | |
| 944 | + | return; | |
| 945 | + | ||
| 946 | + | m_protocolGame->sendCloseContainer(container->getId()); | |
| 947 | + | } | |
| 948 | + | ||
| 949 | + | void Game::refreshContainer(const ContainerPtr& container) | |
| 950 | + | { | |
| 951 | + | if(!canPerformGameAction()) | |
| 952 | + | return; | |
| 953 | + | m_protocolGame->sendRefreshContainer(container->getId()); | |
| 954 | + | } | |
| 955 | + | ||
| 956 | + | void Game::attack(CreaturePtr creature, bool cancel) | |
| 957 | + | { | |
| 958 | + | if(!canPerformGameAction() || creature == m_localPlayer) | |
| 959 | + | return; | |
| 960 | + | ||
| 961 | + | // cancel when attacking again | |
| 962 | + | if(creature && creature == m_attackingCreature) | |
| 963 | + | creature = nullptr; | |
| 964 | + | ||
| 965 | + | if(creature && isFollowing()) | |
| 966 | + | cancelFollow(); | |
| 967 | + | ||
| 968 | + | setAttackingCreature(creature); | |
| 969 | + | m_localPlayer->stopAutoWalk(); | |
| 970 | + | ||
| 971 | + | if(m_protocolVersion >= 963) { | |
| 972 | + | if(creature) | |
| 973 | + | m_seq = creature->getId(); | |
| 974 | + | } else | |
| 975 | + | m_seq++; | |
| 976 | + | ||
| 977 | + | if(!cancel) | |
| 978 | + | m_protocolGame->sendAttack(creature ? creature->getId() : 0, m_seq); | |
| 979 | + | } | |
| 980 | + | ||
| 981 | + | void Game::follow(CreaturePtr creature) | |
| 982 | + | { | |
| 983 | + | m_denyBotCall = false; | |
| 984 | + | if (!canPerformGameAction() || creature == m_localPlayer) { | |
| 985 | + | m_denyBotCall = true; | |
| 986 | + | return; | |
| 987 | + | } | |
| 988 | + | ||
| 989 | + | // cancel when following again | |
| 990 | + | if(creature && creature == m_followingCreature) | |
| 991 | + | creature = nullptr; | |
| 992 | + | ||
| 993 | + | if(creature && isAttacking()) | |
| 994 | + | cancelAttack(); | |
| 995 | + | ||
| 996 | + | setFollowingCreature(creature); | |
| 997 | + | m_localPlayer->stopAutoWalk(); | |
| 998 | + | ||
| 999 | + | if(m_protocolVersion >= 963) { | |
| 1000 | + | if(creature) | |
| 1001 | + | m_seq = creature->getId(); | |
| 1002 | + | } else | |
| 1003 | + | m_seq++; | |
| 1004 | + | ||
| 1005 | + | m_protocolGame->sendFollow(creature ? creature->getId() : 0, m_seq); | |
| 1006 | + | m_denyBotCall = true; | |
| 1007 | + | } | |
| 1008 | + | ||
| 1009 | + | void Game::cancelAttackAndFollow() | |
| 1010 | + | { | |
| 1011 | + | if(!canPerformGameAction()) | |
| 1012 | + | return; | |
| 1013 | + | ||
| 1014 | + | if(isFollowing()) | |
| 1015 | + | setFollowingCreature(nullptr); | |
| 1016 | + | if(isAttacking()) | |
| 1017 | + | setAttackingCreature(nullptr); | |
| 1018 | + | ||
| 1019 | + | m_localPlayer->stopAutoWalk(); | |
| 1020 | + | ||
| 1021 | + | m_protocolGame->sendCancelAttackAndFollow(); | |
| 1022 | + | ||
| 1023 | + | g_lua.callGlobalField("g_game", "onCancelAttackAndFollow"); | |
| 1024 | + | } | |
| 1025 | + | ||
| 1026 | + | void Game::talk(const std::string& message) | |
| 1027 | + | { | |
| 1028 | + | if(!canPerformGameAction() || message.empty()) | |
| 1029 | + | return; | |
| 1030 | + | ||
| 1031 | + | talkChannel(Otc::MessageSay, 0, message); | |
| 1032 | + | } | |
| 1033 | + | ||
| 1034 | + | void Game::talkChannel(Otc::MessageMode mode, int channelId, const std::string& message) | |
| 1035 | + | { | |
| 1036 | + | if(!canPerformGameAction() || message.empty()) | |
| 1037 | + | return; | |
| 1038 | + | ||
| 1039 | + | m_protocolGame->sendTalk(mode, channelId, "", message, m_localPlayer->getPosition(), m_localPlayer->getDirection()); | |
| 1040 | + | } | |
| 1041 | + | ||
| 1042 | + | void Game::talkPrivate(Otc::MessageMode mode, const std::string& receiver, const std::string& message) | |
| 1043 | + | { | |
| 1044 | + | if(!canPerformGameAction() || receiver.empty() || message.empty()) | |
| 1045 | + | return; | |
| 1046 | + | m_protocolGame->sendTalk(mode, 0, receiver, message, m_localPlayer->getPosition(), m_localPlayer->getDirection()); | |
| 1047 | + | } | |
| 1048 | + | ||
| 1049 | + | void Game::openPrivateChannel(const std::string& receiver) | |
| 1050 | + | { | |
| 1051 | + | if(!canPerformGameAction() || receiver.empty()) | |
| 1052 | + | return; | |
| 1053 | + | m_protocolGame->sendOpenPrivateChannel(receiver); | |
| 1054 | + | } | |
| 1055 | + | ||
| 1056 | + | void Game::requestChannels() | |
| 1057 | + | { | |
| 1058 | + | if(!canPerformGameAction()) | |
| 1059 | + | return; | |
| 1060 | + | m_protocolGame->sendRequestChannels(); | |
| 1061 | + | } | |
| 1062 | + | ||
| 1063 | + | void Game::joinChannel(int channelId) | |
| 1064 | + | { | |
| 1065 | + | if(!canPerformGameAction()) | |
| 1066 | + | return; | |
| 1067 | + | m_protocolGame->sendJoinChannel(channelId); | |
| 1068 | + | } | |
| 1069 | + | ||
| 1070 | + | void Game::leaveChannel(int channelId) | |
| 1071 | + | { | |
| 1072 | + | if(!canPerformGameAction()) | |
| 1073 | + | return; | |
| 1074 | + | m_protocolGame->sendLeaveChannel(channelId); | |
| 1075 | + | } | |
| 1076 | + | ||
| 1077 | + | void Game::closeNpcChannel() | |
| 1078 | + | { | |
| 1079 | + | if(!canPerformGameAction()) | |
| 1080 | + | return; | |
| 1081 | + | m_protocolGame->sendCloseNpcChannel(); | |
| 1082 | + | } | |
| 1083 | + | ||
| 1084 | + | void Game::openOwnChannel() | |
| 1085 | + | { | |
| 1086 | + | if(!canPerformGameAction()) | |
| 1087 | + | return; | |
| 1088 | + | m_protocolGame->sendOpenOwnChannel(); | |
| 1089 | + | } | |
| 1090 | + | ||
| 1091 | + | void Game::inviteToOwnChannel(const std::string& name) | |
| 1092 | + | { | |
| 1093 | + | if(!canPerformGameAction() || name.empty()) | |
| 1094 | + | return; | |
| 1095 | + | m_protocolGame->sendInviteToOwnChannel(name); | |
| 1096 | + | } | |
| 1097 | + | ||
| 1098 | + | void Game::excludeFromOwnChannel(const std::string& name) | |
| 1099 | + | { | |
| 1100 | + | if(!canPerformGameAction() || name.empty()) | |
| 1101 | + | return; | |
| 1102 | + | m_protocolGame->sendExcludeFromOwnChannel(name); | |
| 1103 | + | } | |
| 1104 | + | ||
| 1105 | + | void Game::partyInvite(int creatureId) | |
| 1106 | + | { | |
| 1107 | + | if(!canPerformGameAction()) | |
| 1108 | + | return; | |
| 1109 | + | m_protocolGame->sendInviteToParty(creatureId); | |
| 1110 | + | } | |
| 1111 | + | ||
| 1112 | + | void Game::partyJoin(int creatureId) | |
| 1113 | + | { | |
| 1114 | + | if(!canPerformGameAction()) | |
| 1115 | + | return; | |
| 1116 | + | m_protocolGame->sendJoinParty(creatureId); | |
| 1117 | + | } | |
| 1118 | + | ||
| 1119 | + | void Game::partyRevokeInvitation(int creatureId) | |
| 1120 | + | { | |
| 1121 | + | if(!canPerformGameAction()) | |
| 1122 | + | return; | |
| 1123 | + | m_protocolGame->sendRevokeInvitation(creatureId); | |
| 1124 | + | } | |
| 1125 | + | ||
| 1126 | + | void Game::partyPassLeadership(int creatureId) | |
| 1127 | + | { | |
| 1128 | + | if(!canPerformGameAction()) | |
| 1129 | + | return; | |
| 1130 | + | m_protocolGame->sendPassLeadership(creatureId); | |
| 1131 | + | } | |
| 1132 | + | ||
| 1133 | + | void Game::partyLeave() | |
| 1134 | + | { | |
| 1135 | + | if(!canPerformGameAction()) | |
| 1136 | + | return; | |
| 1137 | + | m_protocolGame->sendLeaveParty(); | |
| 1138 | + | } | |
| 1139 | + | ||
| 1140 | + | void Game::partyShareExperience(bool active) | |
| 1141 | + | { | |
| 1142 | + | if(!canPerformGameAction()) | |
| 1143 | + | return; | |
| 1144 | + | m_protocolGame->sendShareExperience(active); | |
| 1145 | + | } | |
| 1146 | + | ||
| 1147 | + | void Game::requestOutfit() | |
| 1148 | + | { | |
| 1149 | + | if(!canPerformGameAction()) | |
| 1150 | + | return; | |
| 1151 | + | m_protocolGame->sendRequestOutfit(); | |
| 1152 | + | } | |
| 1153 | + | ||
| 1154 | + | void Game::changeOutfit(const Outfit& outfit) | |
| 1155 | + | { | |
| 1156 | + | if(!canPerformGameAction()) | |
| 1157 | + | return; | |
| 1158 | + | m_protocolGame->sendChangeOutfit(outfit); | |
| 1159 | + | } | |
| 1160 | + | ||
| 1161 | + | void Game::addVip(const std::string& name) | |
| 1162 | + | { | |
| 1163 | + | if(!canPerformGameAction() || name.empty()) | |
| 1164 | + | return; | |
| 1165 | + | m_protocolGame->sendAddVip(name); | |
| 1166 | + | } | |
| 1167 | + | ||
| 1168 | + | void Game::removeVip(int playerId) | |
| 1169 | + | { | |
| 1170 | + | if(!canPerformGameAction()) | |
| 1171 | + | return; | |
| 1172 | + | ||
| 1173 | + | auto it = m_vips.find(playerId); | |
| 1174 | + | if(it == m_vips.end()) | |
| 1175 | + | return; | |
| 1176 | + | m_vips.erase(it); | |
| 1177 | + | m_protocolGame->sendRemoveVip(playerId); | |
| 1178 | + | } | |
| 1179 | + | ||
| 1180 | + | void Game::editVip(int playerId, const std::string& description, int iconId, bool notifyLogin) | |
| 1181 | + | { | |
| 1182 | + | if(!canPerformGameAction()) | |
| 1183 | + | return; | |
| 1184 | + | ||
| 1185 | + | auto it = m_vips.find(playerId); | |
| 1186 | + | if(it == m_vips.end()) | |
| 1187 | + | return; | |
| 1188 | + | ||
| 1189 | + | std::get<2>(m_vips[playerId]) = description; | |
| 1190 | + | std::get<3>(m_vips[playerId]) = iconId; | |
| 1191 | + | std::get<4>(m_vips[playerId]) = notifyLogin; | |
| 1192 | + | ||
| 1193 | + | if(getFeature(Otc::GameAdditionalVipInfo)) | |
| 1194 | + | m_protocolGame->sendEditVip(playerId, description, iconId, notifyLogin); | |
| 1195 | + | } | |
| 1196 | + | ||
| 1197 | + | void Game::setChaseMode(Otc::ChaseModes chaseMode) | |
| 1198 | + | { | |
| 1199 | + | if(!canPerformGameAction()) | |
| 1200 | + | return; | |
| 1201 | + | if(m_chaseMode == chaseMode) | |
| 1202 | + | return; | |
| 1203 | + | m_chaseMode = chaseMode; | |
| 1204 | + | m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); | |
| 1205 | + | g_lua.callGlobalField("g_game", "onChaseModeChange", chaseMode); | |
| 1206 | + | } | |
| 1207 | + | ||
| 1208 | + | void Game::setFightMode(Otc::FightModes fightMode) | |
| 1209 | + | { | |
| 1210 | + | if(!canPerformGameAction()) | |
| 1211 | + | return; | |
| 1212 | + | if(m_fightMode == fightMode) | |
| 1213 | + | return; | |
| 1214 | + | m_fightMode = fightMode; | |
| 1215 | + | m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); | |
| 1216 | + | g_lua.callGlobalField("g_game", "onFightModeChange", fightMode); | |
| 1217 | + | } | |
| 1218 | + | ||
| 1219 | + | void Game::setSafeFight(bool on) | |
| 1220 | + | { | |
| 1221 | + | if(!canPerformGameAction()) | |
| 1222 | + | return; | |
| 1223 | + | if(m_safeFight == on) | |
| 1224 | + | return; | |
| 1225 | + | m_safeFight = on; | |
| 1226 | + | m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); | |
| 1227 | + | g_lua.callGlobalField("g_game", "onSafeFightChange", on); | |
| 1228 | + | } | |
| 1229 | + | ||
| 1230 | + | void Game::setPVPMode(Otc::PVPModes pvpMode) | |
| 1231 | + | { | |
| 1232 | + | if(!canPerformGameAction()) | |
| 1233 | + | return; | |
| 1234 | + | if(!getFeature(Otc::GamePVPMode)) | |
| 1235 | + | return; | |
| 1236 | + | if(m_pvpMode == pvpMode) | |
| 1237 | + | return; | |
| 1238 | + | m_pvpMode = pvpMode; | |
| 1239 | + | m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); | |
| 1240 | + | g_lua.callGlobalField("g_game", "onPVPModeChange", pvpMode); | |
| 1241 | + | } | |
| 1242 | + | ||
| 1243 | + | void Game::setUnjustifiedPoints(UnjustifiedPoints unjustifiedPoints) | |
| 1244 | + | { | |
| 1245 | + | if(!canPerformGameAction()) | |
| 1246 | + | return; | |
| 1247 | + | if(!getFeature(Otc::GameUnjustifiedPoints)) | |
| 1248 | + | return; | |
| 1249 | + | if(m_unjustifiedPoints == unjustifiedPoints) | |
| 1250 | + | return; | |
| 1251 | + | ||
| 1252 | + | m_unjustifiedPoints = unjustifiedPoints; | |
| 1253 | + | g_lua.callGlobalField("g_game", "onUnjustifiedPointsChange", unjustifiedPoints); | |
| 1254 | + | } | |
| 1255 | + | ||
| 1256 | + | void Game::setOpenPvpSituations(int openPvpSituations) | |
| 1257 | + | { | |
| 1258 | + | if(!canPerformGameAction()) | |
| 1259 | + | return; | |
| 1260 | + | if(m_openPvpSituations == openPvpSituations) | |
| 1261 | + | return; | |
| 1262 | + | ||
| 1263 | + | m_openPvpSituations = openPvpSituations; | |
| 1264 | + | g_lua.callGlobalField("g_game", "onOpenPvpSituationsChange", openPvpSituations); | |
| 1265 | + | } | |
| 1266 | + | ||
| 1267 | + | ||
| 1268 | + | void Game::inspectNpcTrade(const ItemPtr& item) | |
| 1269 | + | { | |
| 1270 | + | if(!canPerformGameAction() || !item) | |
| 1271 | + | return; | |
| 1272 | + | m_protocolGame->sendInspectNpcTrade(item->getId(), item->getCount()); | |
| 1273 | + | } | |
| 1274 | + | ||
| 1275 | + | void Game::buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack) | |
| 1276 | + | { | |
| 1277 | + | if(!canPerformGameAction() || !item) | |
| 1278 | + | return; | |
| 1279 | + | m_protocolGame->sendBuyItem(item->getId(), item->getCountOrSubType(), amount, ignoreCapacity, buyWithBackpack); | |
| 1280 | + | } | |
| 1281 | + | ||
| 1282 | + | void Game::sellItem(const ItemPtr& item, int amount, bool ignoreEquipped) | |
| 1283 | + | { | |
| 1284 | + | if(!canPerformGameAction() || !item) | |
| 1285 | + | return; | |
| 1286 | + | m_protocolGame->sendSellItem(item->getId(), item->getCountOrSubType(), amount, ignoreEquipped); | |
| 1287 | + | } | |
| 1288 | + | ||
| 1289 | + | void Game::closeNpcTrade() | |
| 1290 | + | { | |
| 1291 | + | if(!canPerformGameAction()) | |
| 1292 | + | return; | |
| 1293 | + | m_protocolGame->sendCloseNpcTrade(); | |
| 1294 | + | } | |
| 1295 | + | ||
| 1296 | + | void Game::requestTrade(const ItemPtr& item, const CreaturePtr& creature) | |
| 1297 | + | { | |
| 1298 | + | if(!canPerformGameAction() || !item || !creature) | |
| 1299 | + | return; | |
| 1300 | + | m_protocolGame->sendRequestTrade(item->getPosition(), item->getId(), item->getStackPos(), creature->getId()); | |
| 1301 | + | } | |
| 1302 | + | ||
| 1303 | + | void Game::inspectTrade(bool counterOffer, int index) | |
| 1304 | + | { | |
| 1305 | + | if(!canPerformGameAction()) | |
| 1306 | + | return; | |
| 1307 | + | m_protocolGame->sendInspectTrade(counterOffer, index); | |
| 1308 | + | } | |
| 1309 | + | ||
| 1310 | + | void Game::acceptTrade() | |
| 1311 | + | { | |
| 1312 | + | if(!canPerformGameAction()) | |
| 1313 | + | return; | |
| 1314 | + | m_protocolGame->sendAcceptTrade(); | |
| 1315 | + | } | |
| 1316 | + | ||
| 1317 | + | void Game::rejectTrade() | |
| 1318 | + | { | |
| 1319 | + | if(!canPerformGameAction()) | |
| 1320 | + | return; | |
| 1321 | + | m_protocolGame->sendRejectTrade(); | |
| 1322 | + | } | |
| 1323 | + | ||
| 1324 | + | void Game::editText(uint id, const std::string& text) | |
| 1325 | + | { | |
| 1326 | + | if(!canPerformGameAction()) | |
| 1327 | + | return; | |
| 1328 | + | m_protocolGame->sendEditText(id, text); | |
| 1329 | + | } | |
| 1330 | + | ||
| 1331 | + | void Game::editList(uint id, int doorId, const std::string& text) | |
| 1332 | + | { | |
| 1333 | + | if(!canPerformGameAction()) | |
| 1334 | + | return; | |
| 1335 | + | m_protocolGame->sendEditList(id, doorId, text); | |
| 1336 | + | } | |
| 1337 | + | ||
| 1338 | + | void Game::openRuleViolation(const std::string& reporter) | |
| 1339 | + | { | |
| 1340 | + | if(!canPerformGameAction()) | |
| 1341 | + | return; | |
| 1342 | + | m_protocolGame->sendOpenRuleViolation(reporter); | |
| 1343 | + | } | |
| 1344 | + | ||
| 1345 | + | void Game::closeRuleViolation(const std::string& reporter) | |
| 1346 | + | { | |
| 1347 | + | if(!canPerformGameAction()) | |
| 1348 | + | return; | |
| 1349 | + | m_protocolGame->sendCloseRuleViolation(reporter); | |
| 1350 | + | } | |
| 1351 | + | ||
| 1352 | + | void Game::cancelRuleViolation() | |
| 1353 | + | { | |
| 1354 | + | if(!canPerformGameAction()) | |
| 1355 | + | return; | |
| 1356 | + | m_protocolGame->sendCancelRuleViolation(); | |
| 1357 | + | } | |
| 1358 | + | ||
| 1359 | + | void Game::reportBug(const std::string& comment) | |
| 1360 | + | { | |
| 1361 | + | if(!canPerformGameAction()) | |
| 1362 | + | return; | |
| 1363 | + | m_protocolGame->sendBugReport(comment); | |
| 1364 | + | } | |
| 1365 | + | ||
| 1366 | + | void Game::reportRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment) | |
| 1367 | + | { | |
| 1368 | + | if(!canPerformGameAction()) | |
| 1369 | + | return; | |
| 1370 | + | m_protocolGame->sendRuleViolation(target, reason, action, comment, statement, statementId, ipBanishment); | |
| 1371 | + | } | |
| 1372 | + | ||
| 1373 | + | void Game::debugReport(const std::string& a, const std::string& b, const std::string& c, const std::string& d) | |
| 1374 | + | { | |
| 1375 | + | m_protocolGame->sendDebugReport(a, b, c, d); | |
| 1376 | + | } | |
| 1377 | + | ||
| 1378 | + | void Game::requestQuestLog() | |
| 1379 | + | { | |
| 1380 | + | if(!canPerformGameAction()) | |
| 1381 | + | return; | |
| 1382 | + | m_protocolGame->sendRequestQuestLog(); | |
| 1383 | + | } | |
| 1384 | + | ||
| 1385 | + | void Game::requestQuestLine(int questId) | |
| 1386 | + | { | |
| 1387 | + | if(!canPerformGameAction()) | |
| 1388 | + | return; | |
| 1389 | + | m_protocolGame->sendRequestQuestLine(questId); | |
| 1390 | + | } | |
| 1391 | + | ||
| 1392 | + | void Game::equipItem(const ItemPtr& item) | |
| 1393 | + | { | |
| 1394 | + | if (!item || !canPerformGameAction()) | |
| 1395 | + | return; | |
| 1396 | + | m_protocolGame->sendEquipItem(item->getId(), item->getCountOrSubType()); | |
| 1397 | + | } | |
| 1398 | + | ||
| 1399 | + | void Game::equipItemId(int itemId, int subType) | |
| 1400 | + | { | |
| 1401 | + | if (!canPerformGameAction()) | |
| 1402 | + | return; | |
| 1403 | + | m_protocolGame->sendEquipItem(itemId, subType); | |
| 1404 | + | } | |
| 1405 | + | ||
| 1406 | + | void Game::mount(bool mount) | |
| 1407 | + | { | |
| 1408 | + | if(!canPerformGameAction()) | |
| 1409 | + | return; | |
| 1410 | + | m_protocolGame->sendOutfitExtensionStatus(mount ? 1 : 0); | |
| 1411 | + | } | |
| 1412 | + | ||
| 1413 | + | void Game::setOutfitExtensions(int mount, int wings, int aura, int shader, int healthBar, int manaBar) | |
| 1414 | + | { | |
| 1415 | + | if (!canPerformGameAction()) | |
| 1416 | + | return; | |
| 1417 | + | m_protocolGame->sendOutfitExtensionStatus(mount, wings, aura, shader, healthBar, manaBar); | |
| 1418 | + | } | |
| 1419 | + | ||
| 1420 | + | void Game::requestItemInfo(const ItemPtr& item, int index) | |
| 1421 | + | { | |
| 1422 | + | if(!canPerformGameAction()) | |
| 1423 | + | return; | |
| 1424 | + | m_protocolGame->sendRequestItemInfo(item->getId(), item->getSubType(), index); | |
| 1425 | + | } | |
| 1426 | + | ||
| 1427 | + | void Game::answerModalDialog(uint32 dialog, int button, int choice) | |
| 1428 | + | { | |
| 1429 | + | if(!canPerformGameAction()) | |
| 1430 | + | return; | |
| 1431 | + | m_protocolGame->sendAnswerModalDialog(dialog, button, choice); | |
| 1432 | + | } | |
| 1433 | + | ||
| 1434 | + | void Game::browseField(const Position& position) | |
| 1435 | + | { | |
| 1436 | + | if(!canPerformGameAction()) | |
| 1437 | + | return; | |
| 1438 | + | m_protocolGame->sendBrowseField(position); | |
| 1439 | + | } | |
| 1440 | + | ||
| 1441 | + | void Game::seekInContainer(int cid, int index) | |
| 1442 | + | { | |
| 1443 | + | if(!canPerformGameAction()) | |
| 1444 | + | return; | |
| 1445 | + | m_protocolGame->sendSeekInContainer(cid, index); | |
| 1446 | + | } | |
| 1447 | + | ||
| 1448 | + | void Game::buyStoreOffer(int offerId, int productType, const std::string& name) | |
| 1449 | + | { | |
| 1450 | + | if(!canPerformGameAction()) | |
| 1451 | + | return; | |
| 1452 | + | m_protocolGame->sendBuyStoreOffer(offerId, productType, name); | |
| 1453 | + | } | |
| 1454 | + | ||
| 1455 | + | void Game::requestTransactionHistory(int page, int entriesPerPage) | |
| 1456 | + | { | |
| 1457 | + | if(!canPerformGameAction()) | |
| 1458 | + | return; | |
| 1459 | + | m_protocolGame->sendRequestTransactionHistory(page, entriesPerPage); | |
| 1460 | + | } | |
| 1461 | + | ||
| 1462 | + | void Game::requestStoreOffers(const std::string& categoryName, int serviceType) | |
| 1463 | + | { | |
| 1464 | + | if(!canPerformGameAction()) | |
| 1465 | + | return; | |
| 1466 | + | m_protocolGame->sendRequestStoreOffers(categoryName, serviceType); | |
| 1467 | + | } | |
| 1468 | + | ||
| 1469 | + | void Game::openStore(int serviceType) | |
| 1470 | + | { | |
| 1471 | + | if(!canPerformGameAction()) | |
| 1472 | + | return; | |
| 1473 | + | m_protocolGame->sendOpenStore(serviceType); | |
| 1474 | + | } | |
| 1475 | + | ||
| 1476 | + | void Game::transferCoins(const std::string& recipient, int amount) | |
| 1477 | + | { | |
| 1478 | + | if(!canPerformGameAction()) | |
| 1479 | + | return; | |
| 1480 | + | m_protocolGame->sendTransferCoins(recipient, amount); | |
| 1481 | + | } | |
| 1482 | + | ||
| 1483 | + | void Game::openTransactionHistory(int entriesPerPage) | |
| 1484 | + | { | |
| 1485 | + | if(!canPerformGameAction()) | |
| 1486 | + | return; | |
| 1487 | + | m_protocolGame->sendOpenTransactionHistory(entriesPerPage); | |
| 1488 | + | } | |
| 1489 | + | ||
| 1490 | + | void Game::preyAction(int slot, int actionType, int index) | |
| 1491 | + | { | |
| 1492 | + | if (!canPerformGameAction()) | |
| 1493 | + | return; | |
| 1494 | + | m_protocolGame->sendPreyAction(slot, actionType, index); | |
| 1495 | + | } | |
| 1496 | + | ||
| 1497 | + | void Game::preyRequest() | |
| 1498 | + | { | |
| 1499 | + | if (!canPerformGameAction()) | |
| 1500 | + | return; | |
| 1501 | + | m_protocolGame->sendPreyRequest(); | |
| 1502 | + | } | |
| 1503 | + | ||
| 1504 | + | ||
| 1505 | + | void Game::applyImbuement(uint8_t slot, uint32_t imbuementId, bool protectionCharm) | |
| 1506 | + | { | |
| 1507 | + | if (!canPerformGameAction()) | |
| 1508 | + | return; | |
| 1509 | + | m_protocolGame->sendApplyImbuement(slot, imbuementId, protectionCharm); | |
| 1510 | + | } | |
| 1511 | + | ||
| 1512 | + | void Game::clearImbuement(uint8_t slot) | |
| 1513 | + | { | |
| 1514 | + | if (!canPerformGameAction()) | |
| 1515 | + | return; | |
| 1516 | + | m_protocolGame->sendClearImbuement(slot); | |
| 1517 | + | } | |
| 1518 | + | ||
| 1519 | + | void Game::closeImbuingWindow() | |
| 1520 | + | { | |
| 1521 | + | if (!canPerformGameAction()) | |
| 1522 | + | return; | |
| 1523 | + | m_protocolGame->sendCloseImbuingWindow(); | |
| 1524 | + | } | |
| 1525 | + | ||
| 1526 | + | void Game::ping() | |
| 1527 | + | { | |
| 1528 | + | if(!m_protocolGame || !m_protocolGame->isConnected()) | |
| 1529 | + | return; | |
| 1530 | + | ||
| 1531 | + | if(m_pingReceived != m_pingSent) | |
| 1532 | + | return; | |
| 1533 | + | ||
| 1534 | + | m_denyBotCall = false; | |
| 1535 | + | m_protocolGame->sendPing(); | |
| 1536 | + | m_denyBotCall = true; | |
| 1537 | + | m_pingSent++; | |
| 1538 | + | m_pingTimer.restart(); | |
| 1539 | + | } | |
| 1540 | + | ||
| 1541 | + | void Game::newPing() | |
| 1542 | + | { | |
| 1543 | + | if(!m_protocolGame || !m_protocolGame->isConnected()) | |
| 1544 | + | return; | |
| 1545 | + | ||
| 1546 | + | static uint32_t pingId = 1; | |
| 1547 | + | pingId += 1; | |
| 1548 | + | m_newPingIds[pingId] = stdext::timer(); | |
| 1549 | + | ||
| 1550 | + | m_protocolGame->sendNewPing(pingId, (int16_t)m_ping, (int16_t)g_app.getFps()); | |
| 1551 | + | m_newPingEvent = g_dispatcher.scheduleEvent([] { | |
| 1552 | + | g_game.newPing(); | |
| 1553 | + | }, m_newPingDelay); | |
| 1554 | + | } | |
| 1555 | + | ||
| 1556 | + | void Game::changeMapAwareRange(int xrange, int yrange) | |
| 1557 | + | { | |
| 1558 | + | if(!canPerformGameAction()) | |
| 1559 | + | return; | |
| 1560 | + | m_protocolGame->sendChangeMapAwareRange(xrange, yrange); | |
| 1561 | + | } | |
| 1562 | + | ||
| 1563 | + | bool Game::checkBotProtection() | |
| 1564 | + | { | |
| 1565 | + | if (getFeature(Otc::GameBotProtection)) { | |
| 1566 | + | // accepts calls comming from a stacktrace containing only C++ functions, | |
| 1567 | + | // if the stacktrace contains a lua function, then only accept if the engine is processing an input event | |
| 1568 | + | if (m_denyBotCall && g_lua.isInCppCallback() && !g_app.isOnInputEvent() && !g_dispatcher.isBotSafe()) { | |
| 1569 | + | g_logger.error(g_lua.traceback("caught a lua call to a bot protected game function, the call was cancelled")); | |
| 1570 | + | return false; | |
| 1571 | + | } | |
| 1572 | + | } | |
| 1573 | + | ||
| 1574 | + | return true; | |
| 1575 | + | } | |
| 1576 | + | ||
| 1577 | + | bool Game::canPerformGameAction() | |
| 1578 | + | { | |
| 1579 | + | // we can only perform game actions if we meet these conditions: | |
| 1580 | + | // - the game is online | |
| 1581 | + | // - the local player exists | |
| 1582 | + | // - the local player is not dead | |
| 1583 | + | // - we have a game protocol | |
| 1584 | + | // - the game protocol is connected | |
| 1585 | + | // - its not a bot action | |
| 1586 | + | return m_online && m_localPlayer && !m_localPlayer->isDead() && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection(); | |
| 1587 | + | } | |
| 1588 | + | ||
| 1589 | + | void Game::setProtocolVersion(int version) | |
| 1590 | + | { | |
| 1591 | + | if(m_protocolVersion == version) | |
| 1592 | + | return; | |
| 1593 | + | ||
| 1594 | + | if(isOnline()) | |
| 1595 | + | stdext::throw_exception("Unable to change protocol version while online"); | |
| 1596 | + | ||
| 1597 | + | m_protocolVersion = version; | |
| 1598 | + | ||
| 1599 | + | Proto::buildMessageModesMap(version); | |
| 1600 | + | ||
| 1601 | + | g_lua.callGlobalField("g_game", "onProtocolVersionChange", version); | |
| 1602 | + | } | |
| 1603 | + | ||
| 1604 | + | void Game::setClientVersion(int version) | |
| 1605 | + | { | |
| 1606 | + | if(isOnline()) | |
| 1607 | + | stdext::throw_exception("Unable to change client version while online"); | |
| 1608 | + | ||
| 1609 | + | m_clientVersion = version; | |
| 1610 | + | g_lua.callGlobalField("g_game", "onClientVersionChange", version); | |
| 1611 | + | } | |
| 1612 | + | ||
| 1613 | + | void Game::setAttackingCreature(const CreaturePtr& creature) | |
| 1614 | + | { | |
| 1615 | + | if(creature != m_attackingCreature) { | |
| 1616 | + | CreaturePtr oldCreature = m_attackingCreature; | |
| 1617 | + | m_attackingCreature = creature; | |
| 1618 | + | ||
| 1619 | + | g_lua.callGlobalField("g_game", "onAttackingCreatureChange", creature, oldCreature); | |
| 1620 | + | } | |
| 1621 | + | } | |
| 1622 | + | ||
| 1623 | + | void Game::setFollowingCreature(const CreaturePtr& creature) | |
| 1624 | + | { | |
| 1625 | + | CreaturePtr oldCreature = m_followingCreature; | |
| 1626 | + | m_followingCreature = creature; | |
| 1627 | + | ||
| 1628 | + | g_lua.callGlobalField("g_game", "onFollowingCreatureChange", creature, oldCreature); | |
| 1629 | + | } | |
| 1630 | + | ||
| 1631 | + | std::string Game::formatCreatureName(const std::string& name) | |
| 1632 | + | { | |
| 1633 | + | std::string formatedName = name; | |
| 1634 | + | if(getFeature(Otc::GameFormatCreatureName) && name.length() > 0) { | |
| 1635 | + | bool upnext = true; | |
| 1636 | + | for(uint i=0;i<formatedName.length();++i) { | |
| 1637 | + | char ch = formatedName[i]; | |
| 1638 | + | if(upnext) { | |
| 1639 | + | formatedName[i] = stdext::upchar(ch); | |
| 1640 | + | upnext = false; | |
| 1641 | + | } | |
| 1642 | + | if(ch == ' ') | |
| 1643 | + | upnext = true; | |
| 1644 | + | } | |
| 1645 | + | } | |
| 1646 | + | return formatedName; | |
| 1647 | + | } | |
| 1648 | + | ||
| 1649 | + | int Game::findEmptyContainerId() | |
| 1650 | + | { | |
| 1651 | + | int id = 0; | |
| 1652 | + | while(m_containers[id] != nullptr) | |
| 1653 | + | id++; | |
| 1654 | + | return id; | |
| 1655 | + | } | |
| 1656 | + | ||
| 1657 | + | int Game::getOs() | |
| 1658 | + | { | |
| 1659 | + | if(m_clientCustomOs >= 0) | |
| 1660 | + | return m_clientCustomOs; | |
| 1661 | + | ||
| 1662 | + | if(g_app.getOs() == "windows") | |
| 1663 | + | return 20; | |
| 1664 | + | if(g_app.getOs() == "mac") | |
| 1665 | + | return 22; | |
| 1666 | + | if (g_app.getOs() == "android") | |
| 1667 | + | return 23; | |
| 1668 | + | if (g_app.getOs() == "ios") | |
| 1669 | + | return 24; | |
| 1670 | + | if (g_app.getOs() == "web") | |
| 1671 | + | return 25; | |
| 1672 | + | return 21; // linux | |
| 1673 | + | } |
| @@ -0,0 +1,484 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef GAME_H | |
| 24 | + | #define GAME_H | |
| 25 | + | ||
| 26 | + | #include "declarations.h" | |
| 27 | + | #include "item.h" | |
| 28 | + | #include "animatedtext.h" | |
| 29 | + | #include "effect.h" | |
| 30 | + | #include "creature.h" | |
| 31 | + | #include "container.h" | |
| 32 | + | #include "protocolgame.h" | |
| 33 | + | #include "localplayer.h" | |
| 34 | + | #include "outfit.h" | |
| 35 | + | #include <framework/core/timer.h> | |
| 36 | + | ||
| 37 | + | #include <bitset> | |
| 38 | + | ||
| 39 | + | struct UnjustifiedPoints { | |
| 40 | + | bool operator==(const UnjustifiedPoints& other) const { | |
| 41 | + | return killsDay == other.killsDay && | |
| 42 | + | killsDayRemaining == other.killsDayRemaining && | |
| 43 | + | killsWeek == other.killsWeek && | |
| 44 | + | killsWeekRemaining == other.killsWeekRemaining && | |
| 45 | + | killsMonth == other.killsMonth && | |
| 46 | + | killsMonthRemaining == other.killsMonthRemaining && | |
| 47 | + | skullTime == other.skullTime; | |
| 48 | + | } | |
| 49 | + | uint8 killsDay; | |
| 50 | + | uint8 killsDayRemaining; | |
| 51 | + | uint8 killsWeek; | |
| 52 | + | uint8 killsWeekRemaining; | |
| 53 | + | uint8 killsMonth; | |
| 54 | + | uint8 killsMonthRemaining; | |
| 55 | + | uint8 skullTime; | |
| 56 | + | }; | |
| 57 | + | ||
| 58 | + | typedef std::tuple<std::string, uint, std::string, int, bool> Vip; | |
| 59 | + | ||
| 60 | + | //@bindsingleton g_game | |
| 61 | + | class Game | |
| 62 | + | { | |
| 63 | + | public: | |
| 64 | + | Game(); | |
| 65 | + | ||
| 66 | + | void init(); | |
| 67 | + | void terminate(); | |
| 68 | + | ||
| 69 | + | private: | |
| 70 | + | void resetGameStates(); | |
| 71 | + | ||
| 72 | + | protected: | |
| 73 | + | void processConnectionError(const boost::system::error_code& error); | |
| 74 | + | void processDisconnect(); | |
| 75 | + | void processPing(); | |
| 76 | + | void processPingBack(); | |
| 77 | + | void processNewPing(uint32_t pingId); | |
| 78 | + | ||
| 79 | + | void processUpdateNeeded(const std::string& signature); | |
| 80 | + | void processLoginError(const std::string& error); | |
| 81 | + | void processLoginAdvice(const std::string& message); | |
| 82 | + | void processLoginWait(const std::string& message, int time); | |
| 83 | + | void processLoginToken(bool unknown); | |
| 84 | + | void processLogin(); | |
| 85 | + | void processPendingGame(); | |
| 86 | + | void processEnterGame(); | |
| 87 | + | ||
| 88 | + | void processGameStart(); | |
| 89 | + | void processGameEnd(); | |
| 90 | + | void processDeath(int deathType, int penality); | |
| 91 | + | ||
| 92 | + | void processGMActions(const std::vector<uint8>& actions); | |
| 93 | + | void processInventoryChange(int slot, const ItemPtr& item); | |
| 94 | + | void processAttackCancel(uint seq); | |
| 95 | + | void processWalkCancel(Otc::Direction direction); | |
| 96 | + | ||
| 97 | + | void processNewWalkCancel(Otc::Direction dir); | |
| 98 | + | void processPredictiveWalkCancel(const Position& pos, Otc::Direction dir); | |
| 99 | + | void processWalkId(uint32_t walkId); | |
| 100 | + | ||
| 101 | + | void processPlayerHelpers(int helpers); | |
| 102 | + | void processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode, Otc::PVPModes pvpMode); | |
| 103 | + | ||
| 104 | + | // message related | |
| 105 | + | void processTextMessage(Otc::MessageMode mode, const std::string& text); | |
| 106 | + | void processTalk(const std::string& name, int level, Otc::MessageMode mode, const std::string& text, int channelId, const Position& pos); | |
| 107 | + | ||
| 108 | + | // container related | |
| 109 | + | void processOpenContainer(int containerId, const ItemPtr& containerItem, const std::string& name, int capacity, bool hasParent, const std::vector<ItemPtr>& items, bool isUnlocked, bool hasPages, int containerSize, int firstIndex); | |
| 110 | + | void processCloseContainer(int containerId); | |
| 111 | + | void processContainerAddItem(int containerId, const ItemPtr& item, int slot); | |
| 112 | + | void processContainerUpdateItem(int containerId, int slot, const ItemPtr& item); | |
| 113 | + | void processContainerRemoveItem(int containerId, int slot, const ItemPtr& lastItem); | |
| 114 | + | ||
| 115 | + | // channel related | |
| 116 | + | void processChannelList(const std::vector<std::tuple<int, std::string> >& channelList); | |
| 117 | + | void processOpenChannel(int channelId, const std::string& name); | |
| 118 | + | void processOpenPrivateChannel(const std::string& name); | |
| 119 | + | void processOpenOwnPrivateChannel(int channelId, const std::string& name); | |
| 120 | + | void processCloseChannel(int channelId); | |
| 121 | + | ||
| 122 | + | // rule violations | |
| 123 | + | void processRuleViolationChannel(int channelId); | |
| 124 | + | void processRuleViolationRemove(const std::string& name); | |
| 125 | + | void processRuleViolationCancel(const std::string& name); | |
| 126 | + | void processRuleViolationLock(); | |
| 127 | + | ||
| 128 | + | // vip related | |
| 129 | + | void processVipAdd(uint id, const std::string& name, uint status, const std::string& description, int iconId, bool notifyLogin); | |
| 130 | + | void processVipStateChange(uint id, uint status); | |
| 131 | + | ||
| 132 | + | // tutorial hint | |
| 133 | + | void processTutorialHint(int id); | |
| 134 | + | void processAddAutomapFlag(const Position& pos, int icon, const std::string& message); | |
| 135 | + | void processRemoveAutomapFlag(const Position& pos, int icon, const std::string& message); | |
| 136 | + | ||
| 137 | + | // outfit | |
| 138 | + | void processOpenOutfitWindow(const Outfit& currentOutfit, const std::vector<std::tuple<int, std::string, int>>& outfitList, | |
| 139 | + | const std::vector<std::tuple<int, std::string>>& mountList, | |
| 140 | + | const std::vector<std::tuple<int, std::string>>& wingList, | |
| 141 | + | const std::vector<std::tuple<int, std::string>>& auraList, | |
| 142 | + | const std::vector<std::tuple<int, std::string>>& shaderList, | |
| 143 | + | const std::vector<std::tuple<int, std::string>>& healthBarList, | |
| 144 | + | const std::vector<std::tuple<int, std::string>>& manaBarList); | |
| 145 | + | ||
| 146 | + | // npc trade | |
| 147 | + | void processOpenNpcTrade(const std::vector<std::tuple<ItemPtr, std::string, int, int64_t, int64_t> >& items); | |
| 148 | + | void processPlayerGoods(uint64_t money, const std::vector<std::tuple<ItemPtr, int> >& goods); | |
| 149 | + | void processCloseNpcTrade(); | |
| 150 | + | ||
| 151 | + | // player trade | |
| 152 | + | void processOwnTrade(const std::string& name, const std::vector<ItemPtr>& items); | |
| 153 | + | void processCounterTrade(const std::string& name, const std::vector<ItemPtr>& items); | |
| 154 | + | void processCloseTrade(); | |
| 155 | + | ||
| 156 | + | // edit text/list | |
| 157 | + | void processEditText(uint id, int itemId, int maxLength, const std::string& text, const std::string& writer, const std::string& date); | |
| 158 | + | void processEditList(uint id, int doorId, const std::string& text); | |
| 159 | + | ||
| 160 | + | // questlog | |
| 161 | + | void processQuestLog(const std::vector<std::tuple<int, std::string, bool> >& questList); | |
| 162 | + | void processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string, int> >& questMissions); | |
| 163 | + | ||
| 164 | + | // modal dialogs >= 970 | |
| 165 | + | void processModalDialog(uint32 id, std::string title, std::string message, std::vector<std::tuple<int, std::string> > buttonList, int enterButton, int escapeButton, std::vector<std::tuple<int, std::string> > choiceList, bool priority); | |
| 166 | + | ||
| 167 | + | friend class ProtocolGame; | |
| 168 | + | friend class Map; | |
| 169 | + | ||
| 170 | + | public: | |
| 171 | + | // login related | |
| 172 | + | void loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName, const std::string& authenticatorToken, const std::string& sessionKey, const std::string& recordTo = ""); | |
| 173 | + | void playRecord(const std::string& file); | |
| 174 | + | void cancelLogin(); | |
| 175 | + | void forceLogout(); | |
| 176 | + | void safeLogout(); | |
| 177 | + | ||
| 178 | + | // walk related | |
| 179 | + | void walk(Otc::Direction direction, bool withPreWalk); | |
| 180 | + | void autoWalk(const std::vector<Otc::Direction>& dirs, Position startPos); | |
| 181 | + | void turn(Otc::Direction direction); | |
| 182 | + | void stop(); | |
| 183 | + | ||
| 184 | + | // item related | |
| 185 | + | void look(const ThingPtr& thing, bool isBattleList = false); | |
| 186 | + | void move(const ThingPtr& thing, const Position& toPos, int count); | |
| 187 | + | void moveRaw(const Position& pos, int id, int stackpos, const Position& toPos, int count); | |
| 188 | + | void moveToParentContainer(const ThingPtr& thing, int count); | |
| 189 | + | void rotate(const ThingPtr& thing); | |
| 190 | + | void wrap(const ThingPtr& thing); | |
| 191 | + | void use(const ThingPtr& thing); | |
| 192 | + | void useWith(const ItemPtr& fromThing, const ThingPtr& toThing, int subType = 0); | |
| 193 | + | void useInventoryItem(int itemId, int subType = 0); | |
| 194 | + | void useInventoryItemWith(int itemId, const ThingPtr& toThing, int subType = 0); | |
| 195 | + | ItemPtr findItemInContainers(uint itemId, int subType); | |
| 196 | + | ||
| 197 | + | // container related | |
| 198 | + | int open(const ItemPtr& item, const ContainerPtr& previousContainer); | |
| 199 | + | void openParent(const ContainerPtr& container); | |
| 200 | + | void close(const ContainerPtr& container); | |
| 201 | + | void refreshContainer(const ContainerPtr& container); | |
| 202 | + | ||
| 203 | + | // attack/follow related | |
| 204 | + | void attack(CreaturePtr creature, bool cancel = false); | |
| 205 | + | void cancelAttack() { attack(nullptr, true); } | |
| 206 | + | void follow(CreaturePtr creature); | |
| 207 | + | void cancelFollow() { follow(nullptr); } | |
| 208 | + | void cancelAttackAndFollow(); | |
| 209 | + | ||
| 210 | + | // talk related | |
| 211 | + | void talk(const std::string& message); | |
| 212 | + | void talkChannel(Otc::MessageMode mode, int channelId, const std::string& message); | |
| 213 | + | void talkPrivate(Otc::MessageMode mode, const std::string& receiver, const std::string& message); | |
| 214 | + | ||
| 215 | + | // channel related | |
| 216 | + | void openPrivateChannel(const std::string& receiver); | |
| 217 | + | void requestChannels(); | |
| 218 | + | void joinChannel(int channelId); | |
| 219 | + | void leaveChannel(int channelId); | |
| 220 | + | void closeNpcChannel(); | |
| 221 | + | void openOwnChannel(); | |
| 222 | + | void inviteToOwnChannel(const std::string& name); | |
| 223 | + | void excludeFromOwnChannel(const std::string& name); | |
| 224 | + | ||
| 225 | + | // party related | |
| 226 | + | void partyInvite(int creatureId); | |
| 227 | + | void partyJoin(int creatureId); | |
| 228 | + | void partyRevokeInvitation(int creatureId); | |
| 229 | + | void partyPassLeadership(int creatureId); | |
| 230 | + | void partyLeave(); | |
| 231 | + | void partyShareExperience(bool active); | |
| 232 | + | ||
| 233 | + | // outfit related | |
| 234 | + | void requestOutfit(); | |
| 235 | + | void changeOutfit(const Outfit& outfit); | |
| 236 | + | ||
| 237 | + | // vip related | |
| 238 | + | void addVip(const std::string& name); | |
| 239 | + | void removeVip(int playerId); | |
| 240 | + | void editVip(int playerId, const std::string& description, int iconId, bool notifyLogin); | |
| 241 | + | ||
| 242 | + | // fight modes related | |
| 243 | + | void setChaseMode(Otc::ChaseModes chaseMode); | |
| 244 | + | void setFightMode(Otc::FightModes fightMode); | |
| 245 | + | void setSafeFight(bool on); | |
| 246 | + | void setPVPMode(Otc::PVPModes pvpMode); | |
| 247 | + | Otc::ChaseModes getChaseMode() { return m_chaseMode; } | |
| 248 | + | Otc::FightModes getFightMode() { return m_fightMode; } | |
| 249 | + | bool isSafeFight() { return m_safeFight; } | |
| 250 | + | Otc::PVPModes getPVPMode() { return m_pvpMode; } | |
| 251 | + | ||
| 252 | + | // pvp related | |
| 253 | + | void setUnjustifiedPoints(UnjustifiedPoints unjustifiedPoints); | |
| 254 | + | UnjustifiedPoints getUnjustifiedPoints() { return m_unjustifiedPoints; }; | |
| 255 | + | void setOpenPvpSituations(int openPvpSitations); | |
| 256 | + | int getOpenPvpSituations() { return m_openPvpSituations; } | |
| 257 | + | ||
| 258 | + | // npc trade related | |
| 259 | + | void inspectNpcTrade(const ItemPtr& item); | |
| 260 | + | void buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack); | |
| 261 | + | void sellItem(const ItemPtr& item, int amount, bool ignoreEquipped); | |
| 262 | + | void closeNpcTrade(); | |
| 263 | + | ||
| 264 | + | // player trade related | |
| 265 | + | void requestTrade(const ItemPtr& item, const CreaturePtr& creature); | |
| 266 | + | void inspectTrade(bool counterOffer, int index); | |
| 267 | + | void acceptTrade(); | |
| 268 | + | void rejectTrade(); | |
| 269 | + | ||
| 270 | + | // house window and editable items related | |
| 271 | + | void editText(uint id, const std::string& text); | |
| 272 | + | void editList(uint id, int doorId, const std::string& text); | |
| 273 | + | ||
| 274 | + | // rule violations (only gms) | |
| 275 | + | void openRuleViolation(const std::string& reporter); | |
| 276 | + | void closeRuleViolation(const std::string& reporter); | |
| 277 | + | void cancelRuleViolation(); | |
| 278 | + | ||
| 279 | + | // reports | |
| 280 | + | void reportBug(const std::string& comment); | |
| 281 | + | void reportRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment); | |
| 282 | + | void debugReport(const std::string& a, const std::string& b, const std::string& c, const std::string& d); | |
| 283 | + | ||
| 284 | + | // questlog related | |
| 285 | + | void requestQuestLog(); | |
| 286 | + | void requestQuestLine(int questId); | |
| 287 | + | ||
| 288 | + | // 870 only | |
| 289 | + | void equipItem(const ItemPtr& item); | |
| 290 | + | void equipItemId(int itemId, int subType); | |
| 291 | + | void mount(bool mount); | |
| 292 | + | void setOutfitExtensions(int mount, int wings, int aura, int shader, int healthBar, int manaBar); | |
| 293 | + | ||
| 294 | + | // 910 only | |
| 295 | + | void requestItemInfo(const ItemPtr& item, int index); | |
| 296 | + | ||
| 297 | + | // >= 970 modal dialog | |
| 298 | + | void answerModalDialog(uint32 dialog, int button, int choice); | |
| 299 | + | ||
| 300 | + | // >= 984 browse field | |
| 301 | + | void browseField(const Position& position); | |
| 302 | + | void seekInContainer(int cid, int index); | |
| 303 | + | ||
| 304 | + | // >= 1080 ingame store | |
| 305 | + | void buyStoreOffer(int offerId, int productType, const std::string& name = ""); | |
| 306 | + | void requestTransactionHistory(int page, int entriesPerPage); | |
| 307 | + | void requestStoreOffers(const std::string& categoryName, int serviceType = 0); | |
| 308 | + | void openStore(int serviceType = 0); | |
| 309 | + | void transferCoins(const std::string& recipient, int amount); | |
| 310 | + | void openTransactionHistory(int entriesPerPage); | |
| 311 | + | ||
| 312 | + | // >= 1100 | |
| 313 | + | void preyAction(int slot, int actionType, int index); | |
| 314 | + | void preyRequest(); | |
| 315 | + | ||
| 316 | + | void applyImbuement(uint8_t slot, uint32_t imbuementId, bool protectionCharm); | |
| 317 | + | void clearImbuement(uint8_t slot); | |
| 318 | + | void closeImbuingWindow(); | |
| 319 | + | ||
| 320 | + | //void reportRuleViolation2(); | |
| 321 | + | void ping(); | |
| 322 | + | void newPing(); | |
| 323 | + | void setPingDelay(int delay) { m_pingDelay = delay; } | |
| 324 | + | ||
| 325 | + | // otclient only | |
| 326 | + | void changeMapAwareRange(int xrange, int yrange); | |
| 327 | + | ||
| 328 | + | // dynamic support for game features | |
| 329 | + | void resetFeatures() { m_features.reset(); } | |
| 330 | + | void enableFeature(Otc::GameFeature feature) { m_features.set(feature, true); } | |
| 331 | + | void disableFeature(Otc::GameFeature feature) { m_features.set(feature, false); } | |
| 332 | + | void setFeature(Otc::GameFeature feature, bool enabled) { m_features.set(feature, enabled); } | |
| 333 | + | bool getFeature(Otc::GameFeature feature) { return m_features.test(feature); } | |
| 334 | + | ||
| 335 | + | void setProtocolVersion(int version); | |
| 336 | + | int getProtocolVersion() { return m_protocolVersion; } | |
| 337 | + | void setCustomProtocolVersion(int version) { m_customProtocolVersion = version; } | |
| 338 | + | int getCustomProtocolVersion() { return m_customProtocolVersion != 0 ? m_customProtocolVersion : m_protocolVersion; } | |
| 339 | + | ||
| 340 | + | void setClientVersion(int version); | |
| 341 | + | int getClientVersion() { return m_clientVersion; } | |
| 342 | + | ||
| 343 | + | void setCustomOs(int os) { m_clientCustomOs = os; } | |
| 344 | + | int getOs(); | |
| 345 | + | ||
| 346 | + | bool canPerformGameAction(); | |
| 347 | + | bool checkBotProtection(); | |
| 348 | + | ||
| 349 | + | bool isOnline() { return m_online; } | |
| 350 | + | bool isLogging() { return !m_online && m_protocolGame; } | |
| 351 | + | bool isDead() { return m_dead; } | |
| 352 | + | bool isAttacking() { return !!m_attackingCreature && !m_attackingCreature->isRemoved(); } | |
| 353 | + | bool isFollowing() { return !!m_followingCreature && !m_followingCreature->isRemoved(); } | |
| 354 | + | bool isConnectionOk() { return m_protocolGame && m_protocolGame->getElapsedTicksSinceLastRead() < 5000; } | |
| 355 | + | ||
| 356 | + | int getPing() { return m_ping; } | |
| 357 | + | ContainerPtr getContainer(int index) { if (m_containers.find(index) == m_containers.end()) { return nullptr; } return m_containers[index]; } | |
| 358 | + | std::map<int, ContainerPtr> getContainers() { return m_containers; } | |
| 359 | + | std::map<int, Vip> getVips() { return m_vips; } | |
| 360 | + | CreaturePtr getAttackingCreature() { return m_attackingCreature; } | |
| 361 | + | CreaturePtr getFollowingCreature() { return m_followingCreature; } | |
| 362 | + | void setServerBeat(int beat) { m_serverBeat = beat; } | |
| 363 | + | int getServerBeat() { return m_serverBeat; } | |
| 364 | + | void setCanReportBugs(bool enable) { m_canReportBugs = enable; } | |
| 365 | + | bool canReportBugs() { return m_canReportBugs; } | |
| 366 | + | void setExpertPvpMode(bool enable) { m_expertPvpMode = enable; } | |
| 367 | + | bool getExpertPvpMode() { return m_expertPvpMode; } | |
| 368 | + | LocalPlayerPtr getLocalPlayer() { return m_localPlayer; } | |
| 369 | + | ProtocolGamePtr getProtocolGame() { return m_protocolGame; } | |
| 370 | + | std::string getCharacterName() { return m_characterName; } | |
| 371 | + | std::string getWorldName() { return m_worldName; } | |
| 372 | + | std::vector<uint8> getGMActions() { return m_gmActions; } | |
| 373 | + | bool isGM() { return m_gmActions.size() > 0; } | |
| 374 | + | Otc::Direction getLastWalkDir() { return m_lastWalkDir; } | |
| 375 | + | ||
| 376 | + | std::string formatCreatureName(const std::string &name); | |
| 377 | + | int findEmptyContainerId(); | |
| 378 | + | ||
| 379 | + | void setTibiaCoins(int coins, int transferableCoins) | |
| 380 | + | { | |
| 381 | + | m_coins = coins; | |
| 382 | + | m_transferableCoins = transferableCoins; | |
| 383 | + | } | |
| 384 | + | int getTibiaCoins() | |
| 385 | + | { | |
| 386 | + | return m_coins; | |
| 387 | + | } | |
| 388 | + | int getTransferableTibiaCoins() | |
| 389 | + | { | |
| 390 | + | return m_transferableCoins; | |
| 391 | + | } | |
| 392 | + | ||
| 393 | + | void setMaxPreWalkingSteps(uint value) { m_maxPreWalkingSteps = value; } | |
| 394 | + | uint getMaxPreWalkingSteps() { return m_maxPreWalkingSteps; } | |
| 395 | + | ||
| 396 | + | void showRealDirection(bool value) { m_showRealDirection = value; } | |
| 397 | + | bool shouldShowingRealDirection() { return m_showRealDirection; } | |
| 398 | + | ||
| 399 | + | uint getWalkId() { return m_walkId; } | |
| 400 | + | uint getWalkPreditionId() { return m_walkPrediction; } | |
| 401 | + | ||
| 402 | + | void ignoreServerDirection(bool value) { m_ignoreServerDirection = value; } | |
| 403 | + | bool isIgnoringServerDirection() | |
| 404 | + | { | |
| 405 | + | return m_ignoreServerDirection; | |
| 406 | + | } | |
| 407 | + | ||
| 408 | + | void enableTileThingLuaCallback(bool value) { m_tileThingsLuaCallback = value; } | |
| 409 | + | bool isTileThingLuaCallbackEnabled() { return m_tileThingsLuaCallback; } | |
| 410 | + | ||
| 411 | + | int getRecivedPacketsCount() | |
| 412 | + | { | |
| 413 | + | return m_protocolGame ? m_protocolGame->getRecivedPacketsCount() : 0; | |
| 414 | + | } | |
| 415 | + | ||
| 416 | + | int getRecivedPacketsSize() | |
| 417 | + | { | |
| 418 | + | return m_protocolGame ? m_protocolGame->getRecivedPacketsSize() : 0; | |
| 419 | + | } | |
| 420 | + | ||
| 421 | + | protected: | |
| 422 | + | void enableBotCall() { m_denyBotCall = false; } | |
| 423 | + | void disableBotCall() { m_denyBotCall = true; } | |
| 424 | + | ||
| 425 | + | private: | |
| 426 | + | void setAttackingCreature(const CreaturePtr& creature); | |
| 427 | + | void setFollowingCreature(const CreaturePtr& creature); | |
| 428 | + | ||
| 429 | + | LocalPlayerPtr m_localPlayer; | |
| 430 | + | CreaturePtr m_attackingCreature; | |
| 431 | + | CreaturePtr m_followingCreature; | |
| 432 | + | ProtocolGamePtr m_protocolGame; | |
| 433 | + | std::map<int, ContainerPtr> m_containers; | |
| 434 | + | std::map<int, Vip> m_vips; | |
| 435 | + | ||
| 436 | + | bool m_online; | |
| 437 | + | bool m_denyBotCall; | |
| 438 | + | bool m_dead; | |
| 439 | + | bool m_expertPvpMode; | |
| 440 | + | int m_serverBeat; | |
| 441 | + | ticks_t m_ping; | |
| 442 | + | uint m_pingSent; | |
| 443 | + | uint m_pingReceived; | |
| 444 | + | uint m_walkId = 0; | |
| 445 | + | uint m_walkPrediction = 0; | |
| 446 | + | uint m_maxPreWalkingSteps = 2; | |
| 447 | + | stdext::timer m_pingTimer; | |
| 448 | + | std::map<uint32_t, stdext::timer> m_newPingIds; | |
| 449 | + | uint m_seq; | |
| 450 | + | int m_pingDelay; | |
| 451 | + | int m_newPingDelay; | |
| 452 | + | Otc::FightModes m_fightMode; | |
| 453 | + | Otc::ChaseModes m_chaseMode; | |
| 454 | + | Otc::PVPModes m_pvpMode; | |
| 455 | + | Otc::Direction m_lastWalkDir; | |
| 456 | + | bool m_waitingForAnotherDir = false; | |
| 457 | + | UnjustifiedPoints m_unjustifiedPoints; | |
| 458 | + | int m_openPvpSituations; | |
| 459 | + | bool m_safeFight; | |
| 460 | + | bool m_canReportBugs; | |
| 461 | + | std::vector<uint8> m_gmActions; | |
| 462 | + | std::string m_characterName; | |
| 463 | + | std::string m_worldName; | |
| 464 | + | std::bitset<Otc::LastGameFeature> m_features; | |
| 465 | + | ScheduledEventPtr m_pingEvent; | |
| 466 | + | ScheduledEventPtr m_newPingEvent; | |
| 467 | + | ScheduledEventPtr m_checkConnectionEvent; | |
| 468 | + | bool m_connectionFailWarned; | |
| 469 | + | int m_protocolVersion; | |
| 470 | + | int m_customProtocolVersion = 0; | |
| 471 | + | int m_clientVersion; | |
| 472 | + | std::string m_clientSignature; | |
| 473 | + | int m_clientCustomOs; | |
| 474 | + | int m_coins; | |
| 475 | + | int m_transferableCoins; | |
| 476 | + | ||
| 477 | + | bool m_showRealDirection = false; | |
| 478 | + | bool m_ignoreServerDirection = true; | |
| 479 | + | bool m_tileThingsLuaCallback = false; | |
| 480 | + | }; | |
| 481 | + | ||
| 482 | + | extern Game g_game; | |
| 483 | + | ||
| 484 | + | #endif |
| @@ -0,0 +1,32 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef CLIENT_GLOBAL_H | |
| 24 | + | #define CLIENT_GLOBAL_H | |
| 25 | + | ||
| 26 | + | #include <framework/global.h> | |
| 27 | + | ||
| 28 | + | // widely used headers | |
| 29 | + | #include "const.h" | |
| 30 | + | #include "position.h" | |
| 31 | + | ||
| 32 | + | #endif |
| @@ -0,0 +1,146 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #include "healthbars.h" | |
| 24 | + | ||
| 25 | + | #include <framework/graphics/texturemanager.h> | |
| 26 | + | ||
| 27 | + | HealthBars g_healthBars; | |
| 28 | + | ||
| 29 | + | void HealthBars::init() | |
| 30 | + | { | |
| 31 | + | m_healthBars.reserve(21); | |
| 32 | + | m_healthBars.push_back(nullptr); // 0 = default bar | |
| 33 | + | m_manaBars.reserve(21); | |
| 34 | + | m_manaBars.push_back(nullptr); // 0 = default bar | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | void HealthBars::terminate() | |
| 38 | + | { | |
| 39 | + | m_healthBars.clear(); | |
| 40 | + | m_manaBars.clear(); | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | void HealthBars::addHealthBackground(const std::string& path, int offsetX, int offsetY, int barOffsetX, int barOffsetY, int height) { | |
| 44 | + | HealthBarPtr bar(new HealthBar); | |
| 45 | + | bar->setPath(path); | |
| 46 | + | bar->setTexture(path); | |
| 47 | + | bar->setOffset(offsetX, offsetY); | |
| 48 | + | bar->setBarOffset(barOffsetX, barOffsetY); | |
| 49 | + | bar->setHeight(height); | |
| 50 | + | m_healthBars.push_back(bar); | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | void HealthBars::addManaBackground(const std::string& path, int offsetX, int offsetY, int barOffsetX, int barOffsetY, int height) { | |
| 54 | + | HealthBarPtr bar(new HealthBar); | |
| 55 | + | bar->setPath(path); | |
| 56 | + | bar->setTexture(path); | |
| 57 | + | bar->setOffset(offsetX, offsetY); | |
| 58 | + | bar->setBarOffset(barOffsetX, barOffsetY); | |
| 59 | + | bar->setHeight(height); | |
| 60 | + | m_manaBars.push_back(bar); | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | std::string HealthBars::getHealthBarPath(int id) | |
| 64 | + | { | |
| 65 | + | HealthBarPtr bar = getHealthBar(id); | |
| 66 | + | if (bar) { | |
| 67 | + | return bar->getPath(); | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | return std::string(); | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | std::string HealthBars::getManaBarPath(int id) | |
| 74 | + | { | |
| 75 | + | HealthBarPtr bar = getManaBar(id); | |
| 76 | + | if (bar) { | |
| 77 | + | return bar->getPath(); | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | return std::string(); | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | Point HealthBars::getHealthBarOffset(int id) | |
| 84 | + | { | |
| 85 | + | HealthBarPtr bar = getHealthBar(id); | |
| 86 | + | if (bar) { | |
| 87 | + | return bar->getOffset(); | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | return Point(); | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | Point HealthBars::getManaBarOffset(int id) | |
| 94 | + | { | |
| 95 | + | HealthBarPtr bar = getManaBar(id); | |
| 96 | + | if (bar) { | |
| 97 | + | return bar->getOffset(); | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | return Point(); | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | Point HealthBars::getHealthBarOffsetBar(int id) | |
| 104 | + | { | |
| 105 | + | HealthBarPtr bar = getHealthBar(id); | |
| 106 | + | if (bar) { | |
| 107 | + | return bar->getBarOffset(); | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | return Point(); | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | Point HealthBars::getManaBarOffsetBar(int id) | |
| 114 | + | { | |
| 115 | + | HealthBarPtr bar = getManaBar(id); | |
| 116 | + | if (bar) { | |
| 117 | + | return bar->getBarOffset(); | |
| 118 | + | } | |
| 119 | + | ||
| 120 | + | return Point(); | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | int HealthBars::getHealthBarHeight(int id) | |
| 124 | + | { | |
| 125 | + | HealthBarPtr bar = getHealthBar(id); | |
| 126 | + | if (bar) { | |
| 127 | + | return bar->getHeight(); | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | return 0; | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | int HealthBars::getManaBarHeight(int id) | |
| 134 | + | { | |
| 135 | + | HealthBarPtr bar = getManaBar(id); | |
| 136 | + | if (bar) { | |
| 137 | + | return bar->getHeight(); | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | return 0; | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | void HealthBar::setTexture(const std::string& path) | |
| 144 | + | { | |
| 145 | + | m_texture = g_textures.getTexture(path); | |
| 146 | + | } |
| @@ -0,0 +1,99 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef HEALTHBARS_H | |
| 24 | + | #define HEALTHBARS_H | |
| 25 | + | ||
| 26 | + | #include "declarations.h" | |
| 27 | + | #include <framework/graphics/declarations.h> | |
| 28 | + | ||
| 29 | + | class HealthBar : public stdext::shared_object | |
| 30 | + | { | |
| 31 | + | public: | |
| 32 | + | void setPath(const std::string& path) { | |
| 33 | + | m_path = path; | |
| 34 | + | } | |
| 35 | + | std::string getPath() { return m_path; } | |
| 36 | + | ||
| 37 | + | void setTexture(const std::string& path); | |
| 38 | + | TexturePtr getTexture() { return m_texture; } | |
| 39 | + | ||
| 40 | + | void setOffset(int x, int y) { | |
| 41 | + | m_offset = Point(x, y); | |
| 42 | + | } | |
| 43 | + | Point getOffset() { return m_offset; } | |
| 44 | + | ||
| 45 | + | void setBarOffset(int x, int y) { | |
| 46 | + | m_barOffset = Point(x, y); | |
| 47 | + | } | |
| 48 | + | Point getBarOffset() { return m_barOffset; } | |
| 49 | + | ||
| 50 | + | void setHeight(int height) { | |
| 51 | + | m_height = height; | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | int getHeight() { return m_height; } | |
| 55 | + | ||
| 56 | + | private: | |
| 57 | + | std::string m_path; | |
| 58 | + | TexturePtr m_texture; | |
| 59 | + | ||
| 60 | + | Point m_offset; | |
| 61 | + | Point m_barOffset; | |
| 62 | + | ||
| 63 | + | int m_height; | |
| 64 | + | }; | |
| 65 | + | ||
| 66 | + | //@bindsingleton g_healthBars | |
| 67 | + | class HealthBars | |
| 68 | + | { | |
| 69 | + | public: | |
| 70 | + | void init(); | |
| 71 | + | void terminate(); | |
| 72 | + | ||
| 73 | + | void addHealthBackground(const std::string& path, int offsetX, int offsetY, int barOffsetX, int barOffsetY, int height); | |
| 74 | + | void addManaBackground(const std::string& path, int offsetX, int offsetY, int barOffsetX, int barOffsetY, int height); | |
| 75 | + | ||
| 76 | + | HealthBarPtr getHealthBar(int id) { return m_healthBars[id]; } | |
| 77 | + | HealthBarPtr getManaBar(int id) { return m_manaBars[id]; } | |
| 78 | + | ||
| 79 | + | std::string getHealthBarPath(int id); | |
| 80 | + | std::string getManaBarPath(int id); | |
| 81 | + | ||
| 82 | + | Point getHealthBarOffset(int id); | |
| 83 | + | Point getManaBarOffset(int id); | |
| 84 | + | ||
| 85 | + | Point getHealthBarOffsetBar(int id); | |
| 86 | + | Point getManaBarOffsetBar(int id); | |
| 87 | + | ||
| 88 | + | int getHealthBarHeight(int id); | |
| 89 | + | int getManaBarHeight(int id); | |
| 90 | + | ||
| 91 | + | private: | |
| 92 | + | std::vector<HealthBarPtr> m_healthBars; | |
| 93 | + | std::vector<HealthBarPtr> m_manaBars; | |
| 94 | + | }; | |
| 95 | + | ||
| 96 | + | extern HealthBars g_healthBars; | |
| 97 | + | ||
| 98 | + | #endif | |
| 99 | + |
| @@ -0,0 +1,210 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #include "map.h" | |
| 24 | + | ||
| 25 | + | #include <framework/core/resourcemanager.h> | |
| 26 | + | ||
| 27 | + | HouseManager g_houses; | |
| 28 | + | ||
| 29 | + | House::House() | |
| 30 | + | { | |
| 31 | + | } | |
| 32 | + | ||
| 33 | + | House::House(uint32 hId, const std::string &name, const Position &pos) | |
| 34 | + | { | |
| 35 | + | setId(hId); | |
| 36 | + | setName(name); | |
| 37 | + | if(pos.isValid()) | |
| 38 | + | setEntry(pos); | |
| 39 | + | } | |
| 40 | + | ||
| 41 | + | void House::setTile(const TilePtr& tile) | |
| 42 | + | { | |
| 43 | + | tile->setFlag(TILESTATE_HOUSE); | |
| 44 | + | tile->setHouseId(getId()); | |
| 45 | + | m_tiles.insert(std::make_pair(tile->getPosition(), tile)); | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | TilePtr House::getTile(const Position& position) | |
| 49 | + | { | |
| 50 | + | TileMap::const_iterator iter = m_tiles.find(position); | |
| 51 | + | if(iter != m_tiles.end()) | |
| 52 | + | return iter->second; | |
| 53 | + | return nullptr; | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | void House::addDoor(const ItemPtr& door) | |
| 57 | + | { | |
| 58 | + | if (!door) return; | |
| 59 | + | door->setDoorId(m_lastDoorId); | |
| 60 | + | m_doors[m_lastDoorId++] = door; | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | void House::removeDoorById(uint32 doorId) | |
| 64 | + | { | |
| 65 | + | if(doorId >= m_lastDoorId) | |
| 66 | + | stdext::throw_exception(stdext::format("Failed to remove door of id %d (would overflow), max id: %d", | |
| 67 | + | doorId, m_lastDoorId)); | |
| 68 | + | m_doors[doorId] = nullptr; | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | void House::load(const TiXmlElement *elem) | |
| 72 | + | { | |
| 73 | + | std::string name = elem->Attribute("name"); | |
| 74 | + | if(name.empty()) | |
| 75 | + | name = stdext::format("Unnamed house #%lu", getId()); | |
| 76 | + | ||
| 77 | + | setName(name); | |
| 78 | + | setRent(elem->readType<uint32>("rent")); | |
| 79 | + | setSize(elem->readType<uint32>("size")); | |
| 80 | + | setTownId(elem->readType<uint32>("townid")); | |
| 81 | + | m_isGuildHall = elem->readType<bool>("guildhall"); | |
| 82 | + | ||
| 83 | + | Position entryPos; | |
| 84 | + | entryPos.x = elem->readType<int>("entryx"); | |
| 85 | + | entryPos.y = elem->readType<int>("entryy"); | |
| 86 | + | entryPos.z = elem->readType<int>("entryz"); | |
| 87 | + | setEntry(entryPos); | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | void House::save(TiXmlElement* elem) | |
| 91 | + | { | |
| 92 | + | elem->SetAttribute("name", getName()); | |
| 93 | + | elem->SetAttribute("houseid", getId()); | |
| 94 | + | ||
| 95 | + | Position entry = getEntry(); | |
| 96 | + | elem->SetAttribute("entryx", entry.x); | |
| 97 | + | elem->SetAttribute("entryy", entry.y); | |
| 98 | + | elem->SetAttribute("entryz", entry.z); | |
| 99 | + | ||
| 100 | + | elem->SetAttribute("rent", getRent()); | |
| 101 | + | elem->SetAttribute("townid", getTownId()); | |
| 102 | + | elem->SetAttribute("size", getSize()); | |
| 103 | + | elem->SetAttribute("guildhall", (int)m_isGuildHall); | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | HouseManager::HouseManager() | |
| 107 | + | { | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | void HouseManager::addHouse(const HousePtr& house) | |
| 111 | + | { | |
| 112 | + | if(findHouse(house->getId()) == m_houses.end()) | |
| 113 | + | m_houses.push_back(house); | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | void HouseManager::removeHouse(uint32 houseId) | |
| 117 | + | { | |
| 118 | + | auto it = findHouse(houseId); | |
| 119 | + | if(it != m_houses.end()) | |
| 120 | + | m_houses.erase(it); | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | HousePtr HouseManager::getHouse(uint32 houseId) | |
| 124 | + | { | |
| 125 | + | auto it = findHouse(houseId); | |
| 126 | + | return it != m_houses.end() ? *it : nullptr; | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | HousePtr HouseManager::getHouseByName(std::string name) | |
| 130 | + | { | |
| 131 | + | auto it = std::find_if(m_houses.begin(), m_houses.end(), | |
| 132 | + | [=] (const HousePtr& house) -> bool { return house->getName() == name; }); | |
| 133 | + | return it != m_houses.end() ? *it : nullptr; | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | void HouseManager::load(const std::string& fileName) | |
| 137 | + | { | |
| 138 | + | try { | |
| 139 | + | TiXmlDocument doc; | |
| 140 | + | doc.Parse(g_resources.readFileContents(fileName).c_str()); | |
| 141 | + | if(doc.Error()) | |
| 142 | + | stdext::throw_exception(stdext::format("failed to load '%s': %s (House XML)", fileName, doc.ErrorDesc())); | |
| 143 | + | ||
| 144 | + | TiXmlElement *root = doc.FirstChildElement(); | |
| 145 | + | if(!root || root->ValueTStr() != "houses") | |
| 146 | + | stdext::throw_exception("invalid root tag name"); | |
| 147 | + | ||
| 148 | + | for(TiXmlElement *elem = root->FirstChildElement(); elem; elem = elem->NextSiblingElement()) { | |
| 149 | + | if(elem->ValueTStr() != "house") | |
| 150 | + | stdext::throw_exception("invalid house tag."); | |
| 151 | + | ||
| 152 | + | uint32 houseId = elem->readType<uint32>("houseid"); | |
| 153 | + | HousePtr house = getHouse(houseId); | |
| 154 | + | if(!house) | |
| 155 | + | house = HousePtr(new House(houseId)), addHouse(house); | |
| 156 | + | ||
| 157 | + | house->load(elem); | |
| 158 | + | } | |
| 159 | + | } catch(std::exception& e) { | |
| 160 | + | g_logger.error(stdext::format("Failed to load '%s': %s", fileName, e.what())); | |
| 161 | + | } | |
| 162 | + | sort(); | |
| 163 | + | } | |
| 164 | + | ||
| 165 | + | void HouseManager::save(const std::string& fileName) | |
| 166 | + | { | |
| 167 | + | try { | |
| 168 | + | TiXmlDocument doc; | |
| 169 | + | doc.SetTabSize(2); | |
| 170 | + | ||
| 171 | + | TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", ""); | |
| 172 | + | doc.LinkEndChild(decl); | |
| 173 | + | ||
| 174 | + | TiXmlElement* root = new TiXmlElement("houses"); | |
| 175 | + | doc.LinkEndChild(root); | |
| 176 | + | ||
| 177 | + | for(auto house : m_houses) { | |
| 178 | + | TiXmlElement *elem = new TiXmlElement("house"); | |
| 179 | + | house->save(elem); | |
| 180 | + | root->LinkEndChild(elem); | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | if(!doc.SaveFile("data"+fileName)) | |
| 184 | + | stdext::throw_exception(stdext::format("failed to save houses XML %s: %s", fileName, doc.ErrorDesc())); | |
| 185 | + | } catch(std::exception& e) { | |
| 186 | + | g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what())); | |
| 187 | + | } | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | HouseList HouseManager::filterHouses(uint32 townId) | |
| 191 | + | { | |
| 192 | + | HouseList ret; | |
| 193 | + | for(const HousePtr& house : m_houses) | |
| 194 | + | if(house->getTownId() == townId) | |
| 195 | + | ret.push_back(house); | |
| 196 | + | return ret; | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | HouseList::iterator HouseManager::findHouse(uint32 houseId) | |
| 200 | + | { | |
| 201 | + | return std::find_if(m_houses.begin(), m_houses.end(), | |
| 202 | + | [=] (const HousePtr& house) -> bool { return house->getId() == houseId; }); | |
| 203 | + | } | |
| 204 | + | ||
| 205 | + | void HouseManager::sort() | |
| 206 | + | { | |
| 207 | + | m_houses.sort([] (const HousePtr& lhs, const HousePtr& rhs) { return lhs->getName() < rhs->getName(); }); | |
| 208 | + | } | |
| 209 | + | ||
| 210 | + | /* vim: set ts=4 sw=4 et: */ |