[Factions] Remove from shared memory and simplify (#3999)

* [Factions] Remove from shared memory and simplify

- Removes factions from shared memory and moves to zone based storage of repositories and changes the NPC `faction_list` to also use repositories.
- This affects NPC Factions and Faction Associations.

* Bug fixes.

* Update client.cpp

* Update client.cpp

* Update client.cpp

* Cleanup

* Update client.cpp

* Update client.cpp

* Update client.cpp

* Final push

* Update CMakeLists.txt

* Consolidate reloading.

* [Cleanup] PR # 3999 (#4039)

* [Fixes for PR # 3999

* [Reload actual in game factions, not just the umbrella data.

* syntax

* Fix typo

* Foix bug where primary_faction not filled in when no hits

* Fix typos

* Fix splash factions for kills.

* Fix typo

* Fix more variable names to be accurate

* Fix Loads to load new ones as they come in.

* Load npc_factions without primary (tasks) and support old task faction

* Rename to make way for new LoadFactionAssocition (by faction_id)

* Fix some review comments

* Add code to load factions for splash tasks and quests.

* Fix issue with sign and RewardFaction, fix Log Message

---------

Co-authored-by: Paul Coene <noudess@gmail.com>
This commit is contained in:
Alex King
2024-02-04 10:38:38 -05:00
committed by GitHub
parent 029581772d
commit 297e358c02
31 changed files with 568 additions and 597 deletions
+1
View File
@@ -161,6 +161,7 @@ SET(zone_sources
zone_config.cpp
zonedb.cpp
zone_event_scheduler.cpp
zone_npc_factions.cpp
zone_reload.cpp
zoning.cpp
)
+5 -5
View File
@@ -285,24 +285,24 @@ void NPC::DescribeAggro(Client *to_who, Mob *mob, bool verbose) {
auto faction_name = content_db.GetFactionName(mob_faction_id);
bool has_entry = false;
for (auto faction : faction_list) {
if (static_cast<int>(faction->factionID) == mob_faction_id) {
if (static_cast<int>(faction.faction_id) == mob_faction_id) {
to_who->Message(
Chat::White,
fmt::format(
"{} has {} standing with Faction {} ({}) with their Faction Level of {}",
to_who->GetTargetDescription(mob),
(
faction->npc_value != 0 ?
faction.npc_value != 0 ?
(
faction->npc_value > 0 ?
faction.npc_value > 0 ?
"positive" :
"negative"
) :
"neutral"
),
faction_name,
faction->factionID,
faction->npc_value
faction.faction_id,
faction.npc_value
).c_str()
);
has_entry = true;
+151 -58
View File
@@ -7385,39 +7385,42 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra
}
//Sets the characters faction standing with the specified NPC.
void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest)
void Client::SetFactionLevel(
uint32 character_id,
uint32 npc_faction_id,
uint8 class_id,
uint8 race_id,
uint8 deity_id,
bool is_quest
)
{
int32 faction_id[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32 npc_value[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8 temp[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32 current_value;
auto l = zone->GetNPCFactionEntries(npc_faction_id);
// Get the npc faction list
if (!content_db.GetNPCFactionList(npc_id, faction_id, npc_value, temp)) {
if (l.empty()) {
return;
}
for (int i = 0; i < MAX_NPC_FACTIONS; i++) {
int32 faction_before_hit;
FactionMods fm;
int32 this_faction_max;
int32 this_faction_min;
int current_value;
if (faction_id[i] <= 0)
for (auto& e : l) {
if (e.faction_id <= 0 || e.value == 0) {
continue;
}
// Find out starting faction for this faction
// It needs to be used to adj max and min personal
// The range is still the same, 1200-3000(4200), but adjusted for base
content_db.GetFactionData(&fm, GetClass(), GetFactionRace(), GetDeity(), faction_id[i]);
int faction_before;
int faction_minimum;
int faction_maximum;
if (quest)
{
//The ole switcheroo
if (npc_value[i] > 0)
npc_value[i] = -std::abs(npc_value[i]);
else if (npc_value[i] < 0)
npc_value[i] = std::abs(npc_value[i]);
FactionMods faction_modifiers;
content_db.GetFactionData(&faction_modifiers, class_id, race_id, deity_id, e.faction_id);
if (is_quest) {
if (e.npc_value > 0) {
e.npc_value = -std::abs(e.npc_value);
} else if (e.npc_value < 0) {
e.npc_value = std::abs(e.npc_value);
}
}
// Adjust the amount you can go up or down so the resulting range
@@ -7425,23 +7428,36 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui
//
// Adjust these values for cases where starting faction is below
// min or above max by not allowing any earn in those directions.
this_faction_min = fm.min - fm.base;
this_faction_min = std::min(0, this_faction_min);
this_faction_max = fm.max - fm.base;
this_faction_max = std::max(0, this_faction_max);
faction_minimum = faction_modifiers.min - faction_modifiers.base;
faction_minimum = std::min(0, faction_minimum);
faction_maximum = faction_modifiers.max - faction_modifiers.base;
faction_maximum = std::max(0, faction_maximum);
// Get the characters current value with that faction
current_value = GetCharacterFactionLevel(faction_id[i]);
faction_before_hit = current_value;
current_value = GetCharacterFactionLevel(e.faction_id);
faction_before = current_value;
UpdatePersonalFaction(char_id, npc_value[i], faction_id[i], &current_value, temp[i], this_faction_min, this_faction_max);
UpdatePersonalFaction(
character_id,
e.value,
e.faction_id,
&current_value,
e.temp,
faction_minimum,
faction_maximum
);
//Message(Chat::Lime, "Min(%d) Max(%d) Before(%d), After(%d)\n", this_faction_min, this_faction_max, faction_before_hit, current_value);
SendFactionMessage(npc_value[i], faction_id[i], faction_before_hit, current_value, temp[i], this_faction_min, this_faction_max);
SendFactionMessage(
e.value,
e.faction_id,
faction_before,
current_value,
e.temp,
faction_minimum,
faction_maximum
);
}
return;
}
void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp)
@@ -8213,33 +8229,92 @@ void Client::CashReward(uint32 copper, uint32 silver, uint32 gold, uint32 platin
QueuePacket(outapp.get());
}
void Client::RewardFaction(int id, int amount)
void Client::RewardFaction(int faction_id, int amount)
{
// first we hit the primary faction, even without any associations
SetFactionLevel2(CharacterID(), id, GetClass(), GetBaseRace(), GetDeity(), amount, false);
SetFactionLevel2(CharacterID(), faction_id, GetClass(), GetBaseRace(), GetDeity(), amount, false);
auto faction_assoc = content_db.GetFactionAssociationHit(id);
// We could log here, but since it's actually expected for some not to have entries, it would be noisy.
if (!faction_assoc) {
auto f = zone->GetFactionAssociation(faction_id);
if (!f) {
return;
}
// now hit them in order
for (int i = 0; i < MAX_FACTION_ASSOC; ++i) {
if (faction_assoc->hits[i].id <= 0) // we don't allow later entries
break;
if (faction_assoc->hits[i].multiplier == 0.0f) {
LogFaction("Bad association multiplier for ID {} entry {}", id, i + 1);
continue;
std::vector<int> faction_ids = {
f->id_1,
f->id_2,
f->id_3,
f->id_4,
f->id_5,
f->id_6,
f->id_7,
f->id_8,
f->id_9,
f->id_10
};
std::vector<float> faction_modifiers = {
f->mod_1,
f->mod_2,
f->mod_3,
f->mod_4,
f->mod_5,
f->mod_6,
f->mod_7,
f->mod_8,
f->mod_9,
f->mod_10
};
std::vector<float> temporary_values = {
static_cast<float>(faction_modifiers[0] * amount),
static_cast<float>(faction_modifiers[1] * amount),
static_cast<float>(faction_modifiers[2] * amount),
static_cast<float>(faction_modifiers[3] * amount),
static_cast<float>(faction_modifiers[4] * amount),
static_cast<float>(faction_modifiers[5] * amount),
static_cast<float>(faction_modifiers[6] * amount),
static_cast<float>(faction_modifiers[7] * amount),
static_cast<float>(faction_modifiers[8] * amount),
static_cast<float>(faction_modifiers[9] * amount)
};
std::vector<int> signs = {
temporary_values[0] < 0.0f ? -1 : 1,
temporary_values[1] < 0.0f ? -1 : 1,
temporary_values[2] < 0.0f ? -1 : 1,
temporary_values[3] < 0.0f ? -1 : 1,
temporary_values[4] < 0.0f ? -1 : 1,
temporary_values[5] < 0.0f ? -1 : 1,
temporary_values[6] < 0.0f ? -1 : 1,
temporary_values[7] < 0.0f ? -1 : 1,
temporary_values[8] < 0.0f ? -1 : 1,
temporary_values[9] < 0.0f ? -1 : 1
};
std::vector<int> new_values = {
std::max(1, static_cast<int>(std::abs(temporary_values[0]))) * signs[0],
std::max(1, static_cast<int>(std::abs(temporary_values[1]))) * signs[1],
std::max(1, static_cast<int>(std::abs(temporary_values[2]))) * signs[2],
std::max(1, static_cast<int>(std::abs(temporary_values[3]))) * signs[3],
std::max(1, static_cast<int>(std::abs(temporary_values[4]))) * signs[4],
std::max(1, static_cast<int>(std::abs(temporary_values[5]))) * signs[5],
std::max(1, static_cast<int>(std::abs(temporary_values[6]))) * signs[6],
std::max(1, static_cast<int>(std::abs(temporary_values[7]))) * signs[7],
std::max(1, static_cast<int>(std::abs(temporary_values[8]))) * signs[8],
std::max(1, static_cast<int>(std::abs(temporary_values[9]))) * signs[9]
};
for (uint16 slot_id = 0; slot_id < faction_ids.size(); slot_id++) {
if (faction_ids[slot_id] > 0) {
SetFactionLevel2(
CharacterID(),
faction_ids[slot_id],
GetClass(),
GetBaseRace(),
GetDeity(),
new_values[slot_id],
false
);
}
// value is truncated and min clamped to 1 (or -1)
float temp = faction_assoc->hits[i].multiplier * amount;
int sign = temp < 0.0f ? -1 : 1;
int32 new_amount = std::max(1, static_cast<int32>(std::abs(temp))) * sign;
SetFactionLevel2(CharacterID(), faction_assoc->hits[i].id, GetClass(), GetBaseRace(), GetDeity(),
new_amount, false);
}
}
@@ -9019,6 +9094,7 @@ void Client::ShowDevToolsMenu()
menu_reload_three += Saylink::Silent("#reload data_buckets_cache", "Databuckets");
menu_reload_three += " | " + Saylink::Silent("#reload doors", "Doors");
menu_reload_three += " | " + Saylink::Silent("#reload factions", "Factions");
menu_reload_three += " | " + Saylink::Silent("#reload ground_spawns", "Ground Spawns");
menu_reload_four += Saylink::Silent("#reload logs", "Level Based Experience Modifiers");
@@ -10993,7 +11069,24 @@ void Client::SendReloadCommandMessages() {
);
auto dztemplates_link = Saylink::Silent("#reload dztemplates");
Message(Chat::White, fmt::format("Usage: {} - Reloads Dynamic Zone Templates globally", dztemplates_link).c_str());
Message(
Chat::White,
fmt::format(
"Usage: {} - Reloads Dynamic Zone Templates globally",
dztemplates_link
).c_str()
);
auto factions_link = Saylink::Silent("#reload factions");
Message(
Chat::White,
fmt::format(
"Usage: {} - Reloads Factions globally",
factions_link
).c_str()
);
auto ground_spawns_link = Saylink::Silent("#reload ground_spawns");
+1 -1
View File
@@ -699,7 +699,7 @@ public:
void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max);
void UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max);
void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest = false);
void SetFactionLevel(uint32 char_id, uint32 npc_faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest = false);
void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp);
int32 GetRawItemAC();
+3 -3
View File
@@ -340,9 +340,9 @@ void command_npcedit(Client *c, const Seperator *sep)
} else if (!strcasecmp(sep->arg[1], "faction")) {
if (sep->IsNumber(2)) {
auto npc_faction_id = Strings::ToInt(sep->arg[2]);
const NPCFactionList* cf = content_db.GetNPCFactionEntry(npc_faction_id);
if (cf) {
auto faction_id = cf->primaryfaction;
const auto f = zone->GetNPCFaction(npc_faction_id);
if (f) {
auto faction_id = f->primaryfaction;
auto faction_name = content_db.GetFactionName(faction_id);
n.npc_faction_id = npc_faction_id;
+5
View File
@@ -21,6 +21,7 @@ void command_reload(Client *c, const Seperator *sep)
bool is_data_buckets = !strcasecmp(sep->arg[1], "data_buckets_cache");
bool is_doors = !strcasecmp(sep->arg[1], "doors");
bool is_dztemplates = !strcasecmp(sep->arg[1], "dztemplates");
bool is_factions = !strcasecmp(sep->arg[1], "factions");
bool is_ground_spawns = !strcasecmp(sep->arg[1], "ground_spawns");
bool is_level_mods = !strcasecmp(sep->arg[1], "level_mods");
bool is_logs = !strcasecmp(sep->arg[1], "logs") || is_logs_reload_alias;
@@ -50,6 +51,7 @@ void command_reload(Client *c, const Seperator *sep)
!is_data_buckets &&
!is_doors &&
!is_dztemplates &&
!is_factions &&
!is_ground_spawns &&
!is_level_mods &&
!is_logs &&
@@ -100,6 +102,9 @@ void command_reload(Client *c, const Seperator *sep)
} else if (is_dztemplates) {
c->Message(Chat::White, "Attempting to reload Dynamic Zone Templates globally.");
pack = new ServerPacket(ServerOP_ReloadDzTemplates, 0);
} else if (is_factions) {
c->Message(Chat::White, "Attempting to reload Factions globally.");
pack = new ServerPacket(ServerOP_ReloadFactions, 0);
} else if (is_ground_spawns) {
c->Message(Chat::White, "Attempting to reload Ground Spawns globally.");
pack = new ServerPacket(ServerOP_ReloadGroundSpawns, 0);
+2 -2
View File
@@ -390,9 +390,9 @@ int Lua_Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 race, uint
return static_cast<int>(self->GetFactionLevel(char_id, npc_id, race, class_, deity, faction, npc));
}
void Lua_Client::SetFactionLevel(uint32 char_id, uint32 npc_id, int char_class, int char_race, int char_deity) {
void Lua_Client::SetFactionLevel(uint32 char_id, uint32 npc_faction_id, int char_class, int char_race, int char_deity) {
Lua_Safe_Call_Void();
self->SetFactionLevel(char_id, npc_id, char_class, char_race, char_deity);
self->SetFactionLevel(char_id, npc_faction_id, char_class, char_race, char_deity);
}
void Lua_Client::SetFactionLevel2(uint32 char_id, int faction_id, int char_class, int char_race, int char_deity, int value, int temp) {
+1 -1
View File
@@ -145,7 +145,7 @@ public:
bool TeleportRaidToPlayerByName(std::string player_name);
void ChangeLastName(std::string last_name);
int GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 race, uint32 class_, uint32 deity, uint32 faction, Lua_NPC npc);
void SetFactionLevel(uint32 char_id, uint32 npc_id, int char_class, int char_race, int char_deity);
void SetFactionLevel(uint32 char_id, uint32 npc_faction_id, int char_class, int char_race, int char_deity);
void SetFactionLevel2(uint32 char_id, int faction_id, int char_class, int char_race, int char_deity, int value, int temp);
void RewardFaction(int id, int amount);
int GetRawItemAC();
-8
View File
@@ -372,14 +372,6 @@ int main(int argc, char **argv)
LogError("Failed. But ignoring error and going on..");
}
if (!content_db.LoadNPCFactionLists(hotfix_name)) {
LogError("Loading npcs faction lists failed!");
return 1;
}
if (!content_db.LoadFactionAssociation(hotfix_name)) {
LogError("Loading faction association hits failed!");
return 1;
}
if (!database.LoadLoot(hotfix_name)) {
LogError("Loading loot failed!");
return 1;
+2 -3
View File
@@ -2775,14 +2775,13 @@ void Mob::ShowStats(Client* c)
// Faction
if (t->GetNPCFactionID()) {
auto faction_id = t->GetPrimaryFaction();
auto faction_name = content_db.GetFactionName(faction_id);
const std::string& faction_name = content_db.GetFactionName(t->GetPrimaryFaction());
c->Message(
Chat::White,
fmt::format(
"Faction: {} ({})",
faction_name,
faction_id
t->GetPrimaryFaction()
).c_str()
);
}
+21 -36
View File
@@ -512,34 +512,19 @@ NPC::~NPC()
{
AI_Stop();
if(proximity != nullptr) {
if (proximity) {
entity_list.RemoveProximity(GetID());
safe_delete(proximity);
}
safe_delete(NPCTypedata_ours);
{
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; ++cur) {
ServerLootItem_Struct* item = *cur;
safe_delete(item);
}
itemlist.clear();
for (auto* e : itemlist) {
safe_delete(e);
}
{
std::list<struct NPCFaction*>::iterator cur,end;
cur = faction_list.begin();
end = faction_list.end();
for(; cur != end; ++cur) {
struct NPCFaction* fac = *cur;
safe_delete(fac);
}
itemlist.clear();
faction_list.clear();
}
safe_delete(reface_timer);
safe_delete(swarmInfoPtr);
@@ -3204,19 +3189,17 @@ FACTION_VALUE NPC::GetReverseFactionCon(Mob* iOther) {
//Look through our faction list and return a faction con based
//on the npc_value for the other person's primary faction in our list.
FACTION_VALUE NPC::CheckNPCFactionAlly(int32 other_faction) {
std::list<struct NPCFaction*>::iterator cur,end;
cur = faction_list.begin();
end = faction_list.end();
for(; cur != end; ++cur) {
struct NPCFaction* fac = *cur;
if ((int32)fac->factionID == other_faction) {
if (fac->npc_value > 0)
FACTION_VALUE NPC::CheckNPCFactionAlly(int32 other_faction)
{
for (const auto& e : faction_list) {
if (e.faction_id == other_faction) {
if (e.npc_value > 0) {
return FACTION_ALLY;
else if (fac->npc_value < 0)
} else if (e.npc_value < 0) {
return FACTION_SCOWLS;
else
} else {
return FACTION_INDIFFERENTLY;
}
}
}
@@ -3225,14 +3208,16 @@ FACTION_VALUE NPC::CheckNPCFactionAlly(int32 other_faction) {
// where an npc is on a faction but has no hits (hence no entry in
// npc_faction_entries).
if (GetPrimaryFaction() == other_faction)
if (GetPrimaryFaction() == other_faction) {
return FACTION_ALLY;
else
} else {
return FACTION_INDIFFERENTLY;
}
}
bool NPC::IsFactionListAlly(uint32 other_faction) {
return(CheckNPCFactionAlly(other_faction) == FACTION_ALLY);
bool NPC::IsFactionListAlly(uint32 other_faction)
{
return CheckNPCFactionAlly(other_faction) == FACTION_ALLY;
}
int NPC::GetScore()
@@ -3673,9 +3658,9 @@ void NPC::AIYellForHelp(Mob *sender, Mob *attacker)
*/
if (mob->GetLevel() >= 50 || mob->AlwaysAggro() || attacker->GetLevelCon(mob->GetLevel()) != CON_GRAY) {
if (mob->GetPrimaryFaction() == sender->CastToNPC()->GetPrimaryFaction()) {
const NPCFactionList *cf = content_db.GetNPCFactionEntry(mob->CastToNPC()->GetNPCFactionID());
if (cf) {
if (cf->assistprimaryfaction == 0) {
const auto f = zone->GetNPCFaction(mob->CastToNPC()->GetNPCFactionID());
if (f) {
if (f->ignore_primary_assist) {
continue; //Same faction and ignore primary assist
}
}
+4 -2
View File
@@ -26,6 +26,7 @@
#include "../common/zone_store.h"
#include "zonedump.h"
#include "../common/loottable.h"
#include "../common/repositories/npc_faction_entries_repository.h"
#include <deque>
#include <list>
@@ -296,7 +297,7 @@ public:
void SetNPCFactionID(int32 in)
{
npc_faction_id = in;
content_db.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction);
content_db.GetFactionIDsForNPC(npc_faction_id, &faction_list, &primary_faction);
}
glm::vec4 m_SpawnPoint;
@@ -564,7 +565,6 @@ protected:
friend class EntityList;
friend class Aura;
std::list<struct NPCFaction*> faction_list;
uint32 copper;
uint32 silver;
uint32 gold;
@@ -573,6 +573,8 @@ protected:
uint32 spawn_group_id;
uint16 wp_m;
std::list<NpcFactionEntriesRepository::NpcFactionEntries> faction_list;
int32 npc_faction_id;
int32 primary_faction;
int32 faction_amount;
+2 -2
View File
@@ -344,9 +344,9 @@ int Perl_Client_GetFactionLevel(Client* self, uint32 char_id, uint32 npc_id, uin
return self->GetFactionLevel(char_id, npc_id, race_id, class_id, deity_id, faction_id, tnpc);
}
void Perl_Client_SetFactionLevel(Client* self, uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity) // @categories Faction
void Perl_Client_SetFactionLevel(Client* self, uint32 char_id, uint32 npc_faction_id, uint8 char_class, uint8 char_race, uint8 char_deity) // @categories Faction
{
self->SetFactionLevel(char_id, npc_id, char_class, char_race, char_deity);
self->SetFactionLevel(char_id, npc_faction_id, char_class, char_race, char_deity);
}
void Perl_Client_SetFactionLevel2(Client* self, uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value) // @categories Faction
+1
View File
@@ -1440,6 +1440,7 @@ void QuestManager::rewardfaction(int faction_id, int faction_value) {
QuestManagerCurrentQuestVars();
if (initiator) {
if (faction_id != 0 && faction_value != 0) {
zone->LoadFactionAssociation(faction_id);
initiator->RewardFaction(faction_id, faction_value);
}
}
+3
View File
@@ -1057,6 +1057,7 @@ void ClientTaskState::RewardTask(Client *c, const TaskInformation *ti, ClientTas
// just use normal NPC faction ID stuff
if (ti->faction_reward && ti->faction_amount == 0) {
zone->LoadNPCFaction(ti->faction_reward);
c->SetFactionLevel(
c->CharacterID(),
ti->faction_reward,
@@ -1065,6 +1066,8 @@ void ClientTaskState::RewardTask(Client *c, const TaskInformation *ti, ClientTas
c->GetDeity()
);
} else if (ti->faction_reward != 0 && ti->faction_amount != 0) {
// faction_reward is a faction ID
zone->LoadFactionAssociation(ti->faction_reward);
c->RewardFaction(
ti->faction_reward,
ti->faction_amount
+11 -10
View File
@@ -1989,6 +1989,17 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
break;
}
case ServerOP_ReloadFactions:
{
if (zone && zone->IsLoaded()) {
zone->SendReloadMessage("Factions");
content_db.LoadFactionData();
zone->ReloadNPCFactions();
zone->ReloadFactionAssociations();
}
break;
}
case ServerOP_ReloadLevelEXPMods:
{
if (zone && zone->IsLoaded()) {
@@ -3497,16 +3508,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
LogError("Loading items failed!");
}
LogInfo("Loading npc faction lists");
if (!content_db.LoadNPCFactionLists(hotfix_name)) {
LogError("Loading npcs faction lists failed!");
}
LogInfo("Loading faction association hits");
if (!content_db.LoadFactionAssociation(hotfix_name)) {
LogError("Loading faction association hits failed!");
}
LogInfo("Loading loot tables");
if (!content_db.LoadLoot(hotfix_name)) {
LogError("Loading loot failed!");
+22
View File
@@ -38,6 +38,9 @@
#include "queryserv.h"
#include "../common/discord/discord.h"
#include "../common/repositories/dynamic_zone_templates_repository.h"
#include "../common/repositories/npc_faction_repository.h"
#include "../common/repositories/npc_faction_entries_repository.h"
#include "../common/repositories/faction_association_repository.h"
struct EXPModifier
{
@@ -407,6 +410,21 @@ public:
void ReloadContentFlags();
void LoadNPCFaction(const uint32 npc_faction_id);
void LoadNPCFactions(const std::vector<uint32>& npc_faction_ids);
void ClearNPCFactions();
void ReloadNPCFactions();
NpcFactionRepository::NpcFaction* GetNPCFaction(const uint32 npc_faction_id);
std::vector<NpcFactionEntriesRepository::NpcFactionEntries> GetNPCFactionEntries(const uint32 npc_faction_id) const;
void LoadNPCFactionAssociation(const uint32 npc_faction_id);
void LoadNPCFactionAssociations(const std::vector<uint32>& npc_faction_ids);
void LoadFactionAssociation(const uint32 faction_id);
void LoadFactionAssociations(const std::vector<uint32>& faction_ids);
void ClearFactionAssociations();
void ReloadFactionAssociations();
FactionAssociationRepository::FactionAssociation* GetFactionAssociation(const uint32 faction_id);
private:
bool allow_mercs;
bool can_bind;
@@ -457,6 +475,10 @@ private:
Timer qglobal_purge_timer;
ZoneSpellsBlocked *blocked_spells;
// Factions
std::vector<NpcFactionRepository::NpcFaction> m_npc_factions = { };
std::vector<NpcFactionEntriesRepository::NpcFactionEntries> m_npc_faction_entries = { };
std::vector<FactionAssociationRepository::FactionAssociation> m_faction_associations = { };
};
#endif
+277
View File
@@ -0,0 +1,277 @@
#include <vector>
#include "zone.h"
#include "../common/repositories/npc_faction_repository.h"
#include "../common/repositories/npc_faction_entries_repository.h"
void Zone::LoadNPCFactions(const std::vector<uint32> &npc_faction_ids)
{
LogFaction(
"Load for Faction IDs [{}]",
Strings::Join(npc_faction_ids, ", ")
);
if (npc_faction_ids.empty()) {
LogFactionDetail("No NPC factions to load.");
return;
}
// Narrow the list sent in, to new npc_faction_ids that are being loaded
// as the result of a new spawn. Ignore those already loaded.
std::vector<uint32> new_npc_faction_ids = { };
for (const auto& e : npc_faction_ids) {
bool found = false;
for (const auto& nf : m_npc_factions) {
found = (nf.id == e);
if (found) {
LogFaction("Already loaded npc_faction [{}]", nf.id);
break;
}
}
// This one is new
if (!found) {
new_npc_faction_ids.emplace_back(e);
}
}
if (new_npc_faction_ids.empty()) {
LogFactionDetail("No New NPC factions to load.");
return;
}
auto npc_factions = NpcFactionRepository::GetWhere(
content_db,
fmt::format(
"`id` IN ({})",
Strings::Join(new_npc_faction_ids, ", ")
)
);
auto npc_faction_entries = NpcFactionEntriesRepository::GetWhere(
content_db,
fmt::format(
"`npc_faction_id` IN ({})",
Strings::Join(new_npc_faction_ids, ", ")
)
);
for (const auto& e : npc_factions) {
m_npc_factions.emplace_back(e);
for (const auto& f : npc_faction_entries) {
m_npc_faction_entries.emplace_back(f);
}
}
if (npc_factions.size() > 1) {
LogFaction("Loaded [{}] Factions", npc_factions.size());
}
}
void Zone::LoadNPCFaction(const uint32 npc_faction_id)
{
if (!npc_faction_id) {
return;
}
LogFaction("LoadNPCFaction for [{}]", npc_faction_id);
LoadNPCFactions({ npc_faction_id });
}
void Zone::ClearNPCFactions()
{
m_npc_factions.clear();
m_npc_faction_entries.clear();
}
void Zone::ReloadNPCFactions()
{
LogFaction("Reloading NPC Factions");
ClearNPCFactions();
std::vector<uint32> npc_faction_ids = { };
for (const auto& n : entity_list.GetNPCList()) {
if (n.second->GetNPCFactionID() != 0) {
if (
std::find(
npc_faction_ids.begin(),
npc_faction_ids.end(),
n.second->GetNPCFactionID()
) == npc_faction_ids.end()
) {
npc_faction_ids.emplace_back(n.second->GetNPCFactionID());
}
}
}
LoadNPCFactions(npc_faction_ids);
}
NpcFactionRepository::NpcFaction* Zone::GetNPCFaction(const uint32 npc_faction_id)
{
for (auto& e : m_npc_factions) {
if (e.id == npc_faction_id) {
return &e;
}
}
return nullptr;
}
std::vector<NpcFactionEntriesRepository::NpcFactionEntries> Zone::GetNPCFactionEntries(const uint32 npc_faction_id) const
{
std::vector<NpcFactionEntriesRepository::NpcFactionEntries> npc_faction_entries = { };
std::vector<uint32> faction_ids;
for (auto e : m_npc_faction_entries) {
if (
e.npc_faction_id == npc_faction_id &&
std::find(
faction_ids.begin(),
faction_ids.end(),
e.faction_id
) == faction_ids.end()
) {
faction_ids.emplace_back(e.faction_id);
npc_faction_entries.emplace_back(e);
}
}
return npc_faction_entries;
}
void Zone::LoadNPCFactionAssociations(const std::vector<uint32>& npc_faction_ids)
{
LogFaction(
"Load Associations for NPC Faction IDs [{}]",
Strings::Join(npc_faction_ids, ", ")
);
if (npc_faction_ids.empty()) {
LogFactionDetail("No Faction Associations to load.");
return;
}
std::vector<uint32> faction_ids = { };
for (const auto& e : npc_faction_ids) {
for (const auto& f : m_npc_factions) {
bool found = false;
if (e == f.id && f.primaryfaction > 0) {
for (const auto& a : m_faction_associations) {
if (a.id == f.primaryfaction) {
found = true;
LogFaction("Association [{}] already loaded", a.id);
break;
}
}
if (!found) {
faction_ids.emplace_back(f.primaryfaction);
}
}
}
}
if (faction_ids.empty()) {
LogFactionDetail("No New Faction Associations to load.");
}
else {
LoadFactionAssociations(faction_ids);
}
}
void Zone::LoadNPCFactionAssociation(const uint32 npc_faction_id)
{
if (!npc_faction_id) {
return;
}
LoadNPCFactionAssociations({ npc_faction_id });
}
void Zone::LoadFactionAssociations(const std::vector<uint32>& faction_ids)
{
LogFaction(
"These are the primary faction IDs [{}]",
Strings::Join(faction_ids, ", ")
);
const auto& faction_associations = FactionAssociationRepository::GetWhere(
content_db,
fmt::format(
"`id` IN ({})",
Strings::Join(faction_ids, ", ")
)
);
if (faction_associations.empty()) {
LogFaction(
"No Faction Association Entries to load for Faction IDs [{}]",
Strings::Join(faction_ids, ", ")
);
return;
}
for (const auto& e : faction_associations) {
m_faction_associations.emplace_back(e);
}
LogFaction("Loaded [{}] Faction Associations.", faction_associations.size());
}
void Zone::LoadFactionAssociation(const uint32 faction_id)
{
if (!faction_id) {
return;
}
LoadFactionAssociations({ faction_id });
}
void Zone::ClearFactionAssociations()
{
m_faction_associations.clear();
}
void Zone::ReloadFactionAssociations()
{
ClearFactionAssociations();
std::vector<uint32> npc_faction_ids = { };
for (const auto& n : entity_list.GetNPCList()) {
if (n.second->GetNPCFactionID() != 0) {
if (
std::find(
npc_faction_ids.begin(),
npc_faction_ids.end(),
n.second->GetNPCFactionID()
) == npc_faction_ids.end()
) {
npc_faction_ids.emplace_back(n.second->GetNPCFactionID());
}
}
}
LogFaction("Reloading Faction Associations");
LoadNPCFactionAssociations(npc_faction_ids);
}
FactionAssociationRepository::FactionAssociation* Zone::GetFactionAssociation(const uint32 faction_id)
{
for (auto& e : m_faction_associations) {
if (e.id == faction_id) {
return &e;
}
}
return nullptr;
}
+44 -57
View File
@@ -1746,6 +1746,7 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
}
std::vector<uint32> npc_ids;
std::vector<uint32> npc_faction_ids;
for (NpcTypesRepository::NpcTypes &n : NpcTypesRepository::GetWhere((Database &) content_db, filter)) {
NPCType *t;
@@ -1798,7 +1799,6 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
t->special_abilities[0] = '\0';
}
t->npc_spells_id = n.npc_spells_id;
t->npc_spells_effects_id = n.npc_spells_effects_id;
t->d_melee_texture1 = n.d_melee_texture1;
@@ -1845,6 +1845,18 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
t->drakkin_tattoo = n.drakkin_tattoo;
t->drakkin_details = n.drakkin_details;
if (t->npc_faction_id > 0) {
if (
std::find(
npc_faction_ids.begin(),
npc_faction_ids.end(),
t->npc_faction_id
) == npc_faction_ids.end()
) {
npc_faction_ids.emplace_back(t->npc_faction_id);
}
}
// armor tint
uint32 armor_tint_id = n.armortint_id;
t->armor_tint.Head.Color = (n.armortint_red & 0xFF) << 16;
@@ -1967,6 +1979,11 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
DataBucket::BulkLoadEntities(DataBucketLoadType::NPC, npc_ids);
if (!npc_faction_ids.empty()) {
zone->LoadNPCFactions(npc_faction_ids);
zone->LoadNPCFactionAssociations(npc_faction_ids);
}
return npc;
}
@@ -3466,30 +3483,6 @@ std::string ZoneDatabase::GetFactionName(int32 faction_id)
return faction_name;
}
//o--------------------------------------------------------------
//| Name: GetNPCFactionList; Dec. 16, 2001
//o--------------------------------------------------------------
//| Purpose: Gets a list of faction_id's and values bound to the npc_id. Returns false on failure.
//o--------------------------------------------------------------
bool ZoneDatabase::GetNPCFactionList(uint32 npcfaction_id, int32* faction_id, int32* value, uint8* temp, int32* primary_faction) {
if (npcfaction_id <= 0) {
if (primary_faction)
*primary_faction = npcfaction_id;
return true;
}
const NPCFactionList* nfl = GetNPCFactionEntry(npcfaction_id);
if (!nfl)
return false;
if (primary_faction)
*primary_faction = nfl->primaryfaction;
for (int i=0; i<MAX_NPC_FACTIONS; i++) {
faction_id[i] = nfl->factionid[i];
value[i] = nfl->factionvalue[i];
temp[i] = nfl->factiontemp[i];
}
return true;
}
//o--------------------------------------------------------------
//| Name: SetCharacterFactionLevel; Dec. 20, 2001
//o--------------------------------------------------------------
@@ -3634,46 +3627,40 @@ bool ZoneDatabase::LoadFactionData()
return true;
}
bool ZoneDatabase::GetFactionIdsForNPC(uint32 nfl_id, std::list<struct NPCFaction*> *faction_list, int32* primary_faction) {
if (nfl_id <= 0) {
std::list<struct NPCFaction*>::iterator cur,end;
cur = faction_list->begin();
end = faction_list->end();
for(; cur != end; ++cur) {
struct NPCFaction* tmp = *cur;
safe_delete(tmp);
bool ZoneDatabase::GetFactionIDsForNPC(
uint32 npc_faction_id,
std::list<NpcFactionEntriesRepository::NpcFactionEntries> *faction_list,
int32* primary_faction
)
{
if (npc_faction_id <= 0) {
faction_list->clear();
if (primary_faction) {
*primary_faction = npc_faction_id;
}
faction_list->clear();
if (primary_faction)
*primary_faction = nfl_id;
return true;
}
const NPCFactionList* nfl = GetNPCFactionEntry(nfl_id);
if (!nfl)
return false;
if (primary_faction)
*primary_faction = nfl->primaryfaction;
std::list<struct NPCFaction*>::iterator cur,end;
cur = faction_list->begin();
end = faction_list->end();
for(; cur != end; ++cur) {
struct NPCFaction* tmp = *cur;
safe_delete(tmp);
const auto& npcf = zone->GetNPCFaction(npc_faction_id);
if (!npcf) {
LogError("No NPC faction entry for [{}]", npc_faction_id);
return false;
}
const auto& l = zone->GetNPCFactionEntries(npc_faction_id);
if (primary_faction) {
*primary_faction = npcf->primaryfaction;
}
faction_list->clear();
for (int i=0; i<MAX_NPC_FACTIONS; i++) {
struct NPCFaction *pFac;
if (nfl->factionid[i]) {
pFac = new struct NPCFaction;
pFac->factionID = nfl->factionid[i];
pFac->value_mod = nfl->factionvalue[i];
pFac->npc_value = nfl->factionnpcvalue[i];
pFac->temp = nfl->factiontemp[i];
faction_list->push_back(pFac);
}
for (const auto& e: l) {
faction_list->emplace_back(e);
}
return true;
}
+2 -2
View File
@@ -12,6 +12,7 @@
#include "event_codes.h"
#include "../common/repositories/doors_repository.h"
#include "../common/races.h"
#include "../common/repositories/npc_faction_entries_repository.h"
#include "bot_database.h"
@@ -505,11 +506,10 @@ public:
uint32 UpdateCharacterCorpseConsent(uint32 character_id, uint32 guild_consent_id);
/* Faction */
bool GetNPCFactionList(uint32 npcfaction_id, int32* faction_id, int32* value, uint8* temp, int32* primary_faction = 0);
bool GetFactionData(FactionMods* fd, uint32 class_mod, uint32 race_mod, uint32 deity_mod, int32 faction_id); //needed for factions Dec, 16 2001
bool GetFactionName(int faction_id, char* name, uint32 buflen); // needed for factions Dec, 16 2001
std::string GetFactionName(int faction_id);
bool GetFactionIdsForNPC(uint32 nfl_id, std::list<struct NPCFaction*> *faction_list, int32* primary_faction = 0); // improve faction handling
bool GetFactionIDsForNPC(uint32 npc_faction_id, std::list<NpcFactionEntriesRepository::NpcFactionEntries>* faction_list, int32* primary_faction = 0); // improve faction handling
bool SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list); // needed for factions Dec, 16 2001
bool LoadFactionData();
inline uint32 GetMaxFaction() { return max_faction; }