aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2015-05-08 00:03:15 +0200
committerShauren <shauren.trinity@gmail.com>2015-05-08 00:03:15 +0200
commit5b725db033c656bda5e718ea05a79005946e089e (patch)
treec15ad544c542cdd7dd7cb395c8ec6d3d35e4d2e9 /src
parent0972552e84068cf453231b372bcb232cf2d2f42b (diff)
Core/Garrisons: Basics for garrisons
Diffstat (limited to 'src')
-rw-r--r--src/server/game/CMakeLists.txt5
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp92
-rw-r--r--src/server/game/DataStores/DB2Stores.h10
-rw-r--r--src/server/game/DataStores/DB2Structure.h106
-rw-r--r--src/server/game/DataStores/DB2fmt.h8
-rw-r--r--src/server/game/DataStores/DBCEnums.h1
-rw-r--r--src/server/game/DataStores/DBCStructure.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp36
-rw-r--r--src/server/game/Entities/Player/Player.h11
-rw-r--r--src/server/game/Garrison/Garrison.cpp420
-rw-r--r--src/server/game/Garrison/Garrison.h117
-rw-r--r--src/server/game/Garrison/GarrisonMap.cpp125
-rw-r--r--src/server/game/Garrison/GarrisonMap.h39
-rw-r--r--src/server/game/Garrison/GarrisonMgr.cpp83
-rw-r--r--src/server/game/Garrison/GarrisonMgr.h49
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp16
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp12
-rw-r--r--src/server/game/Handlers/GarrisonHandler.cpp47
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp5
-rw-r--r--src/server/game/Maps/Map.cpp9
-rw-r--r--src/server/game/Maps/Map.h2
-rw-r--r--src/server/game/Maps/MapInstanced.cpp21
-rw-r--r--src/server/game/Maps/MapInstanced.h3
-rw-r--r--src/server/game/Server/Packets/GarrisonPackets.cpp210
-rw-r--r--src/server/game/Server/Packets/GarrisonPackets.h230
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp95
-rw-r--r--src/server/game/Server/WorldSession.h14
-rw-r--r--src/server/game/Spells/Spell.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp28
-rw-r--r--src/server/game/World/World.cpp14
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/shared/DataStores/DB2Store.h2
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp12
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h11
-rw-r--r--src/server/shared/Database/Implementation/HotfixDatabase.cpp43
-rw-r--r--src/server/shared/Database/Implementation/HotfixDatabase.h22
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,