diff options
author | Shauren <shauren.trinity@gmail.com> | 2015-05-08 00:03:15 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2015-05-08 00:03:15 +0200 |
commit | 5b725db033c656bda5e718ea05a79005946e089e (patch) | |
tree | c15ad544c542cdd7dd7cb395c8ec6d3d35e4d2e9 /src | |
parent | 0972552e84068cf453231b372bcb232cf2d2f42b (diff) |
Core/Garrisons: Basics for garrisons
Diffstat (limited to 'src')
36 files changed, 1805 insertions, 100 deletions
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index caa75c24121..9c3646c39ca 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -24,6 +24,7 @@ file(GLOB_RECURSE sources_DataStores DataStores/*.cpp DataStores/*.h) file(GLOB_RECURSE sources_DungeonFinding DungeonFinding/*.cpp DungeonFinding/*.h) file(GLOB_RECURSE sources_Entities Entities/*.cpp Entities/*.h) file(GLOB_RECURSE sources_Events Events/*.cpp Events/*.h) +file(GLOB_RECURSE sources_Garrison Garrison/*.cpp Garrison/*.h) file(GLOB_RECURSE sources_Globals Globals/*.cpp Globals/*.h) file(GLOB_RECURSE sources_Grids Grids/*.cpp Grids/*.h) file(GLOB_RECURSE sources_Groups Groups/*.cpp Groups/*.h) @@ -75,6 +76,7 @@ set(game_STAT_SRCS ${sources_DungeonFinding} ${sources_Entities} ${sources_Events} + ${sources_Garrison} ${sources_Globals} ${sources_Grids} ${sources_Groups} @@ -172,6 +174,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Vehicle ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Transport ${CMAKE_CURRENT_SOURCE_DIR}/Events + ${CMAKE_CURRENT_SOURCE_DIR}/Garrison ${CMAKE_CURRENT_SOURCE_DIR}/Globals ${CMAKE_CURRENT_SOURCE_DIR}/Grids/Cells ${CMAKE_CURRENT_SOURCE_DIR}/Grids/Notifiers @@ -217,8 +220,8 @@ include_directories( GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) add_library(game STATIC - ${game_STAT_SRCS} ${game_STAT_PCH_SRC} + ${game_STAT_SRCS} ) add_dependencies(game revision.h) diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index bed2cc793f4..c050caa8094 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -28,6 +28,14 @@ DB2Storage<AreaGroupMemberEntry> sAreaGroupMemberStore("AreaGroupMemb DB2Storage<BroadcastTextEntry> sBroadcastTextStore("BroadcastText.db2", BroadcastTextFormat, HOTFIX_SEL_BROADCAST_TEXT); DB2Storage<CurrencyTypesEntry> sCurrencyTypesStore("CurrencyTypes.db2", CurrencyTypesFormat, HOTFIX_SEL_CURRENCY_TYPES); DB2Storage<CurvePointEntry> sCurvePointStore("CurvePoint.db2", CurvePointFormat, HOTFIX_SEL_CURVE_POINT); +DB2Storage<GameObjectsEntry> sGameObjectsStore("GameObjects.db2", GameObjectsFormat, HOTFIX_SEL_GAMEOBJECTS); +DB2Storage<GarrBuildingEntry> sGarrBuildingStore("GarrBuilding.db2", GarrBuildingFormat, HOTFIX_SEL_GARR_BUILDING); +DB2Storage<GarrBuildingPlotInstEntry> sGarrBuildingPlotInstStore("GarrBuildingPlotInst.db2", GarrBuildingPlotInstFormat, HOTFIX_SEL_GARR_BUILDING_PLOT_INST); +DB2Storage<GarrPlotBuildingEntry> sGarrPlotBuildingStore("GarrPlotBuilding.db2", GarrPlotBuildingFormat, HOTFIX_SEL_GARR_PLOT_BUILDING); +DB2Storage<GarrPlotEntry> sGarrPlotStore("GarrPlot.db2", GarrPlotFormat, HOTFIX_SEL_GARR_PLOT); +DB2Storage<GarrPlotInstanceEntry> sGarrPlotInstanceStore("GarrPlotInstance.db2", GarrPlotInstanceFormat, HOTFIX_SEL_GARR_PLOT_INSTANCE); +DB2Storage<GarrSiteLevelEntry> sGarrSiteLevelStore("GarrSiteLevel.db2", GarrSiteLevelFormat, HOTFIX_SEL_GARR_SITE_LEVEL); +DB2Storage<GarrSiteLevelPlotInstEntry> sGarrSiteLevelPlotInstStore("GarrSiteLevelPlotInst.db2", GarrSiteLevelPlotInstFormat, HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST); DB2Storage<HolidaysEntry> sHolidaysStore("Holidays.db2", HolidaysEntryFormat, HOTFIX_SEL_HOLIDAYS); DB2Storage<ItemAppearanceEntry> sItemAppearanceStore("ItemAppearance.db2", ItemAppearanceFormat, HOTFIX_SEL_ITEM_APPEARANCE); DB2Storage<ItemBonusEntry> sItemBonusStore("ItemBonus.db2", ItemBonusFormat, HOTFIX_SEL_ITEM_BONUS); @@ -50,8 +58,8 @@ DB2Storage<SpellCastingRequirementsEntry> sSpellCastingRequirementsStore("Spel DB2Storage<SpellClassOptionsEntry> sSpellClassOptionsStore("SpellClassOptions.db2", SpellClassOptionsFormat, HOTFIX_SEL_SPELL_CLASS_OPTIONS); DB2Storage<SpellLearnSpellEntry> sSpellLearnSpellStore("SpellLearnSpell.db2", SpellLearnSpellFormat, HOTFIX_SEL_SPELL_LEARN_SPELL); DB2Storage<SpellMiscEntry> sSpellMiscStore("SpellMisc.db2", SpellMiscFormat, HOTFIX_SEL_SPELL_MISC); -DB2Storage<SpellPowerEntry> sSpellPowerStore("SpellPower.db2", SpellPowerFormat, HOTFIX_SEL_SPELL_POWER); DB2Storage<SpellPowerDifficultyEntry> sSpellPowerDifficultyStore("SpellPowerDifficulty.db2", SpellPowerDifficultyFormat, HOTFIX_SEL_SPELL_POWER_DIFFICULTY); +DB2Storage<SpellPowerEntry> sSpellPowerStore("SpellPower.db2", SpellPowerFormat, HOTFIX_SEL_SPELL_POWER); DB2Storage<SpellReagentsEntry> sSpellReagentsStore("SpellReagents.db2", SpellReagentsFormat, HOTFIX_SEL_SPELL_REAGENTS); DB2Storage<SpellRuneCostEntry> sSpellRuneCostStore("SpellRuneCost.db2", SpellRuneCostFormat, HOTFIX_SEL_SPELL_RUNE_COST); DB2Storage<SpellTotemsEntry> sSpellTotemsStore("SpellTotems.db2", SpellTotemsFormat, HOTFIX_SEL_SPELL_TOTEMS); @@ -125,41 +133,53 @@ void DB2Manager::LoadStores(std::string const& dataPath) DB2StoreProblemList bad_db2_files; uint32 availableDb2Locales = 0xFF; - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sAreaGroupStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sAreaGroupMemberStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sBroadcastTextStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sCurrencyTypesStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sCurvePointStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sHolidaysStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemAppearanceStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemBonusStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemBonusTreeNodeStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemCurrencyCostStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemEffectStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemExtendedCostStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemModifiedAppearanceStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemSparseStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemXBonusTreeStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sKeyChainStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sMountStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sOverrideSpellDataStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sPhaseXPhaseGroupStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sQuestPackageItemStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSoundEntriesStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellAuraRestrictionsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellCastingRequirementsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellClassOptionsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellLearnSpellStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellMiscStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellPowerStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellPowerDifficultyStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellReagentsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellRuneCostStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellTotemsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sTaxiNodesStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sTaxiPathNodeStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sTaxiPathStore, db2Path); +#define LOAD_DB2(store) LoadDB2(availableDb2Locales, bad_db2_files, _stores, &store, db2Path) + + LOAD_DB2(sAreaGroupMemberStore); + LOAD_DB2(sAreaGroupStore); + LOAD_DB2(sBroadcastTextStore); + LOAD_DB2(sCurrencyTypesStore); + LOAD_DB2(sCurvePointStore); + LOAD_DB2(sGameObjectsStore); + LOAD_DB2(sGarrBuildingPlotInstStore); + LOAD_DB2(sGarrBuildingStore); + LOAD_DB2(sGarrPlotBuildingStore); + LOAD_DB2(sGarrPlotInstanceStore); + LOAD_DB2(sGarrPlotStore); + LOAD_DB2(sGarrSiteLevelPlotInstStore); + LOAD_DB2(sGarrSiteLevelStore); + LOAD_DB2(sHolidaysStore); + LOAD_DB2(sItemAppearanceStore); + LOAD_DB2(sItemBonusStore); + LOAD_DB2(sItemBonusTreeNodeStore); + LOAD_DB2(sItemCurrencyCostStore); + LOAD_DB2(sItemEffectStore); + LOAD_DB2(sItemExtendedCostStore); + LOAD_DB2(sItemModifiedAppearanceStore); + LOAD_DB2(sItemSparseStore); + LOAD_DB2(sItemStore); + LOAD_DB2(sItemXBonusTreeStore); + LOAD_DB2(sKeyChainStore); + LOAD_DB2(sMountStore); + LOAD_DB2(sOverrideSpellDataStore); + LOAD_DB2(sPhaseXPhaseGroupStore); + LOAD_DB2(sQuestPackageItemStore); + LOAD_DB2(sSoundEntriesStore); + LOAD_DB2(sSpellAuraRestrictionsStore); + LOAD_DB2(sSpellCastingRequirementsStore); + LOAD_DB2(sSpellClassOptionsStore); + LOAD_DB2(sSpellLearnSpellStore); + LOAD_DB2(sSpellMiscStore); + LOAD_DB2(sSpellPowerDifficultyStore); + LOAD_DB2(sSpellPowerStore); + LOAD_DB2(sSpellReagentsStore); + LOAD_DB2(sSpellRuneCostStore); + LOAD_DB2(sSpellTotemsStore); + LOAD_DB2(sTaxiNodesStore); + LOAD_DB2(sTaxiPathNodeStore); + LOAD_DB2(sTaxiPathStore); + +#undef LOAD_DB2 for (AreaGroupMemberEntry const* areaGroupMember : sAreaGroupMemberStore) _areaGroupMembers[areaGroupMember->AreaGroupID].push_back(areaGroupMember->AreaID); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index ece71c7413e..6e3818e8f41 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -23,8 +23,16 @@ #include "SharedDefines.h" extern DB2Storage<BroadcastTextEntry> sBroadcastTextStore; -extern DB2Storage<HolidaysEntry> sHolidaysStore; extern DB2Storage<CurrencyTypesEntry> sCurrencyTypesStore; +extern DB2Storage<GameObjectsEntry> sGameObjectsStore; +extern DB2Storage<GarrBuildingEntry> sGarrBuildingStore; +extern DB2Storage<GarrBuildingPlotInstEntry> sGarrBuildingPlotInstStore; +extern DB2Storage<GarrPlotBuildingEntry> sGarrPlotBuildingStore; +extern DB2Storage<GarrPlotEntry> sGarrPlotStore; +extern DB2Storage<GarrPlotInstanceEntry> sGarrPlotInstanceStore; +extern DB2Storage<GarrSiteLevelEntry> sGarrSiteLevelStore; +extern DB2Storage<GarrSiteLevelPlotInstEntry> sGarrSiteLevelPlotInstStore; +extern DB2Storage<HolidaysEntry> sHolidaysStore; extern DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore; extern DB2Storage<ItemEffectEntry> sItemEffectStore; extern DB2Storage<ItemEntry> sItemStore; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 912ae5d60d5..cad9ca32e69 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -81,6 +81,112 @@ struct CurvePointEntry float Y; // 4 }; +struct GameObjectsEntry +{ + uint32 ID; // 0 + uint32 MapID; // 1 + uint32 DisplayID; // 2 + DBCPosition3D Position; // 3-5 + float RotationX; // 6 + float RotationY; // 7 + float RotationZ; // 8 + float RotationW; // 9 + float Size; // 10 + uint32 PhaseUseFlags; // 11 + uint32 PhaseID; // 12 + uint32 PhaseGroupID; // 13 + uint32 Type; // 14 + uint32 Data[8]; // 15-22 + LocalizedString* Name; // 23 +}; + +struct GarrBuildingEntry +{ + uint32 ID; // 0 + uint32 HordeGameObjectID; // 1 + uint32 AllianceGameObjectID; // 2 + uint32 Unknown; // 3 + uint32 Type; // 4 + uint32 Level; // 5 + LocalizedString* NameAlliance; // 6 + LocalizedString* NameHorde; // 7 + LocalizedString* Description; // 8 + LocalizedString* Tooltip; // 9 + uint32 BuildDuration; // 10 + uint32 CostCurrencyID; // 11 + int32 CostCurrencyAmount; // 12 + uint32 HordeTexPrefixKitID; // 13 + uint32 AllianceTexPrefixKitID; // 14 + uint32 IconFileDataID; // 15 + uint32 BonusAmount; // 16 + uint32 Flags; // 17 + uint32 AllianceActivationScenePackageID; // 18 + uint32 HordeActivationScenePackageID; // 19 + uint32 MaxShipments; // 20 + uint32 FollowerRequiredGarrAbilityID; // 21 + uint32 FollowerGarrAbilityEffectID; // 22 + int32 CostMoney; // 23 +}; + +struct GarrBuildingPlotInstEntry +{ + uint32 ID; // 0 + uint32 GarrBuildingID; // 1 + uint32 UiTextureAtlasMemberID; // 2 + uint32 GarrSiteLevelPlotInstID; // 3 + DBCPosition2D LandmarkOffset; // 4-5 +}; + +struct GarrPlotEntry +{ + uint32 ID; // 0 + uint32 GarrPlotUICategoryID; // 1 + uint32 PlotType; // 2 + uint32 Flags; // 3 + LocalizedString* Name; // 4 + uint32 MinCount; // 5 + uint32 MaxCount; // 6 + uint32 AllianceConstructionGameObjectID; // 7 + uint32 HordeConstructionGameObjectID; // 8 +}; + +struct GarrPlotBuildingEntry +{ + uint32 ID; // 0 + uint32 GarrPlotID; // 1 + uint32 GarrBuildingID; // 2 +}; + +struct GarrPlotInstanceEntry +{ + uint32 ID; // 0 + uint32 GarrPlotID; // 1 + LocalizedString* Name; // 2 +}; + +struct GarrSiteLevelEntry +{ + uint32 ID; // 0 + uint32 Level; // 1 + uint32 MapID; // 2 + uint32 SiteID; // 3 + uint32 UITextureKitID; // 4 + DBCPosition2D TownHall; // 5-6 + uint32 MovieID; // 7 + uint32 Level2; // 8 + uint32 UpgradeResourceCost; // 9 + uint32 UpgradeMoneyCost; // 10 +}; + +struct GarrSiteLevelPlotInstEntry +{ + uint32 ID; // 0 + uint32 GarrSiteLevelID; // 1 + uint32 GarrPlotInstanceID; // 2 + DBCPosition2D Landmark; // 3-4 + uint32 Unknown; // 5 +}; + struct HolidaysEntry { uint32 ID; // 0 diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h index f59c7b56f56..19622dcc3d2 100644 --- a/src/server/game/DataStores/DB2fmt.h +++ b/src/server/game/DataStores/DB2fmt.h @@ -23,6 +23,14 @@ char const AreaGroupMemberFormat[] = "nii"; char const BroadcastTextFormat[] = "nissiiiiiiiii"; char const CurrencyTypesFormat[] = "nisssiiiiiis"; char const CurvePointFormat[] = "niiff"; +char const GameObjectsFormat[] = "niiffffffffiiiiiiiiiiiis"; +char const GarrBuildingFormat[] = "niiiiissssiiiiiiiiiiiiii"; +char const GarrPlotFormat[] = "niiisiiii"; +char const GarrPlotBuildingFormat[] = "nii"; +char const GarrBuildingPlotInstFormat[] = "niiiff"; +char const GarrPlotInstanceFormat[] = "nis"; +char const GarrSiteLevelFormat[] = "niiiiffiiii"; +char const GarrSiteLevelPlotInstFormat[] = "niiffi"; char const HolidaysEntryFormat[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisiii"; char const ItemFormat[] = "niiiiiiii"; char const ItemAppearanceFormat[] = "nii"; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 1aa74d3b1a3..fc05f0fdc6a 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -431,6 +431,7 @@ enum MapFlags MAP_FLAG_CAN_TOGGLE_DIFFICULTY = 0x0100, MAP_FLAG_FLEX_LOCKING = 0x8000, // All difficulties share completed encounters lock, not bound to a single instance id // heroic difficulty flag overrides it and uses instance id bind + MAP_FLAG_GARRISON = 0x4000000 }; enum AbilytyLearnType diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 2fdc6ba1e3e..ca1ec344d04 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1241,7 +1241,7 @@ struct MapEntry // Helpers uint32 Expansion() const { return ExpansionID; } - bool IsDungeon() const { return InstanceType == MAP_INSTANCE || InstanceType == MAP_RAID; } + bool IsDungeon() const { return (InstanceType == MAP_INSTANCE || InstanceType == MAP_RAID) && !IsGarrison(); } bool IsNonRaidDungeon() const { return InstanceType == MAP_INSTANCE; } bool Instanceable() const { return InstanceType == MAP_INSTANCE || InstanceType == MAP_RAID || InstanceType == MAP_BATTLEGROUND || InstanceType == MAP_ARENA; } bool IsRaid() const { return InstanceType == MAP_RAID; } @@ -1266,6 +1266,7 @@ struct MapEntry } bool IsDynamicDifficultyMap() const { return (Flags & MAP_FLAG_CAN_TOGGLE_DIFFICULTY) != 0; } + bool IsGarrison() const { return (Flags & MAP_FLAG_GARRISON) != 0; } }; struct MapDifficultyEntry diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 3be32baa7c5..09e30b1b51b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -46,6 +46,7 @@ #include "Formulas.h" #include "GameEventMgr.h" #include "GameObjectAI.h" +#include "Garrison.h" #include "GossipDef.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -4582,6 +4583,18 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); sWorld->DeleteCharacterInfo(playerguid); @@ -17322,6 +17335,12 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) _LoadCUFProfiles(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); + std::unique_ptr<Garrison> garrison(new Garrison(this)); + if (garrison->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS))) + _garrison = std::move(garrison); + return true; } @@ -19079,6 +19098,8 @@ void Player::SaveToDB(bool create /*=false*/) _SaveInstanceTimeRestrictions(trans); _SaveCurrency(trans); _SaveCUFProfiles(trans); + if (_garrison) + _garrison->SaveToDB(trans); // check if stats should only be saved on logout // save stats can be out of transaction @@ -22587,6 +22608,9 @@ void Player::SendInitialPacketsAfterAddToMap() } else if (GetMap()->IsNonRaidDungeon()) SendDungeonDifficulty(); + + if (_garrison) + _garrison->SendRemoteInfo(); } void Player::SendUpdateToOutOfRangeGroupMembers() @@ -23029,7 +23053,7 @@ void Player::SetMonthlyQuestStatus(uint32 quest_id) m_MonthlyQuestChanged = true; } -void Player::ResetDailyQuestStatus() +void Player::DailyReset() { for (uint32 questId : GetDynamicValues(PLAYER_DYNAMIC_FIELD_DAILY_QUESTS)) if (uint32 questBit = GetQuestUniqueBitFlag(questId)) @@ -23042,6 +23066,9 @@ void Player::ResetDailyQuestStatus() // DB data deleted in caller m_DailyQuestChanged = false; m_lastDailyQuestTime = 0; + + if (_garrison) + _garrison->ResetFollowerActivationLimit(); } void Player::ResetWeeklyQuestStatus() @@ -26123,6 +26150,13 @@ void Player::OnCombatExit() m_holyPowerRegenTimerCount = 20000; // first charge of holy power decays 20 seconds after leaving combat } +void Player::CreateGarrison(uint32 garrSiteId) +{ + std::unique_ptr<Garrison> garrison(new Garrison(this)); + if (garrison->Create(garrSiteId)) + _garrison = std::move(garrison); +} + void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply) { WorldPackets::Movement::MoveSetFlag packet(apply ? SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY : SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index a17b828f0d5..7de2b09a5cb 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -47,6 +47,7 @@ class ReputationMgr; class Channel; class Creature; class DynamicObject; +class Garrison; class Group; class Guild; class OutdoorPvP; @@ -984,6 +985,9 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE, PLAYER_LOGIN_QUERY_LOAD_CURRENCY, PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES, + PLAYER_LOGIN_QUERY_LOAD_GARRISON, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS, MAX_PLAYER_LOGIN_QUERY }; @@ -1677,7 +1681,7 @@ class Player : public Unit, public GridObject<Player> void SetWeeklyQuestStatus(uint32 quest_id); void SetMonthlyQuestStatus(uint32 quest_id); void SetSeasonalQuestStatus(uint32 quest_id); - void ResetDailyQuestStatus(); + void DailyReset(); void ResetWeeklyQuestStatus(); void ResetMonthlyQuestStatus(); void ResetSeasonalQuestStatus(uint16 event_id); @@ -2625,6 +2629,9 @@ class Player : public Unit, public GridObject<Player> void OnCombatExit(); + void CreateGarrison(uint32 garrSiteId); + Garrison* GetGarrison() { return _garrison.get(); } + protected: // Gamemaster whisper whitelist GuidList WhisperList; @@ -2974,6 +2981,8 @@ class Player : public Unit, public GridObject<Player> uint32 _activeCheats; uint32 _maxPersonalArenaRate; + + std::unique_ptr<Garrison> _garrison; }; void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp new file mode 100644 index 00000000000..24fdd1fb30b --- /dev/null +++ b/src/server/game/Garrison/Garrison.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "Garrison.h" +#include "GameObject.h" +#include "GarrisonMgr.h" +#include "MapManager.h" + +Garrison::Garrison(Player* owner) : _owner(owner), _siteLevel(nullptr), _followerActivationsRemainingToday(1) +{ +} + +bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings) +{ + if (!garrison) + return false; + + Field* fields = garrison->Fetch(); + _siteLevel = sGarrSiteLevelStore.LookupEntry(fields[0].GetUInt32()); + _followerActivationsRemainingToday = fields[1].GetUInt32(); + if (!_siteLevel) + return false; + + InitializePlots(); + + if (blueprints) + { + do + { + fields = blueprints->Fetch(); + if (GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(fields[0].GetUInt32())) + _knownBuildings.insert(building->ID); + + } while (blueprints->NextRow()); + } + + if (buildings) + { + do + { + fields = buildings->Fetch(); + uint32 plotInstanceId = fields[0].GetUInt32(); + uint32 buildingId = fields[1].GetUInt32(); + time_t timeBuilt = time_t(fields[2].GetUInt64()); + bool active = fields[3].GetBool(); + + + Plot* plot = GetPlot(plotInstanceId); + if (!plot) + continue; + + if (!sGarrBuildingStore.LookupEntry(buildingId)) + continue; + + plot->BuildingInfo.PacketInfo = boost::in_place(); + plot->BuildingInfo.PacketInfo->GarrPlotInstanceID = plotInstanceId; + plot->BuildingInfo.PacketInfo->GarrBuildingID = buildingId; + plot->BuildingInfo.PacketInfo->TimeBuilt = timeBuilt; + plot->BuildingInfo.PacketInfo->Active = active; + + } while (buildings->NextRow()); + } + + return true; +} + +void Garrison::SaveToDB(SQLTransaction& trans) +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, _siteLevel->ID); + stmt->setUInt32(2, _followerActivationsRemainingToday); + trans->Append(stmt); + + for (uint32 building : _knownBuildings) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, building); + trans->Append(stmt); + } + + for (auto const& p : _plots) + { + Plot const& plot = p.second; + if (plot.BuildingInfo.PacketInfo) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, plot.BuildingInfo.PacketInfo->GarrPlotInstanceID); + stmt->setUInt32(2, plot.BuildingInfo.PacketInfo->GarrBuildingID); + stmt->setUInt64(3, plot.BuildingInfo.PacketInfo->TimeBuilt); + stmt->setBool(4, plot.BuildingInfo.PacketInfo->Active); + trans->Append(stmt); + } + } +} + +bool Garrison::Create(uint32 garrSiteId) +{ + _siteLevel = sGarrisonMgr.GetGarrSiteLevelEntry(garrSiteId, 1); + if (!_siteLevel) + return false; + + InitializePlots(); + + WorldPackets::Garrison::GarrisonCreateResult garrisonCreateResult; + garrisonCreateResult.GarrSiteLevelID = _siteLevel->ID; + _owner->SendDirectMessage(garrisonCreateResult.Write()); + _owner->SendUpdatePhasing(); + SendRemoteInfo(); + return true; +} + +void Garrison::InitializePlots() +{ + if (std::vector<GarrSiteLevelPlotInstEntry const*> const* plots = sGarrisonMgr.GetGarrPlotInstForSiteLevel(_siteLevel->ID)) + { + for (std::size_t i = 0; i < plots->size(); ++i) + { + uint32 garrPlotInstanceId = plots->at(i)->GarrPlotInstanceID; + GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId); + GameObjectsEntry const* gameObject = sGarrisonMgr.GetPlotGameObject(_siteLevel->MapID, garrPlotInstanceId); + if (!plotInstance || !gameObject) + continue; + + GarrPlotEntry const* plot = sGarrPlotStore.LookupEntry(plotInstance->GarrPlotID); + if (!plot) + continue; + + Plot& plotInfo = _plots[garrPlotInstanceId]; + plotInfo.PacketInfo.GarrPlotInstanceID = garrPlotInstanceId; + plotInfo.PacketInfo.PlotPos.Relocate(gameObject->Position.X, gameObject->Position.Y, gameObject->Position.Z, 2 * std::acos(gameObject->RotationW)); + plotInfo.PacketInfo.PlotType = plot->PlotType; + plotInfo.EmptyGameObjectId = gameObject->ID; + plotInfo.GarrSiteLevelPlotInstId = plots->at(i)->ID; + } + } +} + +void Garrison::Upgrade() +{ +} + +void Garrison::Enter() const +{ + WorldLocation loc(_siteLevel->MapID); + loc.Relocate(_owner); + _owner->TeleportTo(loc, TELE_TO_SEAMLESS); +} + +void Garrison::Leave() const +{ + if (MapEntry const* map = sMapStore.LookupEntry(_siteLevel->MapID)) + { + WorldLocation loc(map->ParentMapID); + loc.Relocate(_owner); + _owner->TeleportTo(loc, TELE_TO_SEAMLESS); + } +} + +GarrisonFactionIndex Garrison::GetFaction() const +{ + return _owner->GetTeam() == HORDE ? GARRISON_FACTION_INDEX_HORDE : GARRISON_FACTION_INDEX_ALLIANCE; +} + +std::vector<Garrison::Plot*> Garrison::GetPlots() +{ + std::vector<Plot*> plots; + plots.reserve(_plots.size()); + for (auto& p : _plots) + plots.push_back(&p.second); + + return plots; +} + +Garrison::Plot* Garrison::GetPlot(uint32 garrPlotInstanceId) +{ + auto itr = _plots.find(garrPlotInstanceId); + if (itr != _plots.end()) + return &itr->second; + + return nullptr; +} + +void Garrison::LearnBlueprint(uint32 garrBuildingId) +{ + WorldPackets::Garrison::GarrisonLearnBlueprintResult learnBlueprintResult; + learnBlueprintResult.BuildingID = garrBuildingId; + learnBlueprintResult.Result = GARRISON_SUCCESS; + + if (!sGarrBuildingStore.LookupEntry(garrBuildingId)) + learnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID; + else if (_knownBuildings.count(garrBuildingId)) + learnBlueprintResult.Result = GARRISON_ERROR_BLUEPRINT_KNOWN; + else + _knownBuildings.insert(garrBuildingId); + + _owner->SendDirectMessage(learnBlueprintResult.Write()); +} + +void Garrison::UnlearnBlueprint(uint32 garrBuildingId) +{ + WorldPackets::Garrison::GarrisonUnlearnBlueprintResult unlearnBlueprintResult; + unlearnBlueprintResult.BuildingID = garrBuildingId; + unlearnBlueprintResult.Result = GARRISON_SUCCESS; + + if (!sGarrBuildingStore.LookupEntry(garrBuildingId)) + unlearnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID; + else if (!_knownBuildings.count(garrBuildingId)) + unlearnBlueprintResult.Result = GARRISON_ERROR_BLUEPRINT_NOT_KNOWN; + else + _knownBuildings.erase(garrBuildingId); + + _owner->SendDirectMessage(unlearnBlueprintResult.Write()); +} + +void Garrison::PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId) +{ + WorldPackets::Garrison::GarrisonPlaceBuildingResult placeBuildingResult; + placeBuildingResult.Result = CheckBuildingPlacement(garrPlotInstanceId, garrBuildingId); + if (placeBuildingResult.Result == GARRISON_SUCCESS) + { + placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId; + placeBuildingResult.BuildingInfo.GarrBuildingID = garrBuildingId; + placeBuildingResult.BuildingInfo.TimeBuilt = time(nullptr); + + Plot* plot = GetPlot(garrPlotInstanceId); + + if (Map* map = FindMap()) + { + if (!plot->BuildingInfo.Guid.IsEmpty()) + { + if (GameObject* oldBuilding = map->GetGameObject(plot->BuildingInfo.Guid)) + oldBuilding->AddObjectToRemoveList(); + + plot->BuildingInfo.Guid.Clear(); + } + + plot->BuildingInfo.PacketInfo = placeBuildingResult.BuildingInfo; + if (GameObject* go = plot->CreateGameObject(map, GetFaction())) + { + map->AddToMap(go); + GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(garrBuildingId); + _owner->ModifyCurrency(building->CostCurrencyID, -building->CostCurrencyAmount, false, true); + _owner->ModifyMoney(-building->CostMoney, false); + } + else + plot->BuildingInfo.PacketInfo = boost::none; + } + } + + _owner->SendDirectMessage(placeBuildingResult.Write()); +} + +void Garrison::SendInfo() +{ + WorldPackets::Garrison::GetGarrisonInfoResult garrisonInfo; + garrisonInfo.GarrSiteID = _siteLevel->SiteID; + garrisonInfo.GarrSiteLevelID = _siteLevel->ID; + garrisonInfo.FactionIndex = GetFaction(); + garrisonInfo.NumFollowerActivationsRemaining = _followerActivationsRemainingToday; + for (auto& p : _plots) + { + Plot& plot = p.second; + garrisonInfo.Plots.push_back(&plot.PacketInfo); + if (plot.BuildingInfo.PacketInfo) + garrisonInfo.Buildings.push_back(plot.BuildingInfo.PacketInfo.get_ptr()); + } + + _owner->SendDirectMessage(garrisonInfo.Write()); +} + +void Garrison::SendRemoteInfo() const +{ + MapEntry const* garrisonMap = sMapStore.LookupEntry(_siteLevel->MapID); + if (!garrisonMap || int32(_owner->GetMapId()) != garrisonMap->ParentMapID) + return; + + WorldPackets::Garrison::GarrisonRemoteInfo remoteInfo; + remoteInfo.Sites.resize(1); + + WorldPackets::Garrison::GarrisonRemoteSiteInfo& remoteSiteInfo = remoteInfo.Sites[0]; + remoteSiteInfo.GarrSiteLevelID = _siteLevel->ID; + for (auto const& p : _plots) + if (p.second.BuildingInfo.PacketInfo) + remoteSiteInfo.Buildings.emplace_back(p.first, p.second.BuildingInfo.PacketInfo->GarrBuildingID); + + _owner->SendDirectMessage(remoteInfo.Write()); +} + +void Garrison::SendBlueprintAndSpecializationData() +{ + WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationDataResult data; + data.BlueprintsKnown = &_knownBuildings; + _owner->SendDirectMessage(data.Write()); +} + +void Garrison::SendBuildingLandmarks(Player* receiver) const +{ + WorldPackets::Garrison::GarrisonBuildingLandmarks buildingLandmarks; + buildingLandmarks.Landmarks.reserve(_plots.size()); + + for (auto const& p : _plots) + { + Plot const& plot = p.second; + if (plot.BuildingInfo.PacketInfo) + if (uint32 garrBuildingPlotInstId = sGarrisonMgr.GetGarrBuildingPlotInst(plot.BuildingInfo.PacketInfo->GarrBuildingID, plot.GarrSiteLevelPlotInstId)) + buildingLandmarks.Landmarks.emplace_back(garrBuildingPlotInstId, plot.PacketInfo.PlotPos); + } + + receiver->SendDirectMessage(buildingLandmarks.Write()); +} + +Map* Garrison::FindMap() const +{ + return sMapMgr->FindMap(_siteLevel->MapID, _owner->GetGUID().GetCounter()); +} + +GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const +{ + GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId); + if (!plotInstance || !_plots.count(garrPlotInstanceId)) + return GARRISON_ERROR_INVALID_PLOT; + + GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(garrBuildingId); + if (!building) + return GARRISON_ERROR_INVALID_BUILDINGID; + + if (!sGarrisonMgr.IsPlotMatchingBuilding(plotInstance->GarrPlotID, garrBuildingId)) + return GARRISON_ERROR_INVALID_PLOT_BUILDING; + + if (building->Flags & GARRISON_BUILDING_FLAG_NEEDS_PLAN) + { + if (_knownBuildings.count(garrBuildingId)) + return GARRISON_ERROR_BLUEPRINT_NOT_KNOWN; + } + else // Building is built as a quest reward + return GARRISON_ERROR_INVALID_BUILDINGID; + + // Check all plots to find if we already have this building + GarrBuildingEntry const* existingBuilding; + for (auto const& p : _plots) + { + if (p.second.BuildingInfo.PacketInfo) + { + existingBuilding = sGarrBuildingStore.AssertEntry(p.second.BuildingInfo.PacketInfo->GarrBuildingID); + if (existingBuilding->Type == building->Type) + if (p.first != garrPlotInstanceId || existingBuilding->Level != building->Level + 1) // check if its an upgrade in same plot + return GARRISON_ERROR_BUILDING_EXISTS; + } + } + + if (!_owner->HasCurrency(building->CostCurrencyID, building->CostCurrencyAmount)) + return GARRISON_ERROR_NOT_ENOUGH_CURRENCY; + + if (!_owner->HasEnoughMoney(uint64(building->CostMoney))) + return GARRISON_ERROR_NOT_ENOUGH_GOLD; + + return GARRISON_SUCCESS; +} + +GameObject* Garrison::Plot::CreateGameObject(Map* map, GarrisonFactionIndex faction) +{ + uint32 entry = EmptyGameObjectId; + if (BuildingInfo.PacketInfo) + { + GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.AssertEntry(PacketInfo.GarrPlotInstanceID); + GarrPlotEntry const* plot = sGarrPlotStore.AssertEntry(plotInstance->GarrPlotID); + GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(BuildingInfo.PacketInfo->GarrBuildingID); + if (BuildingInfo.PacketInfo->TimeBuilt + building->BuildDuration <= time(nullptr) && BuildingInfo.PacketInfo->Active) + entry = faction == GARRISON_FACTION_INDEX_HORDE ? building->HordeGameObjectID : building->AllianceGameObjectID; + else + entry = faction == GARRISON_FACTION_INDEX_HORDE ? plot->HordeConstructionGameObjectID : plot->AllianceConstructionGameObjectID; + } + + if (!sObjectMgr->GetGameObjectTemplate(entry)) + { + TC_LOG_ERROR("garrison", "Garrison attempted to spawn gameobject whose template doesn't exist (%u)", entry); + return nullptr; + } + + Position const& pos = PacketInfo.PlotPos; + GameObject* go = new GameObject(); + if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, 0, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), + 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_ACTIVE)) + { + delete go; + return nullptr; + } + + BuildingInfo.Guid = go->GetGUID(); + return go; +} diff --git a/src/server/game/Garrison/Garrison.h b/src/server/game/Garrison/Garrison.h new file mode 100644 index 00000000000..37712386d0b --- /dev/null +++ b/src/server/game/Garrison/Garrison.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef Garrison_h__ +#define Garrison_h__ + +#include "Player.h" +#include "GarrisonPackets.h" + +enum GarrisonFactionIndex +{ + GARRISON_FACTION_INDEX_HORDE = 0, + GARRISON_FACTION_INDEX_ALLIANCE = 1 +}; + +enum GarrisonBuildingFlags +{ + GARRISON_BUILDING_FLAG_NEEDS_PLAN = 0x1 +}; + +enum GarrisonError +{ + GARRISON_SUCCESS = 0, + GARRISON_ERROR_INVALID_PLOT = 1, + GARRISON_ERROR_INVALID_BUILDINGID = 2, + GARRISON_ERROR_INVALID_PLOT_BUILDING = 7, + GARRISON_ERROR_NO_BUILDING = 8, + GARRISON_ERROR_SPECIALIZATION_KNOWN = 19, + GARRISON_ERROR_BLUEPRINT_KNOWN = 21, + GARRISON_ERROR_BLUEPRINT_NOT_KNOWN = 22, + GARRISON_ERROR_BUILDING_EXISTS = 24, + GARRISON_ERROR_NOT_ENOUGH_CURRENCY = 46, + GARRISON_ERROR_NOT_ENOUGH_GOLD = 47 +}; + +enum GarrisonFollowerStatus +{ + FOLLOWER_STATUS_FAVORITE = 0x01, + FOLLOWER_STATUS_EXHAUSTED = 0x02, + FOLLOWER_STATUS_INACTIVE = 0x04 +}; + +class GameObject; +class Map; + +class Garrison +{ +public: + struct Building + { + ObjectGuid Guid; + Optional<WorldPackets::Garrison::GarrisonBuildingInfo> PacketInfo; + }; + + struct Plot + { + GameObject* CreateGameObject(Map* map, GarrisonFactionIndex faction); + + WorldPackets::Garrison::GarrisonPlotInfo PacketInfo; + uint32 EmptyGameObjectId = 0; + uint32 GarrSiteLevelPlotInstId = 0; + Building BuildingInfo; + }; + + explicit Garrison(Player* owner); + + bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings); + void SaveToDB(SQLTransaction& trans); + + bool Create(uint32 garrSiteId); + void Upgrade(); + + void Enter() const; + void Leave() const; + + GarrisonFactionIndex GetFaction() const; + std::vector<Plot*> GetPlots(); + Plot* GetPlot(uint32 garrPlotInstanceId); + + void LearnBlueprint(uint32 garrBuildingId); + void UnlearnBlueprint(uint32 garrBuildingId); + void PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId); + + void SendInfo(); + void SendRemoteInfo() const; + void SendBlueprintAndSpecializationData(); + void SendBuildingLandmarks(Player* receiver) const; + + void ResetFollowerActivationLimit() { _followerActivationsRemainingToday = 1; } + +private: + Map* FindMap() const; + void InitializePlots(); + GarrisonError CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const; + Player* _owner; + GarrSiteLevelEntry const* _siteLevel; + uint32 _followerActivationsRemainingToday; + + std::unordered_map<uint32 /*garrPlotInstanceId*/, Plot> _plots; + std::unordered_set<uint32 /*garrBuildingId*/> _knownBuildings; +}; + +#endif // Garrison_h__ diff --git a/src/server/game/Garrison/GarrisonMap.cpp b/src/server/game/Garrison/GarrisonMap.cpp new file mode 100644 index 00000000000..32b37cff03f --- /dev/null +++ b/src/server/game/Garrison/GarrisonMap.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "GarrisonMap.h" +#include "Garrison.h" +#include "ObjectAccessor.h" +#include "ObjectGridLoader.h" + +class GarrisonGridLoader +{ +public: + GarrisonGridLoader(NGridType* grid, GarrisonMap* map, Cell const& cell) + : i_cell(cell), i_grid(grid), i_map(map), i_garrison(map->GetGarrison()), i_gameObjects(0), i_creatures(0) + { } + + void Visit(GameObjectMapType& m); + void Visit(CreatureMapType& m); + + void LoadN(); + + template<class T> static void SetObjectCell(T* obj, CellCoord const& cellCoord); + template<class T> void Visit(GridRefManager<T>& /*m*/) { } + +private: + Cell i_cell; + NGridType* i_grid; + GarrisonMap* i_map; + Garrison* i_garrison; + uint32 i_gameObjects; + uint32 i_creatures; +}; + +void GarrisonGridLoader::LoadN() +{ + if (i_garrison) + { + i_cell.data.Part.cell_y = 0; + for (uint32 x = 0; x < MAX_NUMBER_OF_CELLS; ++x) + { + i_cell.data.Part.cell_x = x; + for (uint32 y = 0; y < MAX_NUMBER_OF_CELLS; ++y) + { + i_cell.data.Part.cell_y = y; + + //Load creatures and game objects + TypeContainerVisitor<GarrisonGridLoader, GridTypeMapContainer> visitor(*this); + i_grid->VisitGrid(x, y, visitor); + } + } + } + + TC_LOG_DEBUG("maps", "%u GameObjects and %u Creatures loaded for grid %u on map %u", i_gameObjects, i_creatures, i_grid->GetGridId(), i_map->GetId()); +} + +void GarrisonGridLoader::Visit(GameObjectMapType& m) +{ + std::vector<Garrison::Plot*> plots = i_garrison->GetPlots(); + if (!plots.empty()) + { + CellCoord cellCoord = i_cell.GetCellCoord(); + for (Garrison::Plot* plot : plots) + { + Position const& spawn = plot->PacketInfo.PlotPos; + if (cellCoord != Trinity::ComputeCellCoord(spawn.GetPositionX(), spawn.GetPositionY())) + continue; + + GameObject* go = plot->CreateGameObject(i_map, i_garrison->GetFaction()); + if (!go) + continue; + + go->AddToGrid(m); + ObjectGridLoader::SetObjectCell(go, cellCoord); + go->AddToWorld(); + ++i_gameObjects; + } + } +} + +void GarrisonGridLoader::Visit(CreatureMapType& /*m*/) +{ + +} + +GarrisonMap::GarrisonMap(uint32 id, time_t expiry, uint32 instanceId, Map* parent, ObjectGuid const& owner) + : Map(id, expiry, instanceId, DIFFICULTY_NORMAL, parent), _owner(owner) +{ + GarrisonMap::InitVisibilityDistance(); +} + +void GarrisonMap::LoadGridObjects(NGridType* grid, Cell const& cell) +{ + Map::LoadGridObjects(grid, cell); + + GarrisonGridLoader loader(grid, this, cell); + loader.LoadN(); +} + +Garrison* GarrisonMap::GetGarrison() +{ + if (Player* owner = ObjectAccessor::FindConnectedPlayer(_owner)) + return owner->GetGarrison(); + + return nullptr; +} + +void GarrisonMap::InitVisibilityDistance() +{ + //init visibility distance for instances + m_VisibleDistance = World::GetMaxVisibleDistanceInBGArenas(); + m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInBGArenas(); +} diff --git a/src/server/game/Garrison/GarrisonMap.h b/src/server/game/Garrison/GarrisonMap.h new file mode 100644 index 00000000000..0ccc77b05fa --- /dev/null +++ b/src/server/game/Garrison/GarrisonMap.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GarrisonMap_h__ +#define GarrisonMap_h__ + +#include "Map.h" + +class Garrison; + +class GarrisonMap : public Map +{ +public: + GarrisonMap(uint32 id, time_t, uint32 instanceId, Map* parent, ObjectGuid const& owner); + + void LoadGridObjects(NGridType* grid, Cell const& cell) override; + Garrison* GetGarrison(); + + void InitVisibilityDistance() override; + +private: + ObjectGuid _owner; +}; + +#endif // GarrisonMap_h__ diff --git a/src/server/game/Garrison/GarrisonMgr.cpp b/src/server/game/Garrison/GarrisonMgr.cpp new file mode 100644 index 00000000000..dd3ff08c0d1 --- /dev/null +++ b/src/server/game/Garrison/GarrisonMgr.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "GarrisonMgr.h" + +void GarrisonMgr::Initialize() +{ + for (GarrSiteLevelPlotInstEntry const* plotInstance : sGarrSiteLevelPlotInstStore) + _garrisonPlotInstBySiteLevel[plotInstance->GarrSiteLevelID].push_back(plotInstance); + + for (GameObjectsEntry const* gameObject : sGameObjectsStore) + if (gameObject->Type == GAMEOBJECT_TYPE_GARRISON_PLOT) + _garrisonPlots[gameObject->MapID][gameObject->Data[0]] = gameObject; + + for (GarrPlotBuildingEntry const* plotBuilding : sGarrPlotBuildingStore) + _garrisonBuildingsByPlot[plotBuilding->GarrPlotID].insert(plotBuilding->GarrBuildingID); + + for (GarrBuildingPlotInstEntry const* buildingPlotInst : sGarrBuildingPlotInstStore) + _garrisonBuildingPlotInstances[MAKE_PAIR64(buildingPlotInst->GarrBuildingID, buildingPlotInst->GarrSiteLevelPlotInstID)] = buildingPlotInst->ID; +} + +GarrSiteLevelEntry const* GarrisonMgr::GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const +{ + for (GarrSiteLevelEntry const* garrSiteLevel : sGarrSiteLevelStore) + if (garrSiteLevel->SiteID == garrSiteId && garrSiteLevel->Level == level) + return garrSiteLevel; + + return nullptr; +} + +std::vector<GarrSiteLevelPlotInstEntry const*> const* GarrisonMgr::GetGarrPlotInstForSiteLevel(uint32 garrSiteLevelId) const +{ + auto itr = _garrisonPlotInstBySiteLevel.find(garrSiteLevelId); + if (itr != _garrisonPlotInstBySiteLevel.end()) + return &itr->second; + + return nullptr; +} + +GameObjectsEntry const* GarrisonMgr::GetPlotGameObject(uint32 mapId, uint32 garrPlotInstanceId) const +{ + auto mapItr = _garrisonPlots.find(mapId); + if (mapItr != _garrisonPlots.end()) + { + auto plotItr = mapItr->second.find(garrPlotInstanceId); + if (plotItr != mapItr->second.end()) + return plotItr->second; + } + + return nullptr; +} + +bool GarrisonMgr::IsPlotMatchingBuilding(uint32 garrPlotId, uint32 garrBuildingId) const +{ + auto plotItr = _garrisonBuildingsByPlot.find(garrPlotId); + if (plotItr != _garrisonBuildingsByPlot.end()) + return plotItr->second.count(garrBuildingId) > 0; + + return false; +} + +uint32 GarrisonMgr::GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSiteLevelPlotInstId) const +{ + auto itr = _garrisonBuildingPlotInstances.find(MAKE_PAIR64(garrBuildingId, garrSiteLevelPlotInstId)); + if (itr != _garrisonBuildingPlotInstances.end()) + return itr->second; + + return 0; +} diff --git a/src/server/game/Garrison/GarrisonMgr.h b/src/server/game/Garrison/GarrisonMgr.h new file mode 100644 index 00000000000..ca6f4adbe48 --- /dev/null +++ b/src/server/game/Garrison/GarrisonMgr.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GarrisonMgr_h__ +#define GarrisonMgr_h__ + +#include "DB2Stores.h" + +class GarrisonMgr +{ +public: + static GarrisonMgr& Instance() + { + static GarrisonMgr instance; + return instance; + } + + void Initialize(); + + GarrSiteLevelEntry const* GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const; + std::vector<GarrSiteLevelPlotInstEntry const*> const* GetGarrPlotInstForSiteLevel(uint32 garrSiteLevelId) const; + GameObjectsEntry const* GetPlotGameObject(uint32 mapId, uint32 garrPlotInstanceId) const; + bool IsPlotMatchingBuilding(uint32 garrPlotId, uint32 garrBuildingId) const; + uint32 GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSiteLevelPlotInstId) const; + +private: + std::unordered_map<uint32 /*garrSiteId*/, std::vector<GarrSiteLevelPlotInstEntry const*>> _garrisonPlotInstBySiteLevel; + std::unordered_map<uint32 /*mapId*/, std::unordered_map<uint32 /*garrPlotId*/, GameObjectsEntry const*>> _garrisonPlots; + std::unordered_map<uint32 /*garrPlotId*/, std::unordered_set<uint32/*garrBuildingId*/>> _garrisonBuildingsByPlot; + std::unordered_map<uint64 /*garrBuildingId | garrSiteLevelPlotInstId << 32*/, uint32 /*garrBuildingPlotInstId*/> _garrisonBuildingPlotInstances; +}; + +#define sGarrisonMgr GarrisonMgr::Instance() + +#endif // GarrisonMgr_h__ diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 0679cc60cfc..ac87f58af5c 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -6459,6 +6459,22 @@ void ObjectMgr::LoadGameObjectTemplate() { uint32 oldMSTime = getMSTime(); + for (GameObjectsEntry const* db2go : sGameObjectsStore) + { + GameObjectTemplate& go = _gameObjectTemplateStore[db2go->ID]; + go.entry = db2go->ID; + go.type = db2go->Type; + go.displayId = db2go->DisplayID; + go.name = db2go->Name->Str[sWorld->GetDefaultDbcLocale()]; + go.faction = 0; + go.flags = 0; + go.size = db2go->Size; + memset(go.raw.data, 0, sizeof(go.raw.data)); + memcpy(go.raw.data, db2go->Data, std::min(sizeof(db2go->Data), sizeof(go.raw.data))); + go.unkInt32 = 0; + go.ScriptId = 0; + } + // 0 1 2 3 4 5 6 7 8 9 QueryResult result = WorldDatabase.Query("SELECT entry, type, displayId, name, IconName, castBarCaption, unk1, faction, flags, size, " // 10 11 12 13 14 15 16 17 18 19 20 21 22 diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index e7818a841aa..56d865e5d06 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -236,6 +236,18 @@ bool LoginQueryHolder::Initialize() stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CURRENCY, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS, stmt); + return res; } diff --git a/src/server/game/Handlers/GarrisonHandler.cpp b/src/server/game/Handlers/GarrisonHandler.cpp new file mode 100644 index 00000000000..0b45fb0ab57 --- /dev/null +++ b/src/server/game/Handlers/GarrisonHandler.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "WorldSession.h" +#include "Garrison.h" +#include "GarrisonPackets.h" + +void WorldSession::HandleGetGarrisonInfo(WorldPackets::Garrison::GetGarrisonInfo& /*getGarrisonInfo*/) +{ + if (Garrison* garrison = _player->GetGarrison()) + garrison->SendInfo(); +} + +void WorldSession::HandleGarrisonPurchaseBuilding(WorldPackets::Garrison::GarrisonPurchaseBuilding& garrisonPurchaseBuilding) +{ + if (!_player->GetNPCIfCanInteractWith(garrisonPurchaseBuilding.NpcGUID, UNIT_NPC_FLAG_GARRISON_ARCHITECT)) + return; + + if (Garrison* garrison = _player->GetGarrison()) + garrison->PlaceBuilding(garrisonPurchaseBuilding.PlotInstanceID, garrisonPurchaseBuilding.BuildingID); +} + +void WorldSession::HandleGarrisonRequestBlueprintAndSpecializationData(WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData& /*garrisonRequestBlueprintAndSpecializationData*/) +{ + if (Garrison* garrison = _player->GetGarrison()) + garrison->SendBlueprintAndSpecializationData(); +} + +void WorldSession::HandleGarrisonGetBuildingLandmarks(WorldPackets::Garrison::GarrisonGetBuildingLandmarks& /*garrisonGetBuildingLandmarks*/) +{ + if (Garrison* garrison = _player->GetGarrison()) + garrison->SendBuildingLandmarks(_player); +} diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 0cedc1b239c..240825faade 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -23,6 +23,7 @@ #include "Log.h" #include "Corpse.h" #include "Player.h" +#include "Garrison.h" #include "SpellAuras.h" #include "MapManager.h" #include "Transport.h" @@ -131,7 +132,11 @@ void WorldSession::HandleMoveWorldportAckOpcode() if (!seamlessTeleport) GetPlayer()->SendInitialPacketsAfterAddToMap(); else + { GetPlayer()->UpdateVisibilityForPlayer(); + if (Garrison* garrison = GetPlayer()->GetGarrison()) + garrison->SendRemoteInfo(); + } // flight fast teleport case if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 989e7b5f825..d65682dc6ce 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -448,8 +448,7 @@ bool Map::EnsureGridLoaded(const Cell &cell) setGridObjectDataLoaded(true, cell.GridX(), cell.GridY()); - ObjectGridLoader loader(*grid, this, cell); - loader.LoadN(); + LoadGridObjects(grid, cell); // Add resurrectable corpses to world object list in grid sObjectAccessor->AddCorpsesToGrid(GridCoord(cell.GridX(), cell.GridY()), grid->GetGridType(cell.CellX(), cell.CellY()), this); @@ -460,6 +459,12 @@ bool Map::EnsureGridLoaded(const Cell &cell) return false; } +void Map::LoadGridObjects(NGridType* grid, Cell const& cell) +{ + ObjectGridLoader loader(*grid, this, cell); + loader.LoadN(); +} + void Map::LoadGrid(float x, float y) { EnsureGridLoaded(Cell(x, y)); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 02a8292777a..a2faa8cc0a0 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -394,6 +394,7 @@ class Map : public GridRefManager<NGridType> bool IsBattleground() const { return i_mapEntry && i_mapEntry->IsBattleground(); } bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } bool IsBattlegroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattlegroundOrArena(); } + bool IsGarrison() const { return i_mapEntry && i_mapEntry->IsGarrison(); } bool GetEntrancePos(int32 &mapid, float &x, float &y) { if (!i_mapEntry) @@ -601,6 +602,7 @@ class Map : public GridRefManager<NGridType> protected: void SetUnloadReferenceLock(const GridCoord &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } + virtual void LoadGridObjects(NGridType* grid, Cell const& cell); std::mutex _mapLock; std::mutex _gridLock; diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index c48b616788e..473e3163216 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -26,6 +26,7 @@ #include "World.h" #include "Group.h" #include "Player.h" +#include "GarrisonMap.h" MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DIFFICULTY_NORMAL) { @@ -138,7 +139,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) } } } - else + else if (!IsGarrison()) { InstancePlayerBind* pBind = player->GetBoundInstance(GetId(), player->GetDifficultyID(GetEntry())); InstanceSave* pSave = pBind ? pBind->save : NULL; @@ -180,6 +181,13 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) map = CreateInstance(newInstanceId, NULL, diff); } } + else + { + newInstanceId = player->GetGUID().GetCounter(); + map = FindInstanceMap(newInstanceId); + if (!map) + map = CreateGarrison(newInstanceId, player); + } return map; } @@ -237,6 +245,17 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun return map; } +GarrisonMap* MapInstanced::CreateGarrison(uint32 instanceId, Player* owner) +{ + std::lock_guard<std::mutex> lock(_mapLock); + + GarrisonMap* map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner->GetGUID()); + ASSERT(map->IsGarrison()); + + m_InstancedMaps[instanceId] = map; + return map; +} + // increments the iterator after erase bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) { diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index c385215ba76..e487957ed6e 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -23,6 +23,8 @@ #include "InstanceSaveMgr.h" #include "DBCEnums.h" +class GarrisonMap; + class MapInstanced : public Map { friend class MapManager; @@ -66,6 +68,7 @@ class MapInstanced : public Map private: InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty); BattlegroundMap* CreateBattleground(uint32 InstanceId, Battleground* bg); + GarrisonMap* CreateGarrison(uint32 instanceId, Player* owner); InstancedMaps m_InstancedMaps; diff --git a/src/server/game/Server/Packets/GarrisonPackets.cpp b/src/server/game/Server/Packets/GarrisonPackets.cpp new file mode 100644 index 00000000000..09097450486 --- /dev/null +++ b/src/server/game/Server/Packets/GarrisonPackets.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "GarrisonPackets.h" + +WorldPacket const* WorldPackets::Garrison::GarrisonCreateResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << uint32(GarrSiteLevelID); + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonPlotInfo& plotInfo) +{ + data << uint32(plotInfo.GarrPlotInstanceID); + data << plotInfo.PlotPos.PositionXYZOStream(); + data << uint32(plotInfo.PlotType); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo) +{ + data << uint32(buildingInfo.GarrPlotInstanceID); + data << uint32(buildingInfo.GarrBuildingID); + data << uint32(buildingInfo.TimeBuilt); + data << uint32(buildingInfo.CurrentGarSpecID); + data << uint32(buildingInfo.TimeSpecCooldown); + data.WriteBit(buildingInfo.Active); + data.FlushBits(); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonFollower const& follower) +{ + data << uint64(follower.DbID); + data << uint32(follower.GarrFollowerID); + data << uint32(follower.Quality); + data << uint32(follower.FollowerLevel); + data << uint32(follower.ItemLevelWeapon); + data << uint32(follower.ItemLevelArmor); + data << uint32(follower.Xp); + data << uint32(follower.CurrentBuildingID); + data << uint32(follower.CurrentMissionID); + data << uint32(follower.AbilityID.size()); + data << uint32(follower.FollowerStatus); + if (!follower.AbilityID.empty()) + data.append(follower.AbilityID.data(), follower.AbilityID.size()); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonMission const& mission) +{ + data << uint64(mission.DbID); + data << uint32(mission.MissionRecID); + data << uint32(mission.OfferTime); + data << uint32(mission.OfferDuration); + data << uint32(mission.StartTime); + data << uint32(mission.TravelDuration); + data << uint32(mission.MissionDuration); + data << uint32(mission.MissionState); + + return data; +} + +WorldPacket const* WorldPackets::Garrison::GetGarrisonInfoResult::Write() +{ + _worldPacket.reserve(4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + + Buildings.size() * sizeof(GarrisonBuildingInfo) + + Plots.size() * sizeof(GarrisonPlotInfo) + + Followers.size() * (sizeof(GarrisonFollower) + 5 * 4) + + Missions.size() * sizeof(GarrisonMission) + + ArchivedMissions.size() * 4); + + _worldPacket << int32(GarrSiteID); + _worldPacket << int32(GarrSiteLevelID); + _worldPacket << int32(FactionIndex); + _worldPacket << uint32(Buildings.size()); + _worldPacket << uint32(Plots.size()); + _worldPacket << uint32(Followers.size()); + _worldPacket << uint32(Missions.size()); + _worldPacket << uint32(ArchivedMissions.size()); + _worldPacket << int32(NumFollowerActivationsRemaining); + + for (GarrisonBuildingInfo const* building : Buildings) + _worldPacket << *building; + + for (GarrisonPlotInfo* plot : Plots) + _worldPacket << *plot; + + for (GarrisonFollower const* follower : Followers) + _worldPacket << *follower; + + for (GarrisonMission const* mission : Missions) + _worldPacket << *mission; + + if (!ArchivedMissions.empty()) + _worldPacket.append(ArchivedMissions.data(), ArchivedMissions.size()); + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonRemoteBuildingInfo const& building) +{ + data << uint32(building.GarrPlotInstanceID); + data << uint32(building.GarrBuildingID); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonRemoteSiteInfo const& site) +{ + data << uint32(site.GarrSiteLevelID); + data << uint32(site.Buildings.size()); + for (WorldPackets::Garrison::GarrisonRemoteBuildingInfo const& building : site.Buildings) + data << building; + + return data; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonRemoteInfo::Write() +{ + _worldPacket << uint32(Sites.size()); + for (GarrisonRemoteSiteInfo const& site : Sites) + _worldPacket << site; + + return &_worldPacket; +} + +void WorldPackets::Garrison::GarrisonPurchaseBuilding::Read() +{ + _worldPacket >> NpcGUID; + _worldPacket >> PlotInstanceID; + _worldPacket >> BuildingID; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonPlaceBuildingResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << BuildingInfo; + _worldPacket.WriteBit(Active); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonLearnBlueprintResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << uint32(BuildingID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonUnlearnBlueprintResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << uint32(BuildingID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationDataResult::Write() +{ + _worldPacket << uint32(BlueprintsKnown ? BlueprintsKnown->size() : 0); + _worldPacket << uint32(SpecializationsKnown ? SpecializationsKnown->size() : 0); + if (BlueprintsKnown) + for (uint32 blueprint : *BlueprintsKnown) + _worldPacket << uint32(blueprint); + + if (SpecializationsKnown) + for (uint32 specialization : *SpecializationsKnown) + _worldPacket << uint32(specialization); + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonBuildingLandmark& landmark) +{ + data << uint32(landmark.GarrBuildingPlotInstID); + data << landmark.Pos.PositionXYZStream(); + + return data; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonBuildingLandmarks::Write() +{ + _worldPacket << uint32(Landmarks.size()); + for (GarrisonBuildingLandmark& landmark : Landmarks) + _worldPacket << landmark; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/GarrisonPackets.h b/src/server/game/Server/Packets/GarrisonPackets.h new file mode 100644 index 00000000000..c632a5d6103 --- /dev/null +++ b/src/server/game/Server/Packets/GarrisonPackets.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GarrisonPackets_h__ +#define GarrisonPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" +#include "Position.h" +#include "PacketUtilities.h" + +namespace WorldPackets +{ + namespace Garrison + { + class GarrisonCreateResult final : public ServerPacket + { + public: + GarrisonCreateResult() : ServerPacket(SMSG_GARRISON_CREATE_RESULT, 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 GarrSiteLevelID = 0; + uint32 Result = 0; + }; + + class GetGarrisonInfo final : public ClientPacket + { + public: + GetGarrisonInfo(WorldPacket&& packet) : ClientPacket(CMSG_GET_GARRISON_INFO, std::move(packet)) { } + + void Read() override { } + }; + + struct GarrisonPlotInfo + { + uint32 GarrPlotInstanceID = 0; + Position PlotPos; + uint32 PlotType = 0; + }; + + struct GarrisonBuildingInfo + { + uint32 GarrPlotInstanceID = 0; + uint32 GarrBuildingID = 0; + time_t TimeBuilt = time_t(0); + uint32 CurrentGarSpecID = 0; + time_t TimeSpecCooldown = time_t(2288912640); // 06/07/1906 18:35:44 - another in the series of magic blizz dates + bool Active = false; + }; + + struct GarrisonFollower + { + uint64 DbID = 0; + uint32 GarrFollowerID = 0; + uint32 Quality = 0; + uint32 FollowerLevel = 0; + uint32 ItemLevelWeapon = 0; + uint32 ItemLevelArmor = 0; + uint32 Xp = 0; + uint32 CurrentBuildingID = 0; + uint32 CurrentMissionID = 0; + std::vector<uint32> AbilityID; + uint32 FollowerStatus; + }; + + struct GarrisonMission + { + uint64 DbID = 0; + uint32 MissionRecID = 0; + time_t OfferTime = time_t(0); + uint32 OfferDuration = 0; + time_t StartTime = time_t(2288912640); + uint32 TravelDuration = 0; + uint32 MissionDuration = 0; + uint32 MissionState = 0; + }; + + class GetGarrisonInfoResult final : public ServerPacket + { + public: + GetGarrisonInfoResult() : ServerPacket(SMSG_GET_GARRISON_INFO_RESULT) { } + + WorldPacket const* Write() override; + + uint32 GarrSiteID = 0; + uint32 GarrSiteLevelID = 0; + uint32 FactionIndex = 0; + uint32 NumFollowerActivationsRemaining = 0; + std::vector<GarrisonPlotInfo*> Plots; + std::vector<GarrisonBuildingInfo*> Buildings; + std::vector<GarrisonFollower*> Followers; + std::vector<GarrisonMission*> Missions; + std::vector<int32> ArchivedMissions; + }; + + struct GarrisonRemoteBuildingInfo + { + GarrisonRemoteBuildingInfo() : GarrPlotInstanceID(0), GarrBuildingID(0) { } + GarrisonRemoteBuildingInfo(uint32 plotInstanceId, uint32 buildingId) : GarrPlotInstanceID(plotInstanceId), GarrBuildingID(buildingId) { } + + uint32 GarrPlotInstanceID; + uint32 GarrBuildingID; + }; + + struct GarrisonRemoteSiteInfo + { + uint32 GarrSiteLevelID = 0; + std::vector<GarrisonRemoteBuildingInfo> Buildings; + }; + + class GarrisonRemoteInfo final : public ServerPacket + { + public: + GarrisonRemoteInfo() : ServerPacket(SMSG_GARRISON_REMOTE_INFO) { } + + WorldPacket const* Write() override; + + std::vector<GarrisonRemoteSiteInfo> Sites; + }; + + class GarrisonPurchaseBuilding final : public ClientPacket + { + public: + GarrisonPurchaseBuilding(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_PURCHASE_BUILDING, std::move(packet)) { } + + void Read() override; + + ObjectGuid NpcGUID; + uint32 BuildingID = 0; + uint32 PlotInstanceID = 0; + }; + + class GarrisonPlaceBuildingResult final : public ServerPacket + { + public: + GarrisonPlaceBuildingResult() : ServerPacket(SMSG_GARRISON_PLACE_BUILDING_RESULT) { } + + WorldPacket const* Write() override; + + uint32 Result = 0; + GarrisonBuildingInfo BuildingInfo; + bool Active = false; + }; + + class GarrisonLearnBlueprintResult final : public ServerPacket + { + public: + GarrisonLearnBlueprintResult() : ServerPacket(SMSG_GARRISON_LEARN_BLUEPRINT_RESULT, 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 BuildingID = 0; + uint32 Result = 0; + }; + + class GarrisonUnlearnBlueprintResult final : public ServerPacket + { + public: + GarrisonUnlearnBlueprintResult() : ServerPacket(SMSG_GARRISON_UNLEARN_BLUEPRINT_RESULT, 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 BuildingID = 0; + uint32 Result = 0; + }; + + class GarrisonRequestBlueprintAndSpecializationData final : public ClientPacket + { + public: + GarrisonRequestBlueprintAndSpecializationData(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA, std::move(packet)) { } + + void Read() override { } + }; + + class GarrisonRequestBlueprintAndSpecializationDataResult final : public ServerPacket + { + public: + GarrisonRequestBlueprintAndSpecializationDataResult() : ServerPacket(SMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA_RESULT, 400) { } + + WorldPacket const* Write() override; + + std::unordered_set<uint32> const* SpecializationsKnown = nullptr; + std::unordered_set<uint32> const* BlueprintsKnown = nullptr; + }; + + class GarrisonGetBuildingLandmarks final : public ClientPacket + { + public: + GarrisonGetBuildingLandmarks(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_GET_BUILDING_LANDMARKS, std::move(packet)) { } + + void Read() override { } + }; + + struct GarrisonBuildingLandmark + { + GarrisonBuildingLandmark() : GarrBuildingPlotInstID(0), Pos() { } + GarrisonBuildingLandmark(uint32 buildingPlotInstId, Position const& pos) : GarrBuildingPlotInstID(buildingPlotInstId), Pos(pos) { } + + uint32 GarrBuildingPlotInstID; + Position Pos; + }; + + class GarrisonBuildingLandmarks final : public ServerPacket + { + public: + GarrisonBuildingLandmarks() : ServerPacket(SMSG_GARRISON_BUILDING_LANDMARKS) { } + + WorldPacket const* Write() override; + + std::vector<GarrisonBuildingLandmark> Landmarks; + }; + } +} + +#endif // GarrisonPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 71535d6b281..6efac892cf9 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -31,6 +31,7 @@ #include "Packets/DuelPackets.h" #include "Packets/EquipmentSetPackets.h" #include "Packets/GameObjectPackets.h" +#include "Packets/GarrisonPackets.h" #include "Packets/GuildPackets.h" #include "Packets/InspectPackets.h" #include "Packets/InstancePackets.h" @@ -373,13 +374,13 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_GARRISON_CHECK_UPGRADEABLE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_COMPLETE_MISSION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_GENERATE_RECRUITS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GARRISON_GET_BUILDING_LANDMARKS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GARRISON_GET_BUILDING_LANDMARKS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonGetBuildingLandmarks, &WorldSession::HandleGarrisonGetBuildingLandmarks); DEFINE_HANDLER(CMSG_GARRISON_MISSION_BONUS_ROLL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GARRISON_PURCHASE_BUILDING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GARRISON_PURCHASE_BUILDING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonPurchaseBuilding, &WorldSession::HandleGarrisonPurchaseBuilding); DEFINE_HANDLER(CMSG_GARRISON_RECRUIT_FOLLOWER, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_REMOVE_FOLLOWER, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_REMOVE_FOLLOWER_FROM_BUILDING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData, &WorldSession::HandleGarrisonRequestBlueprintAndSpecializationData); DEFINE_HANDLER(CMSG_GARRISON_REQUEST_LANDING_PAGE_SHIPMENT_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_REQUEST_SHIPMENT_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_SET_BUILDING_ACTIVE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -390,7 +391,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_GARRISON_SWAP_BUILDINGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GENERATE_RANDOM_CHARACTER_NAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::GenerateRandomCharacterName, &WorldSession::HandleRandomizeCharNameOpcode); DEFINE_HANDLER(CMSG_GET_CHALLENGE_MODE_REWARDS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GET_GARRISON_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GET_GARRISON_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GetGarrisonInfo, &WorldSession::HandleGetGarrisonInfo); DEFINE_HANDLER(CMSG_GET_ITEM_PURCHASE_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::GetItemPurchaseData, &WorldSession::HandleGetItemPurchaseData); DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_MIRROR_IMAGE_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMirrorImageDataRequest ); DEFINE_HANDLER(CMSG_GET_PVP_OPTIONS_ENABLED, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Battleground::GetPVPOptionsEnabled, &WorldSession::HandleGetPVPOptionsEnabled); @@ -1108,51 +1109,51 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_SPEED_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_TIME_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ASSIGN_FOLLOWER_TO_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_ACTIVATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_LANDMARKS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_SET_ACTIVE_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_COMPLETE_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_CREATE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_DELETE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL2, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_XP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_IS_UPGRADEABLE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LANDINGPAGE_SHIPMENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_BLUEPRINT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_FOLLOWERS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_MISSIONS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_MISSION_BONUS_ROLL_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_NUM_FOLLOWER_ACTIVATIONS_REMAINING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_ARCHITECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_MISSION_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_TRADESKILL_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLACE_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_PLACED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_LAST_USED_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_USED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUITMENT_FOLLOWERS_GENERATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUIT_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOTE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_FROM_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_START_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UNLEARN_BLUEPRINT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UPGRADE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ASSIGN_FOLLOWER_TO_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_ACTIVATED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_LANDMARKS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_SET_ACTIVE_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_COMPLETE_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_CREATE_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_DELETE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL2, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_XP, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_IS_UPGRADEABLE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LANDINGPAGE_SHIPMENTS, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_BLUEPRINT_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_FOLLOWERS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_MISSIONS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_MISSION_BONUS_ROLL_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_NUM_FOLLOWER_ACTIVATIONS_REMAINING, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_ARCHITECT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_MISSION_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_TRADESKILL_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLACE_BUILDING_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_PLACED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_LAST_USED_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_USED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUITMENT_FOLLOWERS_GENERATED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUIT_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOTE_INFO, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_FROM_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_START_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UNLEARN_BLUEPRINT_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UPGRADE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GENERATE_RANDOM_CHARACTER_NAME_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_ACCOUNT_CHARACTER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_DISPLAYED_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_GARRISON_INFO_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENTS_OF_TYPE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENT_INFO_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_DISPLAYED_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_GARRISON_INFO_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENTS_OF_TYPE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENT_INFO_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_REQUEST_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index e49013379ba..da7cbbe8020 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -214,6 +214,14 @@ namespace WorldPackets class GameObjUse; } + namespace Garrison + { + class GetGarrisonInfo; + class GarrisonPurchaseBuilding; + class GarrisonRequestBlueprintAndSpecializationData; + class GarrisonGetBuildingLandmarks; + } + namespace Guild { class QueryGuildInfo; @@ -1464,6 +1472,12 @@ class WorldSession void HandleSaveCUFProfiles(WorldPacket& recvPacket); void SendLoadCUFProfiles(); + // Garrison + void HandleGetGarrisonInfo(WorldPackets::Garrison::GetGarrisonInfo& getGarrisonInfo); + void HandleGarrisonPurchaseBuilding(WorldPackets::Garrison::GarrisonPurchaseBuilding& garrisonPurchaseBuilding); + void HandleGarrisonRequestBlueprintAndSpecializationData(WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData& garrisonRequestBlueprintAndSpecializationData); + void HandleGarrisonGetBuildingLandmarks(WorldPackets::Garrison::GarrisonGetBuildingLandmarks& garrisonGetBuildingLandmarks); + private: void InitializeQueryCallbackParameters(); void ProcessQueryCallbacks(); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index ddf6cb055ae..d363f845a8e 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -405,6 +405,8 @@ class Spell void EffectCreateAreaTrigger(SpellEffIndex effIndex); void EffectRemoveTalent(SpellEffIndex effIndex); void EffectDestroyItem(SpellEffIndex effIndex); + void EffectLearnGarrisonBuilding(SpellEffIndex effIndex); + void EffectCreateGarrison(SpellEffIndex effIndex); typedef std::set<Aura*> UsedSpellMods; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 89112b194e1..97e82426e9d 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -67,6 +67,7 @@ #include "GuildMgr.h" #include "ReputationMgr.h" #include "AreaTrigger.h" +#include "Garrison.h" #include "DuelPackets.h" #include "MiscPackets.h" #include "SpellPackets.h" @@ -283,11 +284,11 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //207 SPELL_EFFECT_LAUNCH_QUEST_TASK &Spell::EffectNULL, //208 SPELL_EFFECT_208 &Spell::EffectNULL, //209 SPELL_EFFECT_209 - &Spell::EffectNULL, //210 SPELL_EFFECT_LEARN_GARRISON_BUILDING + &Spell::EffectLearnGarrisonBuilding, //210 SPELL_EFFECT_LEARN_GARRISON_BUILDING &Spell::EffectNULL, //211 SPELL_EFFECT_LEARN_GARRISON_SPECIALIZATION &Spell::EffectNULL, //212 SPELL_EFFECT_212 &Spell::EffectNULL, //213 SPELL_EFFECT_213 - &Spell::EffectNULL, //214 SPELL_EFFECT_CREATE_GARRISON + &Spell::EffectCreateGarrison, //214 SPELL_EFFECT_CREATE_GARRISON &Spell::EffectNULL, //215 SPELL_EFFECT_UPGRADE_CHARACTER_SPELLS &Spell::EffectNULL, //216 SPELL_EFFECT_CREATE_SHIPMENT &Spell::EffectNULL, //217 SPELL_EFFECT_UPGRADE_GARRISON @@ -5801,3 +5802,26 @@ void Spell::EffectDestroyItem(SpellEffIndex effIndex) if (Item* item = player->GetItemByEntry(itemId)) player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); } + +void Spell::EffectLearnGarrisonBuilding(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (Garrison* garrison = unitTarget->ToPlayer()->GetGarrison()) + garrison->LearnBlueprint(GetEffect(effIndex)->MiscValue); +} + +void Spell::EffectCreateGarrison(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->CreateGarrison(GetEffect(effIndex)->MiscValue); +} diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index c06a4f8060e..9b8c63000fc 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -38,6 +38,7 @@ #include "DatabaseEnv.h" #include "DisableMgr.h" #include "GameEventMgr.h" +#include "GarrisonMgr.h" #include "GridNotifiersImpl.h" #include "GroupMgr.h" #include "GuildFinderMgr.h" @@ -1871,6 +1872,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading client addons..."); AddonMgr::LoadFromDB(); + TC_LOG_INFO("server.loading", "Loading garrison info..."); + sGarrisonMgr.Initialize(); + ///- Handle outdated emails (delete/return) TC_LOG_INFO("server.loading", "Returning old mails..."); sObjectMgr->ReturnOrDeleteOldMails(false); @@ -2123,7 +2127,7 @@ void World::Update(uint32 diff) /// Handle daily quests reset time if (m_gameTime > m_NextDailyQuestReset) { - ResetDailyQuests(); + DailyReset(); m_NextDailyQuestReset += DAY; } @@ -3052,16 +3056,20 @@ void World::InitCurrencyResetTime() sWorld->setWorldState(WS_CURRENCY_RESET_TIME, uint64(m_NextCurrencyReset)); } -void World::ResetDailyQuests() +void World::DailyReset() { TC_LOG_INFO("misc", "Daily quests reset for all characters."); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY); CharacterDatabase.Execute(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS); + stmt->setUInt32(0, 1); + CharacterDatabase.Execute(stmt); + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) if (itr->second->GetPlayer()) - itr->second->GetPlayer()->ResetDailyQuestStatus(); + itr->second->GetPlayer()->DailyReset(); // change available dailies sPoolMgr->ChangeDailyQuests(); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 1a3cfd6f985..b169431f2fd 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -805,7 +805,7 @@ class World void InitRandomBGResetTime(); void InitGuildResetTime(); void InitCurrencyResetTime(); - void ResetDailyQuests(); + void DailyReset(); void ResetWeeklyQuests(); void ResetMonthlyQuests(); void ResetRandomBG(); diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h index 4ce77c1cd28..c541a6651a3 100644 --- a/src/server/shared/DataStores/DB2Store.h +++ b/src/server/shared/DataStores/DB2Store.h @@ -112,6 +112,8 @@ public: void EraseRecord(uint32 id) override { if (id < _indexTableSize) _indexTable.AsT[id] = nullptr; } T const* LookupEntry(uint32 id) const { return (id >= _indexTableSize) ? nullptr : _indexTable.AsT[id]; } + T const* AssertEntry(uint32 id) const { return ASSERT_NOTNULL(LookupEntry(id)); } + std::string const& GetFileName() const { return _fileName; } uint32 GetNumRows() const { return _indexTableSize; } char const* GetFormat() const { return _format; } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 6c18a0e76ee..e9ce253d1cf 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -681,4 +681,16 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_QUEST_TRACK_GM_COMPLETE, "UPDATE quest_tracker SET completed_by_gm = 1 WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_QUEST_TRACK_COMPLETE_TIME, "UPDATE quest_tracker SET quest_complete_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME, "UPDATE quest_tracker SET quest_abandon_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); + + // Garrison + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON, "SELECT siteLevelId, followerActivationsRemainingToday FROM character_garrison WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON, "INSERT INTO character_garrison (guid, siteLevelId, followerActivationsRemainingToday) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON, "DELETE FROM character_garrison WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS, "UPDATE character_garrison SET followerActivationsRemainingToday = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS, "SELECT buildingId FROM character_garrison_blueprints WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS, "INSERT INTO character_garrison_blueprints (guid, buildingId) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS, "DELETE FROM character_garrison_blueprints WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, "SELECT plotInstanceId, buildingId, timeBuilt, active FROM character_garrison_buildings WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS, "INSERT INTO character_garrison_buildings (guid, plotInstanceId, buildingId, timeBuilt, active) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, "DELETE FROM character_garrison_buildings WHERE guid = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index ed3b6dd8098..53c42a0b852 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -598,6 +598,17 @@ enum CharacterDatabaseStatements CHAR_UPD_QUEST_TRACK_COMPLETE_TIME, CHAR_UPD_QUEST_TRACK_ABANDON_TIME, + CHAR_SEL_CHARACTER_GARRISON, + CHAR_INS_CHARACTER_GARRISON, + CHAR_DEL_CHARACTER_GARRISON, + CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS, + CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS, + CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS, + CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS, + CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, + CHAR_INS_CHARACTER_GARRISON_BUILDINGS, + CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, + MAX_CHARACTERDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.cpp b/src/server/shared/Database/Implementation/HotfixDatabase.cpp index e13863d9326..1afb118a06e 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/shared/Database/Implementation/HotfixDatabase.cpp @@ -39,12 +39,51 @@ void HotfixDatabaseConnection::DoPrepareStatements() PREPARE_LOCALE_STMT(HOTFIX_SEL_BROADCAST_TEXT, "SELECT ID, MaleText_lang, FemaleText_lang FROM broadcast_text_locale WHERE locale = ?", CONNECTION_SYNCH); // CurrencyTypes.db2 - PrepareStatement(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, CategoryID, Name, InventoryIcon1, InventoryIcon2, SpellWeight, SpellCategory, MaxQty, MaxEarnablePerWeek, Flags, Quality, Description FROM currency_types ORDER BY ID DESC", CONNECTION_SYNCH); - PREPARE_LOCALE_STMT(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, Name_lang, InventoryIcon1_lang, InventoryIcon2_lang, Description_lang FROM currency_types_locale WHERE locale = ?", CONNECTION_SYNCH); + PrepareStatement(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, CategoryID, Name, InventoryIcon1, InventoryIcon2, SpellWeight, SpellCategory, " + "MaxQty, MaxEarnablePerWeek, Flags, Quality, Description FROM currency_types ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, Name_lang, InventoryIcon1_lang, InventoryIcon2_lang, " + "Description_lang FROM currency_types_locale WHERE locale = ?", CONNECTION_SYNCH); // CurvePoint.db2 PrepareStatement(HOTFIX_SEL_CURVE_POINT, "SELECT ID, CurveID, `Index`, X, Y FROM curve_point ORDER BY ID DESC", CONNECTION_SYNCH); + // GameObjects.db2 + PrepareStatement(HOTFIX_SEL_GAMEOBJECTS, "SELECT ID, MapID, DisplayID, PositionX, PositionY, PositionZ, RotationX, RotationY, RotationZ, RotationW, Size, " + "PhaseUseFlags, PhaseID, PhaseGroupID, Type, Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Name FROM gameobjects ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GAMEOBJECTS, "SELECT ID, Name_lang FROM gameobjects_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrBuilding.db2 + PrepareStatement(HOTFIX_SEL_GARR_BUILDING, "SELECT ID, HordeGameObjectID, AllianceGameObjectID, Unknown, Type, Level, NameAlliance, NameHorde, Description, " + "Tooltip, BuildDuration, CostCurrencyID, CostCurrencyAmount, HordeTexPrefixKitID, AllianceTexPrefixKitID, IconFileDataID, BonusAmount, Flags, " + "AllianceActivationScenePackageID, HordeActivationScenePackageID, MaxShipments, FollowerRequiredGarrAbilityID, FollowerGarrAbilityEffectID, CostMoney " + "FROM garr_building ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_BUILDING, "SELECT ID, NameAlliance_lang, NameHorde_lang, Description_lang, Tooltip_lang " + "FROM garr_building_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrBuildingPlotInst.db2 + PrepareStatement(HOTFIX_SEL_GARR_BUILDING_PLOT_INST, "SELECT ID, GarrBuildingID, UiTextureAtlasMemberID, GarrSiteLevelPlotInstID, " + "LandmarkOffsetX, LandmarkOffsetY FROM garr_building_plot_inst ORDER BY ID DESC", CONNECTION_SYNCH); + + // GarrPlot.db2 + PrepareStatement(HOTFIX_SEL_GARR_PLOT, "SELECT ID, GarrPlotUICategoryID, PlotType, Flags, Name, MinCount, MaxCount, " + "AllianceConstructionGameObjectID, HordeConstructionGameObjectID FROM garr_plot ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_PLOT, "SELECT ID, Name_lang FROM garr_plot_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrPlotBuilding.db2 + PrepareStatement(HOTFIX_SEL_GARR_PLOT_BUILDING, "SELECT ID, GarrPlotID, GarrBuildingID FROM garr_plot_building ORDER BY ID DESC", CONNECTION_SYNCH); + + // GarrPlotInstance.db2 + PrepareStatement(HOTFIX_SEL_GARR_PLOT_INSTANCE, "SELECT ID, GarrPlotID, Name FROM garr_plot_instance ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_PLOT_INSTANCE, "SELECT ID, Name_lang FROM garr_plot_instance_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrSiteLevel.db2 + PrepareStatement(HOTFIX_SEL_GARR_SITE_LEVEL, "SELECT ID, Level, MapID, SiteID, UITextureKitID, TownHallX, TownHallY, MovieID, Level2, " + "UpgradeResourceCost, UpgradeMoneyCost FROM garr_site_level ORDER BY ID DESC", CONNECTION_SYNCH); + + // GarrSiteLevelPlotInst.db2 + PrepareStatement(HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST, "SELECT ID, GarrSiteLevelID, GarrPlotInstanceID, LandmarkX, LandmarkY, " + "Unknown FROM garr_site_level_plot_inst ORDER BY ID DESC", CONNECTION_SYNCH); + // Holidays.db2 PrepareStatement(HOTFIX_SEL_HOLIDAYS, "SELECT ID, Duration1, Duration2, Duration3, Duration4, Duration5, Duration6, Duration7, Duration8, Duration9, Duration10, " "Date1, Date2, Date3, Date4, Date5, Date6, Date7, Date8, Date9, Date10, Date11, Date12, Date13, Date14, Date15, Date16, Region, Looping, " diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.h b/src/server/shared/Database/Implementation/HotfixDatabase.h index 3d8e528cd98..5d5f00dbf9e 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.h +++ b/src/server/shared/Database/Implementation/HotfixDatabase.h @@ -54,6 +54,26 @@ enum HotfixDatabaseStatements HOTFIX_SEL_CURVE_POINT, + HOTFIX_SEL_GAMEOBJECTS, + HOTFIX_SEL_GAMEOBJECTS_LOCALE, + + HOTFIX_SEL_GARR_BUILDING, + HOTFIX_SEL_GARR_BUILDING_LOCALE, + + HOTFIX_SEL_GARR_BUILDING_PLOT_INST, + + HOTFIX_SEL_GARR_PLOT, + HOTFIX_SEL_GARR_PLOT_LOCALE, + + HOTFIX_SEL_GARR_PLOT_BUILDING, + + HOTFIX_SEL_GARR_PLOT_INSTANCE, + HOTFIX_SEL_GARR_PLOT_INSTANCE_LOCALE, + + HOTFIX_SEL_GARR_SITE_LEVEL, + + HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST, + HOTFIX_SEL_HOLIDAYS, HOTFIX_SEL_HOLIDAYS_LOCALE, @@ -86,7 +106,7 @@ enum HotfixDatabaseStatements HOTFIX_SEL_OVERRIDE_SPELL_DATA, HOTFIX_SEL_PHASE_GROUP, - + HOTFIX_SEL_QUEST_PACKAGE_ITEM, HOTFIX_SEL_SOUND_ENTRIES, |