[NPCs] Convert Load of NPC Emotes to Repositories (#3954)

* [NPCs] Convert Load of NPC Emotes to Repositories

- Convert `LoadNPCEmotes()` to repositories.

* Cleanup
This commit is contained in:
Alex King 2024-01-13 00:33:11 -05:00 committed by GitHub
parent 4c028b85f0
commit fc627ed52d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 112 additions and 90 deletions

View File

@ -562,6 +562,7 @@ std::string EQ::constants::GetEmoteEventTypeName(uint8 emote_event_type)
const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap() const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
{ {
static const std::map<uint8, std::string> emote_type_map = { static const std::map<uint8, std::string> emote_type_map = {
{ EmoteTypes::Say, "Say" },
{ EmoteTypes::Emote, "Emote" }, { EmoteTypes::Emote, "Emote" },
{ EmoteTypes::Shout, "Shout" }, { EmoteTypes::Shout, "Shout" },
{ EmoteTypes::Proximity, "Proximity" } { EmoteTypes::Proximity, "Proximity" }
@ -572,7 +573,7 @@ const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
std::string EQ::constants::GetEmoteTypeName(uint8 emote_type) std::string EQ::constants::GetEmoteTypeName(uint8 emote_type)
{ {
if (!EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) { if (!EQ::ValueWithin(emote_type, EmoteTypes::Say, EmoteTypes::Proximity)) {
return std::string(); return std::string();
} }

View File

@ -350,6 +350,7 @@ namespace EQ
}; };
enum EmoteTypes : uint8 { enum EmoteTypes : uint8 {
Say,
Emote, Emote,
Shout, Shout,
Proximity Proximity

View File

@ -1818,9 +1818,9 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
parse->EventNPC(EVENT_SLAY, killerMob->CastToNPC(), this, "", 0); parse->EventNPC(EVENT_SLAY, killerMob->CastToNPC(), this, "", 0);
} }
auto emote_id = killerMob->GetEmoteID(); const uint32 emote_id = killerMob->GetEmoteID();
if (emote_id) { if (emote_id) {
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid, this); killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emote_id, this);
} }
killerMob->TrySpellOnKill(killed_level, spell); killerMob->TrySpellOnKill(killed_level, spell);
@ -2725,7 +2725,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.RemoveFromAutoXTargets(this); entity_list.RemoveFromAutoXTargets(this);
uint32 emoteid = GetEmoteID(); const uint32 emote_id = GetEmoteID();
corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata, corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata,
level > 54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS) level > 54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS)
: RuleI(NPC, MinorNPCCorpseDecayTimeMS)); : RuleI(NPC, MinorNPCCorpseDecayTimeMS));
@ -2740,8 +2740,8 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
SetID(0); SetID(0);
ApplyIllusionToCorpse(illusion_spell_id, corpse); ApplyIllusionToCorpse(illusion_spell_id, corpse);
if (killer != 0 && emoteid != 0) if (killer != 0 && emote_id)
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer); corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emote_id, killer);
if (killer != 0 && killer->IsClient()) { if (killer != 0 && killer->IsClient()) {
corpse->AllowPlayerLoot(killer, 0); corpse->AllowPlayerLoot(killer, 0);
if (killer->IsGrouped()) { if (killer->IsGrouped()) {
@ -2823,9 +2823,9 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
// Parse quests even if we're killed by an NPC // Parse quests even if we're killed by an NPC
if (oos) { if (oos) {
if (IsNPC()) { if (IsNPC()) {
auto emote_id = GetEmoteID(); const uint32 emote_id = GetEmoteID();
if (emote_id) { if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid, killer_mob); DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emote_id, killer_mob);
} }
} }
@ -2834,10 +2834,11 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0); parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
} }
auto emote_id = oos->GetEmoteID(); const uint32 emote_id = oos->GetEmoteID();
if (emote_id) { if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this); oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
} }
if (killer_mob) { if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell); killer_mob->TrySpellOnKill(killed_level, spell);
} }
@ -4308,7 +4309,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
} else { } else {
a->force *= 0.10f; // force against NPCs is divided by 10 I guess? ex bash is 0.3, parsed 0.03 against an NPC a->force *= 0.10f; // force against NPCs is divided by 10 I guess? ex bash is 0.3, parsed 0.03 against an NPC
} }
if (ForcedMovement == 0 && a->force != 0.0f && position_update_melee_push_timer.Check()) { if (ForcedMovement == 0 && a->force != 0.0f && position_update_melee_push_timer.Check()) {
m_Delta.x += a->force * g_Math.FastSin(a->hit_heading); m_Delta.x += a->force * g_Math.FastSin(a->hit_heading);
m_Delta.y += a->force * g_Math.FastCos(a->hit_heading); m_Delta.y += a->force * g_Math.FastCos(a->hit_heading);
@ -5314,8 +5315,8 @@ bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
(RuleB(Combat, FinishingBlowOnlyWhenFleeing) && !defender->currently_fleeing) || (RuleB(Combat, FinishingBlowOnlyWhenFleeing) && !defender->currently_fleeing) ||
!RuleB(Combat, FinishingBlowOnlyWhenFleeing) !RuleB(Combat, FinishingBlowOnlyWhenFleeing)
) && ) &&
finishing_blow_level && finishing_blow_level &&
finishing_blow_damage && finishing_blow_damage &&
defender->GetLevel() <= finishing_blow_level && defender->GetLevel() <= finishing_blow_level &&
proc_chance >= zone->random.Int(1, 1000) proc_chance >= zone->random.Int(1, 1000)
) { ) {
@ -6406,7 +6407,7 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
if (flurry_chance && zone->random.Roll(flurry_chance)) { if (flurry_chance && zone->random.Roll(flurry_chance)) {
Attack(target, hand, false, false, IsFromSpell); Attack(target, hand, false, false, IsFromSpell);
if (zone->random.Roll(flurry_chance)) { if (zone->random.Roll(flurry_chance)) {
Attack(target, hand, false, false, IsFromSpell); Attack(target, hand, false, false, IsFromSpell);
} }

View File

@ -6203,10 +6203,7 @@ void Client::CheckLDoNHail(NPC* n)
void Client::CheckEmoteHail(NPC* n, const char* message) void Client::CheckEmoteHail(NPC* n, const char* message)
{ {
if ( if (!Strings::BeginsWith(Strings::ToLower(message), "hail")) {
!Strings::BeginsWith(message, "hail") &&
!Strings::BeginsWith(message, "Hail")
) {
return; return;
} }
@ -6214,7 +6211,7 @@ void Client::CheckEmoteHail(NPC* n, const char* message)
return; return;
} }
const auto emote_id = n->GetEmoteID(); const uint32 emote_id = n->GetEmoteID();
if (emote_id) { if (emote_id) {
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id, this); n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id, this);
} }

View File

@ -680,8 +680,8 @@ void EntityList::AddNPC(NPC *npc, bool send_spawn_packet, bool dont_queue)
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
} }
const auto emote_id = npc->GetEmoteID(); const uint32 emote_id = npc->GetEmoteID();
if (emote_id != 0) { if (emote_id) {
npc->DoNPCEmote(EQ::constants::EmoteEventTypes::OnSpawn, emote_id); npc->DoNPCEmote(EQ::constants::EmoteEventTypes::OnSpawn, emote_id);
} }

