/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef Garrison_h__ #define Garrison_h__ #include "Define.h" #include "DatabaseEnvFwd.h" #include "GarrisonPackets.h" #include "Optional.h" #include "QuaternionData.h" #include class GameObject; class Map; class Player; struct GarrSiteLevelEntry; enum GarrisonType { GARRISON_TYPE_GARRISON = 2, GARRISON_TYPE_CLASS_ORDER = 3, GARRISON_TYPE_WAR_CAMPAIGN = 9, GARRISON_TYPE_COVENANT = 111 }; enum GarrisonFactionIndex { GARRISON_FACTION_INDEX_HORDE = 0, GARRISON_FACTION_INDEX_ALLIANCE = 1 }; enum GarrisonBuildingFlags { GARRISON_BUILDING_FLAG_NEEDS_PLAN = 0x1 }; enum GarrisonFollowerFlags { GARRISON_FOLLOWER_FLAG_UNIQUE = 0x1 }; enum GarrisonFollowerType { FOLLOWER_TYPE_GARRISON = 1, FOLLOWER_TYPE_SHIPYARD = 2, FOLLOWER_TYPE_CLASS_ORDER = 4, FOLLOWER_TYPE_WAR_CAMPAIGN = 11, FOLLOWER_TYPE_COVENANT = 123 }; enum GarrisonAbilityFlags { GARRISON_ABILITY_FLAG_TRAIT = 0x0001, GARRISON_ABILITY_CANNOT_ROLL = 0x0002, GARRISON_ABILITY_HORDE_ONLY = 0x0004, GARRISON_ABILITY_ALLIANCE_ONLY = 0x0008, GARRISON_ABILITY_FLAG_CANNOT_REMOVE = 0x0010, GARRISON_ABILITY_FLAG_EXCLUSIVE = 0x0020, GARRISON_ABILITY_FLAG_SINGLE_MISSION_DURATION = 0x0040, GARRISON_ABILITY_FLAG_ACTIVE_ONLY_ON_ZONE_SUPPORT = 0x0080, GARRISON_ABILITY_FLAG_APPLY_TO_FIRST_MISSION = 0x0100, GARRISON_ABILITY_FLAG_IS_SPECIALIZATION = 0x0200, GARRISON_ABILITY_FLAG_IS_EMPTY_SLOT = 0x0400 }; enum GarrisonError { GARRISON_SUCCESS = 0, GARRISON_ERROR_NO_GARRISON = 1, GARRISON_ERROR_GARRISON_EXISTS = 2, GARRISON_ERROR_GARRISON_SAME_TYPE_EXISTS = 3, GARRISON_ERROR_INVALID_GARRISON = 4, GARRISON_ERROR_INVALID_GARRISON_LEVEL = 5, GARRISON_ERROR_GARRISON_LEVEL_UNCHANGED = 6, GARRISON_ERROR_NOT_IN_GARRISON = 7, GARRISON_ERROR_NO_BUILDING = 8, GARRISON_ERROR_BUILDING_EXISTS = 9, GARRISON_ERROR_INVALID_PLOT_INSTANCEID = 10, GARRISON_ERROR_INVALID_BUILDINGID = 11, GARRISON_ERROR_INVALID_UPGRADE_LEVEL = 12, GARRISON_ERROR_UPGRADE_LEVEL_EXCEEDS_GARRISON_LEVEL = 13, GARRISON_ERROR_PLOTS_NOT_FULL = 14, GARRISON_ERROR_INVALID_SITE_ID = 15, GARRISON_ERROR_INVALID_PLOT_BUILDING = 16, GARRISON_ERROR_INVALID_FACTION = 17, GARRISON_ERROR_INVALID_SPECIALIZATION = 18, GARRISON_ERROR_SPECIALIZATION_EXISTS = 19, GARRISON_ERROR_SPECIALIZATION_ON_COOLDOWN = 20, GARRISON_ERROR_BLUEPRINT_EXISTS = 21, GARRISON_ERROR_REQUIRES_BLUEPRINT = 22, GARRISON_ERROR_INVALID_DOODAD_SET_ID = 23, GARRISON_ERROR_BUILDING_TYPE_EXISTS = 24, GARRISON_ERROR_BUILDING_NOT_ACTIVE = 25, GARRISON_ERROR_CONSTRUCTION_COMPLETE = 26, GARRISON_ERROR_FOLLOWER_EXISTS = 27, GARRISON_ERROR_INVALID_FOLLOWER = 28, GARRISON_ERROR_FOLLOWER_ALREADY_ON_MISSION = 29, GARRISON_ERROR_FOLLOWER_IN_BUILDING = 30, GARRISON_ERROR_FOLLOWER_INVALID_FOR_BUILDING = 31, GARRISON_ERROR_INVALID_FOLLOWER_LEVEL = 32, GARRISON_ERROR_MISSION_EXISTS = 33, GARRISON_ERROR_INVALID_MISSION = 34, GARRISON_ERROR_INVALID_MISSION_TIME = 35, GARRISON_ERROR_INVALID_MISSION_REWARD_INDEX = 36, GARRISON_ERROR_MISSION_NOT_OFFERED = 37, GARRISON_ERROR_ALREADY_ON_MISSION = 38, GARRISON_ERROR_MISSION_SIZE_INVALID = 39, GARRISON_ERROR_FOLLOWER_SOFT_CAP_EXCEEDED = 40, GARRISON_ERROR_NOT_ON_MISSION = 41, GARRISON_ERROR_ALREADY_COMPLETED_MISSION = 42, GARRISON_ERROR_MISSION_NOT_COMPLETE = 43, GARRISON_ERROR_MISSION_REWARDS_PENDING = 44, GARRISON_ERROR_MISSION_EXPIRED = 45, GARRISON_ERROR_NOT_ENOUGH_CURRENCY = 46, GARRISON_ERROR_NOT_ENOUGH_GOLD = 47, GARRISON_ERROR_BUILDING_MISSING = 48, GARRISON_ERROR_NO_ARCHITECT = 49, GARRISON_ERROR_ARCHITECT_NOT_AVAILABLE = 50, GARRISON_ERROR_NO_MISSION_NPC = 51, GARRISON_ERROR_MISSION_NPC_NOT_AVAILABLE = 52, GARRISON_ERROR_INTERNAL_ERROR = 53, GARRISON_ERROR_INVALID_STATIC_TABLE_VALUE = 54, GARRISON_ERROR_INVALID_ITEM_LEVEL = 55, GARRISON_ERROR_INVALID_AVAILABLE_RECRUIT = 56, GARRISON_ERROR_FOLLOWER_ALREADY_RECRUITED = 57, GARRISON_ERROR_RECRUITMENT_GENERATION_IN_PROGRESS = 58, GARRISON_ERROR_RECRUITMENT_ON_COOLDOWN = 59, GARRISON_ERROR_RECRUIT_BLOCKED_BY_GENERATION = 60, GARRISON_ERROR_RECRUITMENT_NPC_NOT_AVAILABLE = 61, GARRISON_ERROR_INVALID_FOLLOWER_QUALITY = 62, GARRISON_ERROR_PROXY_NOT_OK = 63, GARRISON_ERROR_RECALL_PORTAL_USED_LESS_THAN_24_HOURS_AGO = 64, GARRISON_ERROR_ON_REMOVE_BUILDING_SPELL_FAILED = 65, GARRISON_ERROR_OPERATION_NOT_SUPPORTED = 66, GARRISON_ERROR_FOLLOWER_FATIGUED = 67, GARRISON_ERROR_UPGRADE_CONDITION_FAILED = 68, GARRISON_ERROR_FOLLOWER_INACTIVE = 69, GARRISON_ERROR_FOLLOWER_ACTIVE = 70, GARRISON_ERROR_FOLLOWER_ACTIVATION_UNAVAILABLE = 71, GARRISON_ERROR_FOLLOWER_TYPE_MISMATCH = 72, GARRISON_ERROR_INVALID_GARRISON_TYPE = 73, GARRISON_ERROR_MISSION_START_CONDITION_FAILED = 74, GARRISON_ERROR_INVALID_FOLLOWER_ABILITY = 75, GARRISON_ERROR_INVALID_MISSION_BONUS_ABILITY = 76, GARRISON_ERROR_HIGHER_BUILDING_TYPE_EXISTS = 77, GARRISON_ERROR_AT_FOLLOWER_HARD_CAP = 78, GARRISON_ERROR_FOLLOWER_CANNOT_GAIN_XP = 79, GARRISON_ERROR_NO_OP = 80, GARRISON_ERROR_AT_CLASS_SPEC_CAP = 81, GARRISON_ERROR_MISSION_REQUIRES_100_TO_START = 82, GARRISON_ERROR_MISSION_MISSING_REQUIRED_FOLLOWER = 83, GARRISON_ERROR_INVALID_TALENT = 84, GARRISON_ERROR_ALREADY_RESEARCHING_TALENT = 85, GARRISON_ERROR_FAILED_CONDITION = 86, GARRISON_ERROR_INVALID_TIER = 87, GARRISON_ERROR_INVALID_CLASS = 88 }; enum GarrisonFollowerStatus { FOLLOWER_STATUS_FAVORITE = 0x01, FOLLOWER_STATUS_EXHAUSTED = 0x02, FOLLOWER_STATUS_INACTIVE = 0x04, FOLLOWER_STATUS_TROOP = 0x08, FOLLOWER_STATUS_NO_XP_GAIN = 0x10 }; class TC_GAME_API Garrison { public: struct Building { bool CanActivate() const; ObjectGuid Guid; std::unordered_set Spawns; Optional PacketInfo; }; struct Plot { GameObject* CreateGameObject(Map* map, GarrisonFactionIndex faction); void DeleteGameObject(Map* map); void ClearBuildingInfo(GarrisonType garrisonType, Player* owner); void SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo, Player* owner); WorldPackets::Garrison::GarrisonPlotInfo PacketInfo; QuaternionData Rotation; uint32 EmptyGameObjectId = 0; uint32 GarrSiteLevelPlotInstId = 0; Building BuildingInfo; }; struct Follower { uint32 GetItemLevel() const; bool HasAbility(uint32 garrAbilityId) const; WorldPackets::Garrison::GarrisonFollower PacketInfo; }; explicit Garrison(Player* owner); bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings, PreparedQueryResult followers, PreparedQueryResult abilities); void SaveToDB(CharacterDatabaseTransaction trans); static void DeleteFromDB(ObjectGuid::LowType ownerGuid, CharacterDatabaseTransaction trans); bool Create(uint32 garrSiteId); void Delete(); void Upgrade(); void Enter() const; void Leave() const; GarrisonFactionIndex GetFaction() const; GarrisonType GetType() const { return GARRISON_TYPE_GARRISON; } GarrSiteLevelEntry const* GetSiteLevel() const { return _siteLevel; } // Plots std::vector GetPlots(); Plot* GetPlot(uint32 garrPlotInstanceId); Plot const* GetPlot(uint32 garrPlotInstanceId) const; // Buildings void LearnBlueprint(uint32 garrBuildingId); void UnlearnBlueprint(uint32 garrBuildingId); bool HasBlueprint(uint32 garrBuildingId) const { return _knownBuildings.find(garrBuildingId) != _knownBuildings.end(); } void PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId); void CancelBuildingConstruction(uint32 garrPlotInstanceId); void ActivateBuilding(uint32 garrPlotInstanceId); // Followers void AddFollower(uint32 garrFollowerId); Follower const* GetFollower(uint64 dbId) const; template uint32 CountFollowers(Predicate&& predicate) const { uint32 count = 0; for (auto itr = _followers.begin(); itr != _followers.end(); ++itr) if (predicate(itr->second)) ++count; return count; } void SendInfo(); void SendRemoteInfo() const; void SendBlueprintAndSpecializationData(); void SendMapData(Player* receiver) const; void ResetFollowerActivationLimit() { _followerActivationsRemainingToday = 1; } private: Map* FindMap() const; void InitializePlots(); GarrisonError CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const; GarrisonError CheckBuildingRemoval(uint32 garrPlotInstanceId) const; Player* _owner; GarrSiteLevelEntry const* _siteLevel; uint32 _followerActivationsRemainingToday; std::unordered_map _plots; std::unordered_set _knownBuildings; std::unordered_map _followers; std::unordered_set _followerIds; }; #endif // Garrison_h__