aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2015-05-22 00:17:48 +0200
committerShauren <shauren.trinity@gmail.com>2015-05-22 00:17:48 +0200
commitb3a754cd7bef73c4f29a3fa819d2bac9f173685a (patch)
tree60d1978a3393adbafd9dfe86a7e5ab550306e480 /src
parent1d29328769d505caf4541b0d712972195dda8b70 (diff)
Core/Garrisons: Implemented follower class/spec abilities and saving them to database
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp11
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Garrison/Garrison.cpp90
-rw-r--r--src/server/game/Garrison/Garrison.h3
-rw-r--r--src/server/game/Garrison/GarrisonMgr.cpp100
-rw-r--r--src/server/game/Garrison/GarrisonMgr.h9
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp8
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp7
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h5
9 files changed, 218 insertions, 17 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 419992f3408..55ae58fe342 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -4590,6 +4590,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt64(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS);
+ stmt->setUInt64(0, guid);
+ trans->Append(stmt);
+
CharacterDatabase.CommitTransaction(trans);
sWorld->DeleteCharacterInfo(playerguid);
@@ -17344,8 +17348,6 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
_LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES));
- m_achievementMgr->CheckAllAchievementCriteria(this);
-
_LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS));
_LoadCUFProfiles(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES));
@@ -17353,9 +17355,12 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
std::unique_ptr<Garrison> garrison = Trinity::make_unique<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)))
+ holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS),
+ holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS),
+ holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES)))
_garrison = std::move(garrison);
+ m_achievementMgr->CheckAllAchievementCriteria(this);
return true;
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index c7af9426623..f17b304409e 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -987,6 +987,8 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOAD_GARRISON,
PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS,
PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS,
+ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS,
+ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES,
MAX_PLAYER_LOGIN_QUERY
};
diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp
index 3087de37472..8e27bbd930d 100644
--- a/src/server/game/Garrison/Garrison.cpp
+++ b/src/server/game/Garrison/Garrison.cpp
@@ -25,7 +25,8 @@ Garrison::Garrison(Player* owner) : _owner(owner), _siteLevel(nullptr), _followe
{
}
-bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings)
+bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings,
+ PreparedQueryResult followers, PreparedQueryResult abilities)
{
if (!garrison)
return false;
@@ -76,6 +77,60 @@ bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blue
} while (buildings->NextRow());
}
+ // 0 1 2 3 4 5 6 7 8 9
+ // SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ?
+ if (followers)
+ {
+ std::unordered_map<uint64, Follower*> followersByDbId;
+ do
+ {
+ Field* fields = followers->Fetch();
+
+ uint32 followerId = fields[1].GetUInt32();
+ if (!sGarrFollowerStore.LookupEntry(followerId))
+ continue;
+
+ Follower& follower = _followers[followerId];
+ follower.PacketInfo.DbID = fields[0].GetUInt64();
+ follower.PacketInfo.GarrFollowerID = followerId;
+ follower.PacketInfo.Quality = fields[2].GetUInt32();
+ follower.PacketInfo.FollowerLevel = fields[3].GetUInt32();
+ follower.PacketInfo.ItemLevelWeapon = fields[4].GetUInt32();
+ follower.PacketInfo.ItemLevelArmor = fields[5].GetUInt32();
+ follower.PacketInfo.Xp = fields[6].GetUInt32();
+ follower.PacketInfo.CurrentBuildingID = fields[7].GetUInt32();
+ follower.PacketInfo.CurrentMissionID = fields[8].GetUInt32();
+ follower.PacketInfo.FollowerStatus = fields[9].GetUInt32();
+ if (!sGarrBuildingStore.LookupEntry(follower.PacketInfo.CurrentBuildingID))
+ follower.PacketInfo.CurrentBuildingID = 0;
+
+ //if (!sGarrMissionStore.LookupEntry(follower.PacketInfo.CurrentMissionID))
+ // follower.PacketInfo.CurrentMissionID = 0;
+
+ followersByDbId[follower.PacketInfo.DbID] = &follower;
+
+ } while (followers->NextRow());
+
+ if (abilities)
+ {
+ do
+ {
+ Field* fields = abilities->Fetch();
+ uint64 dbId = fields[0].GetUInt64();
+ GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(fields[1].GetUInt32());
+
+ if (!ability)
+ continue;
+
+ auto itr = followersByDbId.find(dbId);
+ if (itr == followersByDbId.end())
+ continue;
+
+ itr->second->PacketInfo.AbilityID.push_back(ability);
+ } while (abilities->NextRow());
+ }
+ }
+
return true;
}
@@ -93,6 +148,10 @@ void Garrison::SaveToDB(SQLTransaction& trans)
stmt->setUInt64(0, _owner->GetGUID().GetCounter());
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS);
+ 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);
@@ -121,6 +180,35 @@ void Garrison::SaveToDB(SQLTransaction& trans)
trans->Append(stmt);
}
}
+
+ for (auto const& p : _followers)
+ {
+ Follower const& follower = p.second;
+ uint8 index = 0;
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS);
+ stmt->setUInt64(index++, follower.PacketInfo.DbID);
+ stmt->setUInt64(index++, _owner->GetGUID().GetCounter());
+ stmt->setUInt32(index++, follower.PacketInfo.GarrFollowerID);
+ stmt->setUInt32(index++, follower.PacketInfo.Quality);
+ stmt->setUInt32(index++, follower.PacketInfo.FollowerLevel);
+ stmt->setUInt32(index++, follower.PacketInfo.ItemLevelWeapon);
+ stmt->setUInt32(index++, follower.PacketInfo.ItemLevelArmor);
+ stmt->setUInt32(index++, follower.PacketInfo.Xp);
+ stmt->setUInt32(index++, follower.PacketInfo.CurrentBuildingID);
+ stmt->setUInt32(index++, follower.PacketInfo.CurrentMissionID);
+ stmt->setUInt32(index++, follower.PacketInfo.FollowerStatus);
+ trans->Append(stmt);
+
+ uint8 slot = 0;
+ for (GarrAbilityEntry const* ability : follower.PacketInfo.AbilityID)
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES);
+ stmt->setUInt64(0, follower.PacketInfo.DbID);
+ stmt->setUInt32(1, ability->ID);
+ stmt->setUInt8(2, slot++);
+ trans->Append(stmt);
+ }
+ }
}
bool Garrison::Create(uint32 garrSiteId)
diff --git a/src/server/game/Garrison/Garrison.h b/src/server/game/Garrison/Garrison.h
index be92b9e14f3..dc48a43c5cc 100644
--- a/src/server/game/Garrison/Garrison.h
+++ b/src/server/game/Garrison/Garrison.h
@@ -105,7 +105,8 @@ public:
explicit Garrison(Player* owner);
- bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings);
+ bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings,
+ PreparedQueryResult followers, PreparedQueryResult abilities);
void SaveToDB(SQLTransaction& trans);
bool Create(uint32 garrSiteId);
diff --git a/src/server/game/Garrison/GarrisonMgr.cpp b/src/server/game/Garrison/GarrisonMgr.cpp
index 75f4289c385..f95acef952c 100644
--- a/src/server/game/Garrison/GarrisonMgr.cpp
+++ b/src/server/game/Garrison/GarrisonMgr.cpp
@@ -17,6 +17,7 @@
#include "GarrisonMgr.h"
#include "Containers.h"
+#include "DatabaseEnv.h"
#include "Garrison.h"
#include "ObjectDefines.h"
#include "World.h"
@@ -55,6 +56,9 @@ void GarrisonMgr::Initialize()
}
}
}
+
+ InitializeDbIdSequences();
+ LoadFollowerClassSpecAbilities();
}
GarrSiteLevelEntry const* GarrisonMgr::GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const
@@ -185,13 +189,18 @@ std::list<GarrAbilityEntry const*> GarrisonMgr::RollFollowerAbilities(GarrFollow
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
+ // Add abilities specified in GarrFollowerXAbility.db2 before generic classspec ones on follower creation
if (initial)
{
forcedAbilities.splice(forcedAbilities.end(), abilityList);
forcedTraits.splice(forcedTraits.end(), traitList);
}
+ forcedAbilities.sort();
+ abilityList.sort();
+ forcedTraits.sort();
+ traitList.sort();
+
// check if we have a trait from exclusive category
for (GarrAbilityEntry const* ability : forcedTraits)
{
@@ -204,18 +213,18 @@ std::list<GarrAbilityEntry const*> GarrisonMgr::RollFollowerAbilities(GarrFollow
if (slots[0] > forcedAbilities.size() + abilityList.size())
{
- std::list<GarrAbilityEntry const*> classSpecAbilities; // = GetDefaultClassSpecAbilities(follower, faction)
-
- abilityList.splice(abilityList.end(), classSpecAbilities);
- abilityList.sort();
- abilityList.unique();
+ std::list<GarrAbilityEntry const*> classSpecAbilities = GetClassSpecAbilities(follower, faction);
+ std::list<GarrAbilityEntry const*> classSpecAbilitiesTemp, classSpecAbilitiesTemp2;
+ classSpecAbilitiesTemp2.swap(abilityList);
+ std::set_difference(classSpecAbilities.begin(), classSpecAbilities.end(), forcedAbilities.begin(), forcedAbilities.end(), std::back_inserter(classSpecAbilitiesTemp));
+ std::set_union(classSpecAbilitiesTemp.begin(), classSpecAbilitiesTemp.end(), classSpecAbilitiesTemp2.begin(), classSpecAbilitiesTemp2.end(), std::back_inserter(abilityList));
Trinity::Containers::RandomResizeList(abilityList, std::max<int32>(0, slots[0] - forcedAbilities.size()));
}
if (slots[1] > forcedTraits.size() + traitList.size())
{
- std::list<GarrAbilityEntry const*> genericTraits;
+ std::list<GarrAbilityEntry const*> genericTraits, genericTraitsTemp;
for (GarrAbilityEntry const* ability : _garrisonFollowerRandomTraits)
{
if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE)
@@ -227,9 +236,10 @@ std::list<GarrAbilityEntry const*> GarrisonMgr::RollFollowerAbilities(GarrFollow
if (hasForcedExclusiveTrait && ability->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE)
continue;
- genericTraits.push_back(ability);
+ genericTraitsTemp.push_back(ability);
}
+ std::set_difference(genericTraitsTemp.begin(), genericTraitsTemp.end(), forcedTraits.begin(), forcedTraits.end(), std::back_inserter(genericTraits));
genericTraits.splice(genericTraits.begin(), traitList);
// "split" the list into two parts [nonexclusive, exclusive] to make selection later easier
genericTraits.sort([](GarrAbilityEntry const* a1, GarrAbilityEntry const* a2)
@@ -248,7 +258,7 @@ std::list<GarrAbilityEntry const*> GarrisonMgr::RollFollowerAbilities(GarrFollow
if ((*itr)->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE)
break;
- while (traitList.size() < std::max<int32>(0, slots[1] - forcedTraits.size()) && !genericTraits.empty())
+ while (traitList.size() < std::max<int32>(0, slots[1] - forcedTraits.size()) && total)
{
auto itr = genericTraits.begin();
std::advance(itr, urand(0, total-- - 1));
@@ -269,3 +279,75 @@ std::list<GarrAbilityEntry const*> GarrisonMgr::RollFollowerAbilities(GarrFollow
return result;
}
+
+std::list<GarrAbilityEntry const*> GarrisonMgr::GetClassSpecAbilities(GarrFollowerEntry const* follower, uint32 faction) const
+{
+ std::list<GarrAbilityEntry const*> abilities;
+ uint32 classSpecId;
+ switch (faction)
+ {
+ case GARRISON_FACTION_INDEX_HORDE:
+ classSpecId = follower->HordeGarrClassSpecID;
+ break;
+ case GARRISON_FACTION_INDEX_ALLIANCE:
+ classSpecId = follower->AllianceGarrClassSpecID;
+ break;
+ default:
+ return abilities;
+ }
+
+ if (!sGarrClassSpecStore.LookupEntry(classSpecId))
+ return abilities;
+
+ auto itr = _garrisonFollowerClassSpecAbilities.find(classSpecId);
+ if (itr != _garrisonFollowerClassSpecAbilities.end())
+ abilities = itr->second;
+
+ return abilities;
+}
+
+void GarrisonMgr::InitializeDbIdSequences()
+{
+ if (QueryResult result = CharacterDatabase.Query("SELECT MAX(dbId) FROM character_garrison_followers"))
+ _followerDbIdGenerator = (*result)[0].GetUInt64() + 1;
+}
+
+void GarrisonMgr::LoadFollowerClassSpecAbilities()
+{
+ QueryResult result = WorldDatabase.Query("SELECT classSpecId, abilityId FROM garrison_follower_class_spec_abilities");
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 garrison follower class spec abilities. DB table `garrison_follower_class_spec_abilities` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 classSpecId = fields[0].GetUInt32();
+ uint32 abilityId = fields[1].GetUInt32();
+
+ if (!sGarrClassSpecStore.LookupEntry(classSpecId))
+ {
+ TC_LOG_ERROR("sql.sql", "Non-existing GarrClassSpec.db2 entry %u was referenced in `garrison_follower_class_spec_abilities` by row (%u, %u).", classSpecId, classSpecId, abilityId);
+ continue;
+ }
+
+ GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(abilityId);
+ if (!ability)
+ {
+ TC_LOG_ERROR("sql.sql", "Non-existing GarrAbility.db2 entry %u was referenced in `garrison_follower_class_spec_abilities` by row (%u, %u).", abilityId, classSpecId, abilityId);
+ continue;
+ }
+
+ _garrisonFollowerClassSpecAbilities[classSpecId].push_back(ability);
+ ++count;
+
+ } while (result->NextRow());
+
+ for (auto& pair : _garrisonFollowerClassSpecAbilities)
+ pair.second.sort();
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u garrison follower class spec abilities.", count);
+}
diff --git a/src/server/game/Garrison/GarrisonMgr.h b/src/server/game/Garrison/GarrisonMgr.h
index a54606dd9b1..68514f4a2f3 100644
--- a/src/server/game/Garrison/GarrisonMgr.h
+++ b/src/server/game/Garrison/GarrisonMgr.h
@@ -46,17 +46,22 @@ public:
GarrBuildingEntry const* GetPreviousLevelBuilding(uint32 buildingType, uint32 currentLevel) const;
uint64 GenerateFollowerDbId();
std::list<GarrAbilityEntry const*> RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const;
+ std::list<GarrAbilityEntry const*> GetClassSpecAbilities(GarrFollowerEntry const* follower, uint32 faction) const;
private:
+ void InitializeDbIdSequences();
+ void LoadFollowerClassSpecAbilities();
+
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;
std::unordered_map<uint32 /*buildingType*/, std::vector<GarrBuildingEntry const*>> _garrisonBuildingsByType;
std::unordered_map<uint32 /*garrFollowerId*/, GarrAbilities> _garrisonFollowerAbilities[2];
- std::unordered_set<GarrAbilityEntry const*> _garrisonFollowerRandomTraits;
+ std::unordered_map<uint32 /*classSpecId*/, std::list<GarrAbilityEntry const*>> _garrisonFollowerClassSpecAbilities;
+ std::set<GarrAbilityEntry const*> _garrisonFollowerRandomTraits;
- uint64 _followerDbIdGenerator;
+ uint64 _followerDbIdGenerator = UI64LIT(0);
};
#define sGarrisonMgr GarrisonMgr::Instance()
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 56d865e5d06..65f05e4dbbb 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -248,6 +248,14 @@ bool LoginQueryHolder::Initialize()
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS, stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS);
+ stmt->setUInt64(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS, stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES);
+ stmt->setUInt64(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES, stmt);
+
return res;
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index e9ce253d1cf..277ccd4569a 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -690,7 +690,12 @@ void CharacterDatabaseConnection::DoPrepareStatements()
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_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);
+ PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS, "SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS, "INSERT INTO character_garrison_followers (dbId, guid, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS, "DELETE gfab, gf FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE gf.guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "SELECT gfab.dbId, gfab.abilityId FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE guid = ? ORDER BY gfab.slot", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "INSERT INTO character_garrison_follower_abilities (dbId, abilityId, slot) VALUES (?, ?, ?)", CONNECTION_ASYNC);
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index 53c42a0b852..fc9c930e6b1 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -608,6 +608,11 @@ enum CharacterDatabaseStatements
CHAR_SEL_CHARACTER_GARRISON_BUILDINGS,
CHAR_INS_CHARACTER_GARRISON_BUILDINGS,
CHAR_DEL_CHARACTER_GARRISON_BUILDINGS,
+ CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS,
+ CHAR_INS_CHARACTER_GARRISON_FOLLOWERS,
+ CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS,
+ CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES,
+ CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES,
MAX_CHARACTERDATABASE_STATEMENTS
};