View File

@ -1092,6 +1092,22 @@ void command_npcedit(Client *c, const Seperator *sep)
); );
return; return;
} }
} else if (!strcasecmp(sep->arg[1], "emoteid")) {
if (sep->IsNumber(2)) {
const uint32 emote_id = Strings::ToUnsignedInt(sep->arg[2]);
n.emoteid = emote_id;
d = fmt::format(
"{} now has an Emote ID of {}.",
npc_id_string,
Strings::Commify(emote_id)
);
} else {
c->Message(
Chat::White,
"Usage: #npcedit emoteid [Emote ID] - Sets an NPC's Emote ID"
);
return;
}
} else if (!strcasecmp(sep->arg[1], "spellscale")) { } else if (!strcasecmp(sep->arg[1], "spellscale")) {
if (sep->IsNumber(2)) { if (sep->IsNumber(2)) {
auto spell_scale = Strings::ToUnsignedInt(sep->arg[2]); auto spell_scale = Strings::ToUnsignedInt(sep->arg[2]);
@ -1720,6 +1736,7 @@ void SendNPCEditSubCommands(Client *c)
c->Message(Chat::White, "Usage: #npcedit version [Version] - Sets an NPC's Version"); c->Message(Chat::White, "Usage: #npcedit version [Version] - Sets an NPC's Version");
c->Message(Chat::White, "Usage: #npcedit maxlevel [Max Level] - Sets an NPC's Maximum Level"); c->Message(Chat::White, "Usage: #npcedit maxlevel [Max Level] - Sets an NPC's Maximum Level");
c->Message(Chat::White, "Usage: #npcedit scalerate [Scale Rate] - Sets an NPC's Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]"); c->Message(Chat::White, "Usage: #npcedit scalerate [Scale Rate] - Sets an NPC's Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]");
c->Message(Chat::White, "Usage: #npcedit emoteid [Emote ID] - Sets an NPC's Emote ID");
c->Message(Chat::White, "Usage: #npcedit spellscale [Scale Rate] - Sets an NPC's Spell Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]"); c->Message(Chat::White, "Usage: #npcedit spellscale [Scale Rate] - Sets an NPC's Spell Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]");
c->Message(Chat::White, "Usage: #npcedit healscale [Scale Rate] - Sets an NPC's Heal Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]"); c->Message(Chat::White, "Usage: #npcedit healscale [Scale Rate] - Sets an NPC's Heal Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]");
c->Message(Chat::White, "Usage: #npcedit no_target [Flag] - Sets an NPC's No Target Hotkey Flag [0 = Not Targetable with Target Hotkey, 1 = Targetable with Target Hotkey]"); c->Message(Chat::White, "Usage: #npcedit no_target [Flag] - Sets an NPC's No Target Hotkey Flag [0 = Not Targetable with Target Hotkey, 1 = Targetable with Target Hotkey]");

View File

@ -1800,9 +1800,9 @@ void Mob::AI_Event_Engaged(Mob *attacker, bool yell_for_help)
parse->EventNPC(EVENT_COMBAT, CastToNPC(), attacker, "1", 0); parse->EventNPC(EVENT_COMBAT, CastToNPC(), attacker, "1", 0);
} }
auto emote_id = GetEmoteID(); const uint32 emote_id = GetEmoteID();
if (emote_id) { if (emote_id) {
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid, attacker); CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emote_id, attacker);
} }
std::string mob_name = GetCleanName(); std::string mob_name = GetCleanName();
@ -1843,14 +1843,13 @@ void Mob::AI_Event_NoLongerEngaged() {
SetAssistAggro(false); SetAssistAggro(false);
if (CastToNPC()->GetCombatEvent() && GetHP() > 0) { if (CastToNPC()->GetCombatEvent() && GetHP() > 0) {
if (entity_list.GetNPCByID(GetID())) { if (entity_list.GetNPCByID(GetID())) {
auto emote_id = CastToNPC()->GetEmoteID();
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_COMBAT)) { if (parse->HasQuestSub(GetNPCTypeID(), EVENT_COMBAT)) {
parse->EventNPC(EVENT_COMBAT, CastToNPC(), nullptr, "0", 0); parse->EventNPC(EVENT_COMBAT, CastToNPC(), nullptr, "0", 0);
} }
const uint32 emote_id = CastToNPC()->GetEmoteID();
if (emote_id) { if (emote_id) {
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::LeaveCombat, emoteid); CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::LeaveCombat, emote_id);
} }
m_combat_record.Stop(); m_combat_record.Stop();
@ -2120,7 +2119,7 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
if (m_target == GetTarget()) { if (m_target == GetTarget()) {
continue; continue;
} }
if (m_target->IsCorpse()) { if (m_target->IsCorpse()) {
LogAggroDetail("[{}] is on [{}]'s rampage list", m_target->GetCleanName(), GetCleanName()); LogAggroDetail("[{}] is on [{}]'s rampage list", m_target->GetCleanName(), GetCleanName());
RemoveFromRampageList(m_target, true); RemoveFromRampageList(m_target, true);

View File

@ -1113,9 +1113,9 @@ void NPC::UpdateEquipmentLight()
} }
void NPC::Depop(bool start_spawn_timer) { void NPC::Depop(bool start_spawn_timer) {
const auto emote_id = GetEmoteID(); const uint32 emote_id = GetEmoteID();
if (emote_id) { if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn, emoteid); DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn, emote_id);
} }
if (IsNPC()) { if (IsNPC()) {
@ -3070,72 +3070,75 @@ void NPC::SendPayload(int payload_id, std::string payload_value)
} }
} }
NPC_Emote_Struct* NPC::GetNPCEmote(uint32 emoteid, uint8 event_) { NPC_Emote_Struct* NPC::GetNPCEmote(uint32 emote_id, uint8 event_) {
std::vector<NPC_Emote_Struct *> emotes; std::vector<NPC_Emote_Struct*> emotes;
for (auto &e: zone->npc_emote_list) {
NPC_Emote_Struct *nes = e; for (const auto &e : zone->npc_emote_list) {
if (emoteid == nes->emoteid && event_ == nes->event_) { auto nes = e;
emotes.push_back(e);
if (nes->emoteid == emote_id && nes->event_ == event_) {
emotes.emplace_back(e);
} }
} }
if (emotes.empty()) { if (emotes.empty()) {
return nullptr; return nullptr;
} } else if (emotes.size() == 1) {
else if (emotes.size() == 1) { return emotes.front();
return emotes[0];
} }
int index = zone->random.Roll0(emotes.size()); const int index = zone->random.Roll0(emotes.size());
return emotes[index]; return emotes[index];
} }
void NPC::DoNPCEmote(uint8 event_, uint32 emoteid, Mob* target) void NPC::DoNPCEmote(uint8 event_, uint32 emote_id, Mob* t)
{ {
if (emoteid == 0) { if (!emote_id) {
return; return;
} }
NPC_Emote_Struct *nes = GetNPCEmote(emoteid, event_); auto e = GetNPCEmote(emote_id, event_);
if (nes == nullptr) { if (!e) {
return; return;
} }
std::string processed = nes->text; std::string processed = e->text;
// Mob Variables
Strings::FindReplace(processed, "$mname", GetCleanName()); Strings::FindReplace(processed, "$mname", GetCleanName());
Strings::FindReplace(processed, "$mracep", GetRacePlural() = GetClass()); Strings::FindReplace(processed, "$mracep", GetRacePlural());
Strings::FindReplace(processed, "$mrace", GetPlayerRaceName(GetRace())); Strings::FindReplace(processed, "$mrace", GetPlayerRaceName(GetRace()));
Strings::FindReplace(processed, "$mclass", GetClassIDName(GetClass())); Strings::FindReplace(processed, "$mclass", GetClassIDName(GetClass()));
if (target) { Strings::FindReplace(processed, "$mclassp", GetClassPlural());
Strings::FindReplace(processed, "$name", target->GetCleanName());
Strings::FindReplace(processed, "$racep", GetRacePlural() = target->GetClass());
Strings::FindReplace(processed, "$race", GetPlayerRaceName(target->GetRace()));
Strings::FindReplace(processed, "$class", GetClassIDName(target->GetClass()));
}
else {
Strings::FindReplace(processed, "$name", "foe");
Strings::FindReplace(processed, "$race", "race");
Strings::FindReplace(processed, "$racep", "races");
Strings::FindReplace(processed, "$class", "class");
}
if (emoteid == nes->emoteid) { // Target Variables
if (event_ == EQ::constants::EmoteEventTypes::Hailed && target) { Strings::FindReplace(processed, "$name", t ? t->GetCleanName() : "foe");
DoQuestPause(target); Strings::FindReplace(processed, "$class", t ? GetClassIDName(t->GetClass()) : "class");
Strings::FindReplace(processed, "$classp", t ? t->GetClassPlural() : "classes");
Strings::FindReplace(processed, "$race", t ? GetPlayerRaceName(t->GetRace()) : "race");
Strings::FindReplace(processed, "$racep", t ? t->GetRacePlural() : "races");
if (emoteid == e->emoteid) {
if (event_ == EQ::constants::EmoteEventTypes::Hailed && t) {
DoQuestPause(t);
} }
if (nes->type == 1) { if (e->type == EQ::constants::EmoteTypes::Say) {
Emote("%s", processed.c_str()); Say(processed.c_str());
} } else if (e->type == EQ::constants::EmoteTypes::Emote) {
else if (nes->type == 2) { Emote(processed.c_str());
Shout("%s", processed.c_str()); } else if (e->type == EQ::constants::EmoteTypes::Shout) {
} Shout(processed.c_str());
else if (nes->type == 3) { } else if (e->type == EQ::constants::EmoteTypes::Proximity) {
entity_list.MessageCloseString(this, true, 200, 10, GENERIC_STRING, processed.c_str()); entity_list.MessageCloseString(
} this,
else { true,
Say("%s", processed.c_str()); 200,
Chat::NPCQuestSay,
GENERIC_STRING,
processed.c_str()
);
} }
} }
} }

