[NPC] Support for multiple emotes per type, emote variables (#3801)

* [forage rule feature] add a rule to disabled using common_food_ids from the list in forage.cpp.  currently set to enabled.

* NPC database emotes now supports basic variables. More than one variable can be used at a time.

* Format manifest

* Formatting

* Formatting

* Formatting

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
regneq
2023-12-24 21:28:57 -08:00
committed by GitHub
parent 6396a6fbef
commit 25872203ff
13 changed files with 88 additions and 58 deletions
+4 -4
View File
@@ -1820,7 +1820,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
auto emote_id = killerMob->GetEmoteID();
if (emote_id) {
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid);
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid, this);
}
killerMob->TrySpellOnKill(killed_level, spell);
@@ -2710,7 +2710,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
if (IsNPC()) {
auto emote_id = GetEmoteID();
if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid);
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid, killer_mob);
}
}
@@ -2721,7 +2721,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
auto emote_id = oos->GetEmoteID();
if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id);
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
}
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell);
@@ -2799,7 +2799,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
ApplyIllusionToCorpse(illusion_spell_id, corpse);
if (killer != 0 && emoteid != 0)
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid);
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer);
if (killer != 0 && killer->IsClient()) {
corpse->AllowPlayerLoot(killer, 0);
if (killer->IsGrouped()) {
+1 -1
View File
@@ -6172,7 +6172,7 @@ void Client::CheckEmoteHail(NPC* n, const char* message)
const auto emote_id = n->GetEmoteID();
if (emote_id) {
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id);
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id, this);
}
}
+2 -10
View File
@@ -7,10 +7,7 @@ void FindEmote(Client *c, const Seperator *sep)
if (sep->IsNumber(2)) {
auto emote_id = Strings::ToUnsignedInt(sep->arg[2]);
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
auto &e = iterator.GetData();
for (auto& e : zone->npc_emote_list) {
if (emote_id == e->emoteid) {
c->Message(
Chat::White,
@@ -40,7 +37,6 @@ void FindEmote(Client *c, const Seperator *sep)
break;
}
iterator.Advance();
}
if (found_count == 50) {
@@ -70,10 +66,7 @@ void FindEmote(Client *c, const Seperator *sep)
const std::string& search_criteria = sep->argplus[2];
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
auto &e = iterator.GetData();
for (auto& e : zone->npc_emote_list) {
const std::string& current_text = Strings::ToLower(e->text);
@@ -106,7 +99,6 @@ void FindEmote(Client *c, const Seperator *sep)
break;
}
iterator.Advance();
}
if (found_count == 50) {
+1 -5
View File
@@ -12,10 +12,7 @@ void ShowEmotes(Client *c, const Seperator *sep)
uint32 emote_count = 0;
const uint32 emote_id = t->GetEmoteID();
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
const auto& e = iterator.GetData();
for (auto& e : zone->npc_emote_list) {
if (emote_id == e->emoteid) {
c->Message(
Chat::White,
@@ -41,7 +38,6 @@ void ShowEmotes(Client *c, const Seperator *sep)
emote_count++;
}
iterator.Advance();
}
c->Message(
+1 -1
View File
@@ -1800,7 +1800,7 @@ void Mob::AI_Event_Engaged(Mob *attacker, bool yell_for_help)
auto emote_id = GetEmoteID();
if (emote_id) {
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid);
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid, attacker);
}
std::string mob_name = GetCleanName();
+54 -24
View File
@@ -3046,42 +3046,72 @@ void NPC::SendPayload(int payload_id, std::string payload_value)
}
NPC_Emote_Struct* NPC::GetNPCEmote(uint32 emoteid, uint8 event_) {
LinkedListIterator<NPC_Emote_Struct*> iterator(zone->NPCEmoteList);
iterator.Reset();
while(iterator.MoreElements())
{
NPC_Emote_Struct* nes = iterator.GetData();
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_) {
return nes;
emotes.push_back(e);
}
iterator.Advance();
}
return nullptr;
if (emotes.empty()) {
return nullptr;
}
else if (emotes.size() == 1) {
return emotes[0];
}
int index = zone->random.Roll0(emotes.size());
return emotes[index];
}
void NPC::DoNPCEmote(uint8 event_, uint32 emoteid)
void NPC::DoNPCEmote(uint8 event_, uint32 emoteid, Mob* target)
{
if (emoteid == 0)
{
if (emoteid == 0) {
return;
}
NPC_Emote_Struct* nes = GetNPCEmote(emoteid,event_);
if(nes == nullptr)
{
NPC_Emote_Struct *nes = GetNPCEmote(emoteid, event_);
if (nes == nullptr) {
return;
}
if(emoteid == nes->emoteid)
{
if(nes->type == 1)
Emote("%s",nes->text);
else if(nes->type == 2)
Shout("%s",nes->text);
else if(nes->type == 3)
entity_list.MessageCloseString(this, true, 200, 10, GENERIC_STRING, nes->text);
else
Say("%s",nes->text);
std::string processed = nes->text;
Strings::FindReplace(processed, "$mname", GetCleanName());
Strings::FindReplace(processed, "$mracep", GetRacePlural() = GetClass());
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");
}
if (emoteid == nes->emoteid) {
if (event_ == EQ::constants::EmoteEventTypes::Hailed && target) {
DoQuestPause(target);
}
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());
}
}
}
+1 -1
View File
@@ -476,7 +476,7 @@ public:
const uint32 GetAltCurrencyType() const { return NPCTypedata->alt_currency_type; }
NPC_Emote_Struct* GetNPCEmote(uint32 emoteid, uint8 event_);
void DoNPCEmote(uint8 event_, uint32 emoteid);
void DoNPCEmote(uint8 event_, uint32 emoteid, Mob* target = nullptr);
bool CanTalk();
void DoQuestPause(Mob *other);
+1 -1
View File
@@ -2015,7 +2015,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
{
if (zone && zone->IsLoaded()) {
zone->SendReloadMessage("NPC Emotes");
zone->LoadNPCEmotes(&zone->NPCEmoteList);
zone->LoadNPCEmotes(&zone->npc_emote_list);
}
break;
}
+7 -7
View File
@@ -1056,7 +1056,7 @@ Zone::~Zone() {
safe_delete_array(short_name);
safe_delete_array(long_name);
safe_delete(Weather_Timer);
NPCEmoteList.Clear();
npc_emote_list.clear();
zone_point_list.Clear();
entity_list.Clear();
ClearBlockedSpells();
@@ -1152,7 +1152,7 @@ bool Zone::Init(bool is_static) {
LoadLDoNTrapEntries();
LoadVeteranRewards();
LoadAlternateCurrencies();
LoadNPCEmotes(&NPCEmoteList);
LoadNPCEmotes(&npc_emote_list);
LoadAlternateAdvancement();
@@ -1233,8 +1233,8 @@ void Zone::ReloadStaticData() {
LoadVeteranRewards();
LoadAlternateCurrencies();
NPCEmoteList.Clear();
LoadNPCEmotes(&NPCEmoteList);
npc_emote_list.clear();
LoadNPCEmotes(&npc_emote_list);
//load the zone config file.
if (!LoadZoneCFG(GetShortName(), GetInstanceVersion())) { // try loading the zone name...
@@ -2548,10 +2548,10 @@ void Zone::DoAdventureActions()
}
void Zone::LoadNPCEmotes(LinkedList<NPC_Emote_Struct*>* NPCEmoteList)
void Zone::LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* NPCEmoteList)
{
NPCEmoteList->Clear();
NPCEmoteList->clear();
const std::string query = "SELECT emoteid, event_, type, text FROM npc_emotes";
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
@@ -2565,7 +2565,7 @@ void Zone::LoadNPCEmotes(LinkedList<NPC_Emote_Struct*>* NPCEmoteList)
nes->event_ = Strings::ToInt(row[1]);
nes->type = Strings::ToInt(row[2]);
strn0cpy(nes->text, row[3], sizeof(nes->text));
NPCEmoteList->Insert(nes);
NPCEmoteList->push_back(nes);
}
LogInfo("Loaded [{}] npc emotes", Strings::Commify(results.RowCount()));
+2 -2
View File
@@ -185,7 +185,7 @@ public:
DynamicZone *GetDynamicZone();
IPathfinder *pathing;
LinkedList<NPC_Emote_Struct *> NPCEmoteList;
std::vector<NPC_Emote_Struct *> npc_emote_list;
LinkedList<Spawn2 *> spawn2_list;
LinkedList<ZonePoint *> zone_point_list;
std::vector<ZonePointsRepository::ZonePoints> virtual_zone_point_list;
@@ -282,7 +282,7 @@ public:
void LoadMercSpells();
void LoadMercTemplates();
void LoadNewMerchantData(uint32 merchantid);
void LoadNPCEmotes(LinkedList<NPC_Emote_Struct *> *NPCEmoteList);
void LoadNPCEmotes(std::vector<NPC_Emote_Struct *> *NPCEmoteList);
void LoadTempMerchantData();
void LoadTickItems();
void LoadVeteranRewards();