mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Garrisons: Initial work on garrison followers
This commit is contained in:
205
sql/updates/hotfixes/2015_05_17_00_hotfixes.sql
Normal file
205
sql/updates/hotfixes/2015_05_17_00_hotfixes.sql
Normal file
@@ -0,0 +1,205 @@
|
||||
--
|
||||
-- Table structure for table `garr_ability`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `garr_ability`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `garr_ability` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Flags` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Name` text,
|
||||
`Description` text,
|
||||
`IconFileDataID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`OtherFactionGarrAbilityID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`GarrAbilityCategoryID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `garr_ability`
|
||||
--
|
||||
|
||||
LOCK TABLES `garr_ability` WRITE;
|
||||
/*!40000 ALTER TABLE `garr_ability` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `garr_ability` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `garr_ability_locale`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `garr_ability_locale`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `garr_ability_locale` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`locale` varchar(4) NOT NULL,
|
||||
`Name_lang` text,
|
||||
`Description_lang` text,
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`,`locale`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `garr_ability_locale`
|
||||
--
|
||||
|
||||
LOCK TABLES `garr_ability_locale` WRITE;
|
||||
/*!40000 ALTER TABLE `garr_ability_locale` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `garr_ability_locale` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `garr_class_spec`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `garr_class_spec`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `garr_class_spec` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`NameMale` text,
|
||||
`NameFemale` text,
|
||||
`NameGenderless` text,
|
||||
`ClassAtlasID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`GarrFollItemSetID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `garr_class_spec`
|
||||
--
|
||||
|
||||
LOCK TABLES `garr_class_spec` WRITE;
|
||||
/*!40000 ALTER TABLE `garr_class_spec` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `garr_class_spec` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `garr_class_spec_locale`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `garr_class_spec_locale`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `garr_class_spec_locale` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`locale` varchar(4) NOT NULL,
|
||||
`NameMale_lang` text,
|
||||
`NameFemale_lang` text,
|
||||
`NameGenderless_lang` text,
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`,`locale`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `garr_class_spec_locale`
|
||||
--
|
||||
|
||||
LOCK TABLES `garr_class_spec_locale` WRITE;
|
||||
/*!40000 ALTER TABLE `garr_class_spec_locale` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `garr_class_spec_locale` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `garr_follower`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `garr_follower`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `garr_follower` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`HordeCreatureID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AllianceCreatureID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`HordeUiAnimRaceInfoID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AllianceUiAnimRaceInfoID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Quality` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`HordeGarrClassSpecID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AllianceGarrClassSpecID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`HordeGarrFollItemSetID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AllianceGarrFollItemSetID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Level` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemLevelWeapon` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemLevelArmor` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Unknown1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Flags` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`HordeSourceText` text,
|
||||
`AllianceSourceText` text,
|
||||
`Unknown2` int(11) NOT NULL DEFAULT '0',
|
||||
`Unknown3` int(11) NOT NULL DEFAULT '0',
|
||||
`HordePortraitIconID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AlliancePortraitIconID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `garr_follower`
|
||||
--
|
||||
|
||||
LOCK TABLES `garr_follower` WRITE;
|
||||
/*!40000 ALTER TABLE `garr_follower` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `garr_follower` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `garr_follower_locale`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `garr_follower_locale`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `garr_follower_locale` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`locale` varchar(4) NOT NULL,
|
||||
`HordeSourceText_lang` text,
|
||||
`AllianceSourceText_lang` text,
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`,`locale`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `garr_follower_locale`
|
||||
--
|
||||
|
||||
LOCK TABLES `garr_follower_locale` WRITE;
|
||||
/*!40000 ALTER TABLE `garr_follower_locale` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `garr_follower_locale` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `garr_follower_x_ability`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `garr_follower_x_ability`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `garr_follower_x_ability` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`GarrFollowerID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`GarrAbilityID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`FactionIndex` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `garr_follower_x_ability`
|
||||
--
|
||||
|
||||
LOCK TABLES `garr_follower_x_ability` WRITE;
|
||||
/*!40000 ALTER TABLE `garr_follower_x_ability` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `garr_follower_x_ability` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
@@ -29,8 +29,12 @@ DB2Storage<BroadcastTextEntry> sBroadcastTextStore("BroadcastText.d
|
||||
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<GarrAbilityEntry> sGarrAbilityStore("GarrAbility.db2", GarrAbilityFormat, HOTFIX_SEL_GARR_ABILITY);
|
||||
DB2Storage<GarrBuildingEntry> sGarrBuildingStore("GarrBuilding.db2", GarrBuildingFormat, HOTFIX_SEL_GARR_BUILDING);
|
||||
DB2Storage<GarrBuildingPlotInstEntry> sGarrBuildingPlotInstStore("GarrBuildingPlotInst.db2", GarrBuildingPlotInstFormat, HOTFIX_SEL_GARR_BUILDING_PLOT_INST);
|
||||
DB2Storage<GarrClassSpecEntry> sGarrClassSpecStore("GarrClassSpec.db2", GarrClassSpecFormat, HOTFIX_SEL_GARR_CLASS_SPEC);
|
||||
DB2Storage<GarrFollowerEntry> sGarrFollowerStore("GarrFollower.db2", GarrFollowerFormat, HOTFIX_SEL_GARR_FOLLOWER);
|
||||
DB2Storage<GarrFollowerXAbilityEntry> sGarrFollowerXAbilityStore("GarrFollowerXAbility.db2", GarrFollowerXAbilityFormat, HOTFIX_SEL_GARR_FOLLOWER_X_ABILITY);
|
||||
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);
|
||||
@@ -141,8 +145,12 @@ void DB2Manager::LoadStores(std::string const& dataPath)
|
||||
LOAD_DB2(sCurrencyTypesStore);
|
||||
LOAD_DB2(sCurvePointStore);
|
||||
LOAD_DB2(sGameObjectsStore);
|
||||
LOAD_DB2(sGarrBuildingPlotInstStore);
|
||||
LOAD_DB2(sGarrAbilityStore);
|
||||
LOAD_DB2(sGarrBuildingStore);
|
||||
LOAD_DB2(sGarrBuildingPlotInstStore);
|
||||
LOAD_DB2(sGarrClassSpecStore);
|
||||
LOAD_DB2(sGarrFollowerStore);
|
||||
LOAD_DB2(sGarrFollowerXAbilityStore);
|
||||
LOAD_DB2(sGarrPlotBuildingStore);
|
||||
LOAD_DB2(sGarrPlotInstanceStore);
|
||||
LOAD_DB2(sGarrPlotStore);
|
||||
|
||||
@@ -25,8 +25,12 @@
|
||||
extern DB2Storage<BroadcastTextEntry> sBroadcastTextStore;
|
||||
extern DB2Storage<CurrencyTypesEntry> sCurrencyTypesStore;
|
||||
extern DB2Storage<GameObjectsEntry> sGameObjectsStore;
|
||||
extern DB2Storage<GarrAbilityEntry> sGarrAbilityStore;
|
||||
extern DB2Storage<GarrBuildingEntry> sGarrBuildingStore;
|
||||
extern DB2Storage<GarrBuildingPlotInstEntry> sGarrBuildingPlotInstStore;
|
||||
extern DB2Storage<GarrClassSpecEntry> sGarrClassSpecStore;
|
||||
extern DB2Storage<GarrFollowerEntry> sGarrFollowerStore;
|
||||
extern DB2Storage<GarrFollowerXAbilityEntry> sGarrFollowerXAbilityStore;
|
||||
extern DB2Storage<GarrPlotBuildingEntry> sGarrPlotBuildingStore;
|
||||
extern DB2Storage<GarrPlotEntry> sGarrPlotStore;
|
||||
extern DB2Storage<GarrPlotInstanceEntry> sGarrPlotInstanceStore;
|
||||
|
||||
@@ -100,6 +100,17 @@ struct GameObjectsEntry
|
||||
LocalizedString* Name; // 23
|
||||
};
|
||||
|
||||
struct GarrAbilityEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 Flags; // 1
|
||||
LocalizedString* Name; // 2
|
||||
LocalizedString* Description; // 3
|
||||
uint32 IconFileDataID; // 4
|
||||
uint32 OtherFactionGarrAbilityID; // 5
|
||||
uint32 GarrAbilityCategoryID; // 6
|
||||
};
|
||||
|
||||
struct GarrBuildingEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
@@ -137,6 +148,49 @@ struct GarrBuildingPlotInstEntry
|
||||
DBCPosition2D LandmarkOffset; // 4-5
|
||||
};
|
||||
|
||||
struct GarrClassSpecEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
LocalizedString* NameMale; // 1
|
||||
LocalizedString* NameFemale; // 2
|
||||
LocalizedString* NameGenderless; // 3
|
||||
uint32 ClassAtlasID; // 4 UiTextureAtlasMember.db2 ref
|
||||
uint32 GarrFollItemSetID; // 5
|
||||
};
|
||||
|
||||
struct GarrFollowerEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 HordeCreatureID; // 1
|
||||
uint32 AllianceCreatureID; // 2
|
||||
uint32 HordeUiAnimRaceInfoID; // 3
|
||||
uint32 AllianceUiAnimRaceInfoID; // 4
|
||||
uint32 Quality; // 5
|
||||
uint32 HordeGarrClassSpecID; // 6
|
||||
uint32 AllianceGarrClassSpecID; // 7
|
||||
uint32 HordeGarrFollItemSetID; // 8
|
||||
uint32 AllianceGarrFollItemSetID; // 9
|
||||
uint32 Level; // 10
|
||||
uint32 ItemLevelWeapon; // 11
|
||||
uint32 ItemLevelArmor; // 12
|
||||
uint32 Unknown1; // 13
|
||||
uint32 Flags; // 14
|
||||
LocalizedString* HordeSourceText; // 15
|
||||
LocalizedString* AllianceSourceText; // 16
|
||||
int32 Unknown2; // 17
|
||||
int32 Unknown3; // 18
|
||||
uint32 HordePortraitIconID; // 19
|
||||
uint32 AlliancePortraitIconID; // 20
|
||||
};
|
||||
|
||||
struct GarrFollowerXAbilityEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 GarrFollowerID; // 1
|
||||
uint32 GarrAbilityID; // 2
|
||||
uint32 FactionIndex; // 3
|
||||
};
|
||||
|
||||
struct GarrPlotEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
|
||||
@@ -24,10 +24,14 @@ char const BroadcastTextFormat[] = "nissiiiiiiiii";
|
||||
char const CurrencyTypesFormat[] = "nisssiiiiiis";
|
||||
char const CurvePointFormat[] = "niiff";
|
||||
char const GameObjectsFormat[] = "niiffffffffiiiiiiiiiiiis";
|
||||
char const GarrAbilityFormat[] = "nissiii";
|
||||
char const GarrBuildingFormat[] = "niiiiissssiiiiiiiiiiiiii";
|
||||
char const GarrPlotFormat[] = "niiisiiii";
|
||||
char const GarrPlotBuildingFormat[] = "nii";
|
||||
char const GarrBuildingPlotInstFormat[] = "niiiff";
|
||||
char const GarrClassSpecFormat[] = "nsssii";
|
||||
char const GarrFollowerFormat[] = "niiiiiiiiiiiiiissiiii";
|
||||
char const GarrFollowerXAbilityFormat[] = "niii";
|
||||
char const GarrPlotBuildingFormat[] = "nii";
|
||||
char const GarrPlotFormat[] = "niiisiiii";
|
||||
char const GarrPlotInstanceFormat[] = "nis";
|
||||
char const GarrSiteLevelFormat[] = "niiiiffiiii";
|
||||
char const GarrSiteLevelPlotInstFormat[] = "niiffi";
|
||||
|
||||
@@ -344,6 +344,34 @@ void Garrison::CancelBuildingConstruction(uint32 garrPlotInstanceId)
|
||||
_owner->SendDirectMessage(buildingRemoved.Write());
|
||||
}
|
||||
|
||||
void Garrison::AddFollower(uint32 garrFollowerId)
|
||||
{
|
||||
WorldPackets::Garrison::GarrisonAddFollowerResult addFollowerResult;
|
||||
GarrFollowerEntry const* followerEntry = sGarrFollowerStore.LookupEntry(garrFollowerId);
|
||||
if (_followers.count(garrFollowerId) || !followerEntry)
|
||||
{
|
||||
addFollowerResult.Result = GARRISON_GENERIC_UNKNOWN_ERROR;
|
||||
_owner->SendDirectMessage(addFollowerResult.Write());
|
||||
return;
|
||||
}
|
||||
|
||||
Follower& follower = _followers[garrFollowerId];
|
||||
follower.PacketInfo.DbID = sGarrisonMgr.GenerateFollowerDbId();
|
||||
follower.PacketInfo.GarrFollowerID = garrFollowerId;
|
||||
follower.PacketInfo.Quality = followerEntry->Quality; // TODO: handle magic upgrades
|
||||
follower.PacketInfo.FollowerLevel = followerEntry->Level;
|
||||
follower.PacketInfo.ItemLevelWeapon = followerEntry->ItemLevelWeapon;
|
||||
follower.PacketInfo.ItemLevelArmor = followerEntry->ItemLevelArmor;
|
||||
follower.PacketInfo.Xp = 0;
|
||||
follower.PacketInfo.CurrentBuildingID = 0;
|
||||
follower.PacketInfo.CurrentMissionID = 0;
|
||||
follower.PacketInfo.AbilityID = sGarrisonMgr.RollFollowerAbilities(followerEntry, follower.PacketInfo.Quality, GetFaction(), true);
|
||||
follower.PacketInfo.FollowerStatus = 0;
|
||||
|
||||
addFollowerResult.Follower = follower.PacketInfo;
|
||||
_owner->SendDirectMessage(addFollowerResult.Write());
|
||||
}
|
||||
|
||||
void Garrison::SendInfo()
|
||||
{
|
||||
WorldPackets::Garrison::GetGarrisonInfoResult garrisonInfo;
|
||||
@@ -359,6 +387,9 @@ void Garrison::SendInfo()
|
||||
garrisonInfo.Buildings.push_back(plot.BuildingInfo.PacketInfo.get_ptr());
|
||||
}
|
||||
|
||||
for (auto const& p : _followers)
|
||||
garrisonInfo.Followers.push_back(&p.second.PacketInfo);
|
||||
|
||||
_owner->SendDirectMessage(garrisonInfo.Write());
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,20 @@ enum GarrisonBuildingFlags
|
||||
GARRISON_BUILDING_FLAG_NEEDS_PLAN = 0x1
|
||||
};
|
||||
|
||||
enum GarrisonFollowerFlags
|
||||
{
|
||||
GARRISON_FOLLOWER_FLAG_UNIQUE = 0x1
|
||||
};
|
||||
|
||||
enum GarrisonAbilityFlags
|
||||
{
|
||||
GARRISON_ABILITY_FLAG_TRAIT = 0x01,
|
||||
GARRISON_ABILITY_CANNOT_ROLL = 0x02,
|
||||
GARRISON_ABILITY_HORDE_ONLY = 0x04,
|
||||
GARRISON_ABILITY_ALLIANCE_ONLY = 0x08,
|
||||
GARRISON_ABILITY_FLAG_CANNOT_REMOVE = 0x10
|
||||
};
|
||||
|
||||
enum GarrisonError
|
||||
{
|
||||
GARRISON_SUCCESS = 0,
|
||||
@@ -44,7 +58,9 @@ enum GarrisonError
|
||||
GARRISON_ERROR_BLUEPRINT_NOT_KNOWN = 22,
|
||||
GARRISON_ERROR_BUILDING_EXISTS = 24,
|
||||
GARRISON_ERROR_NOT_ENOUGH_CURRENCY = 46,
|
||||
GARRISON_ERROR_NOT_ENOUGH_GOLD = 47
|
||||
GARRISON_ERROR_NOT_ENOUGH_GOLD = 47,
|
||||
|
||||
GARRISON_GENERIC_UNKNOWN_ERROR = 255 // custom value for packets whose handlers only check if error != 0
|
||||
};
|
||||
|
||||
enum GarrisonFollowerStatus
|
||||
@@ -81,6 +97,11 @@ public:
|
||||
Building BuildingInfo;
|
||||
};
|
||||
|
||||
struct Follower
|
||||
{
|
||||
WorldPackets::Garrison::GarrisonFollower PacketInfo;
|
||||
};
|
||||
|
||||
explicit Garrison(Player* owner);
|
||||
|
||||
bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings);
|
||||
@@ -93,15 +114,21 @@ public:
|
||||
void Leave() const;
|
||||
|
||||
GarrisonFactionIndex GetFaction() const;
|
||||
|
||||
// Plots
|
||||
std::vector<Plot*> GetPlots();
|
||||
Plot* GetPlot(uint32 garrPlotInstanceId);
|
||||
Plot const* GetPlot(uint32 garrPlotInstanceId) const;
|
||||
|
||||
// Buildings
|
||||
void LearnBlueprint(uint32 garrBuildingId);
|
||||
void UnlearnBlueprint(uint32 garrBuildingId);
|
||||
void PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId);
|
||||
void CancelBuildingConstruction(uint32 garrPlotInstanceId);
|
||||
|
||||
// Followers
|
||||
void AddFollower(uint32 garrFollowerId);
|
||||
|
||||
void SendInfo();
|
||||
void SendRemoteInfo() const;
|
||||
void SendBlueprintAndSpecializationData();
|
||||
@@ -120,6 +147,7 @@ private:
|
||||
|
||||
std::unordered_map<uint32 /*garrPlotInstanceId*/, Plot> _plots;
|
||||
std::unordered_set<uint32 /*garrBuildingId*/> _knownBuildings;
|
||||
std::unordered_map<uint64 /*dbId*/, Follower> _followers;
|
||||
};
|
||||
|
||||
#endif // Garrison_h__
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
*/
|
||||
|
||||
#include "GarrisonMgr.h"
|
||||
#include "Containers.h"
|
||||
#include "Garrison.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "World.h"
|
||||
|
||||
void GarrisonMgr::Initialize()
|
||||
{
|
||||
@@ -35,6 +38,23 @@ void GarrisonMgr::Initialize()
|
||||
|
||||
for (GarrBuildingEntry const* building : sGarrBuildingStore)
|
||||
_garrisonBuildingsByType[building->Type].push_back(building);
|
||||
|
||||
for (GarrFollowerXAbilityEntry const* followerAbility : sGarrFollowerXAbilityStore)
|
||||
{
|
||||
if (GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(followerAbility->GarrAbilityID))
|
||||
{
|
||||
if (!(ability->Flags & GARRISON_ABILITY_CANNOT_ROLL) && ability->Flags & GARRISON_ABILITY_FLAG_TRAIT)
|
||||
_garrisonFollowerRandomTraits.insert(ability);
|
||||
|
||||
if (followerAbility->FactionIndex < 2)
|
||||
{
|
||||
if (ability->Flags & GARRISON_ABILITY_FLAG_TRAIT)
|
||||
_garrisonFollowerAbilities[followerAbility->FactionIndex][followerAbility->GarrFollowerID].Traits.insert(ability);
|
||||
else
|
||||
_garrisonFollowerAbilities[followerAbility->FactionIndex][followerAbility->GarrFollowerID].Counters.insert(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GarrSiteLevelEntry const* GarrisonMgr::GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const
|
||||
@@ -96,3 +116,116 @@ GarrBuildingEntry const* GarrisonMgr::GetPreviousLevelBuilding(uint32 buildingTy
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint64 GarrisonMgr::GenerateFollowerDbId()
|
||||
{
|
||||
if (_followerDbIdGenerator >= std::numeric_limits<uint64>::max())
|
||||
{
|
||||
TC_LOG_ERROR("misc", "Garrison follower db id oberflow! Can't continue, shutting down server. ");
|
||||
World::StopNow(ERROR_EXIT_CODE);
|
||||
}
|
||||
|
||||
return _followerDbIdGenerator++;
|
||||
}
|
||||
|
||||
uint32 const AbilitiesForQuality[][2] =
|
||||
{
|
||||
// Counters, Traits
|
||||
{ 0, 0 },
|
||||
{ 1, 0 },
|
||||
{ 1, 1 }, // Uncommon
|
||||
{ 1, 2 }, // Rare
|
||||
{ 2, 3 }, // Epic
|
||||
{ 2, 3 } // Legendary
|
||||
};
|
||||
|
||||
std::list<uint32> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const
|
||||
{
|
||||
ASSERT(faction < 2);
|
||||
|
||||
std::list<uint32> result;
|
||||
int32 slots[2] = { AbilitiesForQuality[quality][0], AbilitiesForQuality[quality][1] };
|
||||
|
||||
GarrAbilities const* abilities = nullptr;
|
||||
auto itr = _garrisonFollowerAbilities[faction].find(follower->ID);
|
||||
if (itr != _garrisonFollowerAbilities[faction].end())
|
||||
abilities = &itr->second;
|
||||
|
||||
std::list<uint32> abilityList, forcedAbilities, traitList, forcedTraits;
|
||||
if (abilities)
|
||||
{
|
||||
for (GarrAbilityEntry const* ability : abilities->Counters)
|
||||
{
|
||||
if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE)
|
||||
continue;
|
||||
else if (ability->Flags & GARRISON_ABILITY_ALLIANCE_ONLY && faction != GARRISON_FACTION_INDEX_ALLIANCE)
|
||||
continue;
|
||||
|
||||
if (ability->Flags & GARRISON_ABILITY_FLAG_CANNOT_REMOVE)
|
||||
forcedAbilities.push_back(ability->ID);
|
||||
else
|
||||
abilityList.push_back(ability->ID);
|
||||
}
|
||||
|
||||
for (GarrAbilityEntry const* ability : abilities->Traits)
|
||||
{
|
||||
if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE)
|
||||
continue;
|
||||
else if (ability->Flags & GARRISON_ABILITY_ALLIANCE_ONLY && faction != GARRISON_FACTION_INDEX_ALLIANCE)
|
||||
continue;
|
||||
|
||||
if (ability->Flags & GARRISON_ABILITY_FLAG_CANNOT_REMOVE)
|
||||
forcedTraits.push_back(ability->ID);
|
||||
else
|
||||
traitList.push_back(ability->ID);
|
||||
}
|
||||
}
|
||||
|
||||
Trinity::Containers::RandomResizeList(abilityList, std::max<int32>(0, slots[0] - forcedAbilities.size()));
|
||||
Trinity::Containers::RandomResizeList(traitList, std::max<int32>(0, slots[1] - forcedTraits.size()));
|
||||
|
||||
// Add counters specified in GarrFollowerXAbility.db2 before generic classspec ones on follower creation
|
||||
if (initial)
|
||||
{
|
||||
forcedAbilities.splice(forcedAbilities.end(), abilityList);
|
||||
forcedTraits.splice(forcedTraits.end(), traitList);
|
||||
}
|
||||
|
||||
if (slots[0] > forcedAbilities.size() + abilityList.size())
|
||||
{
|
||||
std::list<uint32> classSpecAbilities; // = GetDefaultClassSpecAbilities(follower, faction)
|
||||
|
||||
abilityList.splice(abilityList.end(), classSpecAbilities);
|
||||
abilityList.sort();
|
||||
abilityList.unique();
|
||||
|
||||
Trinity::Containers::RandomResizeList(abilityList, std::max<int32>(0, slots[0] - forcedAbilities.size()));
|
||||
}
|
||||
|
||||
if (slots[1] > forcedTraits.size() + traitList.size())
|
||||
{
|
||||
std::list<uint32> genericTraits;
|
||||
for (GarrAbilityEntry const* ability : _garrisonFollowerRandomTraits)
|
||||
{
|
||||
if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE)
|
||||
continue;
|
||||
else if (ability->Flags & GARRISON_ABILITY_ALLIANCE_ONLY && faction != GARRISON_FACTION_INDEX_ALLIANCE)
|
||||
continue;
|
||||
|
||||
genericTraits.push_back(ability->ID);
|
||||
}
|
||||
|
||||
traitList.splice(traitList.end(), genericTraits);
|
||||
traitList.sort();
|
||||
traitList.unique();
|
||||
|
||||
Trinity::Containers::RandomResizeList(traitList, std::max<int32>(0, slots[1] - forcedTraits.size()));
|
||||
}
|
||||
|
||||
result.splice(result.end(), forcedAbilities);
|
||||
result.splice(result.end(), abilityList);
|
||||
result.splice(result.end(), forcedTraits);
|
||||
result.splice(result.end(), traitList);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -18,9 +18,14 @@
|
||||
#ifndef GarrisonMgr_h__
|
||||
#define GarrisonMgr_h__
|
||||
|
||||
#include "DB2Stores.h"
|
||||
#include <unordered_set>
|
||||
|
||||
#include "DB2Stores.h"
|
||||
struct GarrAbilities
|
||||
{
|
||||
std::unordered_set<GarrAbilityEntry const*> Counters;
|
||||
std::unordered_set<GarrAbilityEntry const*> Traits;
|
||||
};
|
||||
|
||||
class GarrisonMgr
|
||||
{
|
||||
@@ -39,6 +44,8 @@ public:
|
||||
bool IsPlotMatchingBuilding(uint32 garrPlotId, uint32 garrBuildingId) const;
|
||||
uint32 GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSiteLevelPlotInstId) const;
|
||||
GarrBuildingEntry const* GetPreviousLevelBuilding(uint32 buildingType, uint32 currentLevel) const;
|
||||
uint64 GenerateFollowerDbId();
|
||||
std::list<uint32> RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32 /*garrSiteId*/, std::vector<GarrSiteLevelPlotInstEntry const*>> _garrisonPlotInstBySiteLevel;
|
||||
@@ -46,6 +53,10 @@ private:
|
||||
std::unordered_map<uint32 /*garrPlotId*/, std::unordered_set<uint32/*garrBuildingId*/>> _garrisonBuildingsByPlot;
|
||||
std::unordered_map<uint64 /*garrBuildingId | garrSiteLevelPlotInstId << 32*/, uint32 /*garrBuildingPlotInstId*/> _garrisonBuildingPlotInstances;
|
||||
std::unordered_map<uint32 /*buildingType*/, std::vector<GarrBuildingEntry const*>> _garrisonBuildingsByType;
|
||||
std::unordered_map<uint32 /*garrFollowerId*/, GarrAbilities> _garrisonFollowerAbilities[2];
|
||||
std::unordered_set<GarrAbilityEntry const*> _garrisonFollowerRandomTraits;
|
||||
|
||||
uint64 _followerDbIdGenerator;
|
||||
};
|
||||
|
||||
#define sGarrisonMgr GarrisonMgr::Instance()
|
||||
|
||||
@@ -60,8 +60,8 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonFollowe
|
||||
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());
|
||||
for (uint32 abilityId : follower.AbilityID)
|
||||
data << uint32(abilityId);
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -237,3 +237,11 @@ WorldPacket const* WorldPackets::Garrison::GarrisonPlotRemoved::Write()
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Garrison::GarrisonAddFollowerResult::Write()
|
||||
{
|
||||
_worldPacket << uint32(Result);
|
||||
_worldPacket << Follower;
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace WorldPackets
|
||||
uint32 Xp = 0;
|
||||
uint32 CurrentBuildingID = 0;
|
||||
uint32 CurrentMissionID = 0;
|
||||
std::vector<uint32> AbilityID;
|
||||
std::list<uint32> AbilityID;
|
||||
uint32 FollowerStatus;
|
||||
};
|
||||
|
||||
@@ -102,9 +102,9 @@ namespace WorldPackets
|
||||
uint32 FactionIndex = 0;
|
||||
uint32 NumFollowerActivationsRemaining = 0;
|
||||
std::vector<GarrisonPlotInfo*> Plots;
|
||||
std::vector<GarrisonBuildingInfo*> Buildings;
|
||||
std::vector<GarrisonFollower*> Followers;
|
||||
std::vector<GarrisonMission*> Missions;
|
||||
std::vector<GarrisonBuildingInfo const*> Buildings;
|
||||
std::vector<GarrisonFollower const*> Followers;
|
||||
std::vector<GarrisonMission const*> Missions;
|
||||
std::vector<int32> ArchivedMissions;
|
||||
};
|
||||
|
||||
@@ -267,6 +267,17 @@ namespace WorldPackets
|
||||
|
||||
uint32 GarrPlotInstanceID = 0;
|
||||
};
|
||||
|
||||
class GarrisonAddFollowerResult final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
GarrisonAddFollowerResult() : ServerPacket(SMSG_GARRISON_ADD_FOLLOWER_RESULT, 8 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 5 * 4 + 4) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
GarrisonFollower Follower;
|
||||
uint32 Result = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1109,7 +1109,7 @@ 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_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_FOLLOWER_RESULT, STATUS_NEVER, 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);
|
||||
|
||||
@@ -407,6 +407,7 @@ class Spell
|
||||
void EffectDestroyItem(SpellEffIndex effIndex);
|
||||
void EffectLearnGarrisonBuilding(SpellEffIndex effIndex);
|
||||
void EffectCreateGarrison(SpellEffIndex effIndex);
|
||||
void EffectAddGarrisonFollower(SpellEffIndex effIndex);
|
||||
|
||||
typedef std::set<Aura*> UsedSpellMods;
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
|
||||
&Spell::EffectNULL, //217 SPELL_EFFECT_UPGRADE_GARRISON
|
||||
&Spell::EffectNULL, //218 SPELL_EFFECT_218
|
||||
&Spell::EffectNULL, //219 SPELL_EFFECT_219
|
||||
&Spell::EffectNULL, //220 SPELL_EFFECT_ADD_GARRISON_FOLLOWER
|
||||
&Spell::EffectAddGarrisonFollower, //220 SPELL_EFFECT_ADD_GARRISON_FOLLOWER
|
||||
&Spell::EffectNULL, //221 SPELL_EFFECT_221
|
||||
&Spell::EffectNULL, //222 SPELL_EFFECT_CREATE_HEIRLOOM_ITEM
|
||||
&Spell::EffectNULL, //223 SPELL_EFFECT_CHANGE_ITEM_BONUSES
|
||||
@@ -5826,3 +5826,15 @@ void Spell::EffectCreateGarrison(SpellEffIndex effIndex)
|
||||
|
||||
unitTarget->ToPlayer()->CreateGarrison(GetEffect(effIndex)->MiscValue);
|
||||
}
|
||||
|
||||
void Spell::EffectAddGarrisonFollower(SpellEffIndex effIndex)
|
||||
{
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
|
||||
return;
|
||||
|
||||
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
if (Garrison* garrison = unitTarget->ToPlayer()->GetGarrison())
|
||||
garrison->AddFollower(GetEffect(effIndex)->MiscValue);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ void HotfixDatabaseConnection::DoPrepareStatements()
|
||||
"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);
|
||||
|
||||
// GarrAbility.db2
|
||||
PrepareStatement(HOTFIX_SEL_GARR_ABILITY, "SELECT ID, Flags, Name, Description, IconFileDataID, OtherFactionGarrAbilityID, "
|
||||
"GarrAbilityCategoryID FROM garr_ability ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_ABILITY, "SELECT ID, Name_lang, Description_lang FROM garr_ability_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, "
|
||||
@@ -64,6 +69,20 @@ void HotfixDatabaseConnection::DoPrepareStatements()
|
||||
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);
|
||||
|
||||
// GarrClassSpec.db2
|
||||
PrepareStatement(HOTFIX_SEL_GARR_CLASS_SPEC, "SELECT ID, NameMale, NameFemale, NameGenderless, ClassAtlasID, GarrFollItemSetID "
|
||||
"FROM garr_class_spec ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_CLASS_SPEC, "SELECT ID, NameMale_lang, NameFemale_lang, NameGenderless_lang FROM garr_class_spec_locale WHERE locale = ?", CONNECTION_SYNCH);
|
||||
|
||||
// GarrFollower.db2
|
||||
PrepareStatement(HOTFIX_SEL_GARR_FOLLOWER, "SELECT ID, HordeCreatureID, AllianceCreatureID, HordeUiAnimRaceInfoID, AllianceUiAnimRaceInfoID, Quality, "
|
||||
"HordeGarrClassSpecID, AllianceGarrClassSpecID, HordeGarrFollItemSetID, AllianceGarrFollItemSetID, Level, ItemLevelWeapon, ItemLevelArmor, Unknown1, Flags, "
|
||||
"HordeSourceText, AllianceSourceText, Unknown2, Unknown3, HordePortraitIconID, AlliancePortraitIconID FROM garr_follower ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_FOLLOWER, "SELECT ID, HordeSourceText_lang, AllianceSourceText_lang FROM garr_follower_locale WHERE locale = ?", CONNECTION_SYNCH);
|
||||
|
||||
// GarrFollowerXAbility.db2
|
||||
PrepareStatement(HOTFIX_SEL_GARR_FOLLOWER_X_ABILITY, "SELECT ID, GarrFollowerID, GarrAbilityID, FactionIndex FROM garr_follower_x_ability 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);
|
||||
|
||||
@@ -57,11 +57,22 @@ enum HotfixDatabaseStatements
|
||||
HOTFIX_SEL_GAMEOBJECTS,
|
||||
HOTFIX_SEL_GAMEOBJECTS_LOCALE,
|
||||
|
||||
HOTFIX_SEL_GARR_ABILITY,
|
||||
HOTFIX_SEL_GARR_ABILITY_LOCALE,
|
||||
|
||||
HOTFIX_SEL_GARR_BUILDING,
|
||||
HOTFIX_SEL_GARR_BUILDING_LOCALE,
|
||||
|
||||
HOTFIX_SEL_GARR_BUILDING_PLOT_INST,
|
||||
|
||||
HOTFIX_SEL_GARR_CLASS_SPEC,
|
||||
HOTFIX_SEL_GARR_CLASS_SPEC_LOCALE,
|
||||
|
||||
HOTFIX_SEL_GARR_FOLLOWER,
|
||||
HOTFIX_SEL_GARR_FOLLOWER_LOCALE,
|
||||
|
||||
HOTFIX_SEL_GARR_FOLLOWER_X_ABILITY,
|
||||
|
||||
HOTFIX_SEL_GARR_PLOT,
|
||||
HOTFIX_SEL_GARR_PLOT_LOCALE,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user