View File

@ -475,8 +475,8 @@ public:
Timer *GetRefaceTimer() const { return reface_timer; } Timer *GetRefaceTimer() const { return reface_timer; }
const uint32 GetAltCurrencyType() const { return NPCTypedata->alt_currency_type; } const uint32 GetAltCurrencyType() const { return NPCTypedata->alt_currency_type; }
NPC_Emote_Struct* GetNPCEmote(uint32 emoteid, uint8 event_); NPC_Emote_Struct* GetNPCEmote(uint32 emote_id, uint8 event_);
void DoNPCEmote(uint8 event_, uint32 emoteid, Mob* target = nullptr); void DoNPCEmote(uint8 event_, uint32 emote_id, Mob* t = nullptr);
bool CanTalk(); bool CanTalk();
void DoQuestPause(Mob *other); void DoQuestPause(Mob *other);

View File

@ -62,6 +62,7 @@
#include "../common/repositories/ldon_trap_entries_repository.h" #include "../common/repositories/ldon_trap_entries_repository.h"
#include "../common/repositories/ldon_trap_templates_repository.h" #include "../common/repositories/ldon_trap_templates_repository.h"
#include "../common/repositories/respawn_times_repository.h" #include "../common/repositories/respawn_times_repository.h"
#include "../common/repositories/npc_emotes_repository.h"
#include "../common/serverinfo.h" #include "../common/serverinfo.h"
#include <time.h> #include <time.h>
@ -2570,27 +2571,29 @@ void Zone::DoAdventureActions()
} }
void Zone::LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* NPCEmoteList) void Zone::LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* v)
{ {
v->clear();
NPCEmoteList->clear(); const auto& l = NpcEmotesRepository::All(content_db);
const std::string query = "SELECT emoteid, event_, type, text FROM npc_emotes";
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
return;
}
for (auto row = results.begin(); row != results.end(); ++row) for (const auto& e : l) {
{ auto n = new NPC_Emote_Struct;
auto nes = new NPC_Emote_Struct;
nes->emoteid = Strings::ToInt(row[0]);
nes->event_ = Strings::ToInt(row[1]);
nes->type = Strings::ToInt(row[2]);
strn0cpy(nes->text, row[3], sizeof(nes->text));
NPCEmoteList->push_back(nes);
}
LogInfo("Loaded [{}] npc emotes", Strings::Commify(results.RowCount())); n->emoteid = e.emoteid;
n->event_ = e.event_;
n->type = e.type;
strn0cpy(n->text, e.text.c_str(), sizeof(n->text));
v->push_back(n);
}
LogInfo(
"Loaded [{}] NPC Emote{}",
Strings::Commify(l.size()),
l.size() != 1 ? "s" : ""
);
} }

View File

@ -274,7 +274,7 @@ public:
void LoadMercSpells(); void LoadMercSpells();
void LoadMercTemplates(); void LoadMercTemplates();
void LoadNewMerchantData(uint32 merchantid); void LoadNewMerchantData(uint32 merchantid);
void LoadNPCEmotes(std::vector<NPC_Emote_Struct *> *NPCEmoteList); void LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* v);
void LoadTempMerchantData(); void LoadTempMerchantData();
void LoadVeteranRewards(); void LoadVeteranRewards();
void LoadZoneDoors(); void LoadZoneDoors();