[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()
{
static const std::map<uint8, std::string> emote_type_map = {
{ EmoteTypes::Say, "Say" },
{ EmoteTypes::Emote, "Emote" },
{ EmoteTypes::Shout, "Shout" },
{ EmoteTypes::Proximity, "Proximity" }
@ -572,7 +573,7 @@ const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
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();
}

View File

@ -350,6 +350,7 @@ namespace EQ
};
enum EmoteTypes : uint8 {
Say,
Emote,
Shout,
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);
}
auto emote_id = killerMob->GetEmoteID();
const uint32 emote_id = killerMob->GetEmoteID();
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);
@ -2725,7 +2725,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.RemoveFromAutoXTargets(this);
uint32 emoteid = GetEmoteID();
const uint32 emote_id = GetEmoteID();
corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata,
level > 54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS)
: RuleI(NPC, MinorNPCCorpseDecayTimeMS));
@ -2740,8 +2740,8 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
SetID(0);
ApplyIllusionToCorpse(illusion_spell_id, corpse);
if (killer != 0 && emoteid != 0)
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer);
if (killer != 0 && emote_id)
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emote_id, killer);
if (killer != 0 && killer->IsClient()) {
corpse->AllowPlayerLoot(killer, 0);
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
if (oos) {
if (IsNPC()) {
auto emote_id = GetEmoteID();
const uint32 emote_id = GetEmoteID();
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);
}
auto emote_id = oos->GetEmoteID();
const uint32 emote_id = oos->GetEmoteID();
if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
}
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell);
}
@ -4308,7 +4309,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
} 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
}
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.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)
) &&
finishing_blow_level &&
finishing_blow_damage &&
finishing_blow_level &&
finishing_blow_damage &&
defender->GetLevel() <= finishing_blow_level &&
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)) {
Attack(target, hand, false, false, IsFromSpell);
if (zone->random.Roll(flurry_chance)) {
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)
{
if (
!Strings::BeginsWith(message, "hail") &&
!Strings::BeginsWith(message, "Hail")
) {
if (!Strings::BeginsWith(Strings::ToLower(message), "hail")) {
return;
}
@ -6214,7 +6211,7 @@ void Client::CheckEmoteHail(NPC* n, const char* message)
return;
}
const auto emote_id = n->GetEmoteID();
const uint32 emote_id = n->GetEmoteID();
if (emote_id) {
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);
}
const auto emote_id = npc->GetEmoteID();
if (emote_id != 0) {
const uint32 emote_id = npc->GetEmoteID();
if (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;
}
} 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")) {
if (sep->IsNumber(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 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 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 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]");

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

View File

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

View File

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

View File

@ -62,6 +62,7 @@
#include "../common/repositories/ldon_trap_entries_repository.h"
#include "../common/repositories/ldon_trap_templates_repository.h"
#include "../common/repositories/respawn_times_repository.h"
#include "../common/repositories/npc_emotes_repository.h"
#include "../common/serverinfo.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 std::string query = "SELECT emoteid, event_, type, text FROM npc_emotes";
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
return;
}
const auto& l = NpcEmotesRepository::All(content_db);
for (auto row = results.begin(); row != results.end(); ++row)
{
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);
}
for (const auto& e : l) {
auto n = new NPC_Emote_Struct;
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 LoadMercTemplates();
void LoadNewMerchantData(uint32 merchantid);
void LoadNPCEmotes(std::vector<NPC_Emote_Struct *> *NPCEmoteList);
void LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* v);
void LoadTempMerchantData();
void LoadVeteranRewards();
void LoadZoneDoors();