mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 18:51:29 +00:00
[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:
parent
6396a6fbef
commit
25872203ff
@ -5133,6 +5133,16 @@ CHANGE COLUMN `slot` `inventory_slot` mediumint(9) NOT NULL DEFAULT -1 AFTER `st
|
|||||||
|
|
||||||
ALTER TABLE `starting_items`
|
ALTER TABLE `starting_items`
|
||||||
CHANGE COLUMN `temporary` `class_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `id`;
|
CHANGE COLUMN `temporary` `class_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `id`;
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9248,
|
||||||
|
.description = "2023_12_22_drop_npc_emotes_index.sql",
|
||||||
|
.check = "show index from npc_emotes where key_name = 'emoteid'",
|
||||||
|
.condition = "not_empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `npc_emotes` DROP INDEX `emoteid`;
|
||||||
)"
|
)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include "../../strings.h"
|
#include "../../strings.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
|
||||||
class BaseNpcEmotesRepository {
|
class BaseNpcEmotesRepository {
|
||||||
public:
|
public:
|
||||||
struct NpcEmotes {
|
struct NpcEmotes {
|
||||||
@ -120,8 +121,9 @@ public:
|
|||||||
{
|
{
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"{} WHERE id = {} LIMIT 1",
|
"{} WHERE {} = {} LIMIT 1",
|
||||||
BaseSelect(),
|
BaseSelect(),
|
||||||
|
PrimaryKey(),
|
||||||
npc_emotes_id
|
npc_emotes_id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9247
|
#define CURRENT_BINARY_DATABASE_VERSION 9248
|
||||||
|
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
|
||||||
|
|
||||||
|
|||||||
@ -1820,7 +1820,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
|||||||
|
|
||||||
auto emote_id = killerMob->GetEmoteID();
|
auto emote_id = killerMob->GetEmoteID();
|
||||||
if (emote_id) {
|
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);
|
killerMob->TrySpellOnKill(killed_level, spell);
|
||||||
@ -2710,7 +2710,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
|||||||
if (IsNPC()) {
|
if (IsNPC()) {
|
||||||
auto emote_id = GetEmoteID();
|
auto emote_id = GetEmoteID();
|
||||||
if (emote_id) {
|
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();
|
auto emote_id = oos->GetEmoteID();
|
||||||
if (emote_id) {
|
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) {
|
if (killer_mob) {
|
||||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
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);
|
ApplyIllusionToCorpse(illusion_spell_id, corpse);
|
||||||
|
|
||||||
if (killer != 0 && emoteid != 0)
|
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()) {
|
if (killer != 0 && killer->IsClient()) {
|
||||||
corpse->AllowPlayerLoot(killer, 0);
|
corpse->AllowPlayerLoot(killer, 0);
|
||||||
if (killer->IsGrouped()) {
|
if (killer->IsGrouped()) {
|
||||||
|
|||||||
@ -6172,7 +6172,7 @@ void Client::CheckEmoteHail(NPC* n, const char* message)
|
|||||||
|
|
||||||
const auto emote_id = n->GetEmoteID();
|
const auto emote_id = n->GetEmoteID();
|
||||||
if (emote_id) {
|
if (emote_id) {
|
||||||
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id);
|
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,10 +7,7 @@ void FindEmote(Client *c, const Seperator *sep)
|
|||||||
if (sep->IsNumber(2)) {
|
if (sep->IsNumber(2)) {
|
||||||
auto emote_id = Strings::ToUnsignedInt(sep->arg[2]);
|
auto emote_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||||
|
|
||||||
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
|
for (auto& e : zone->npc_emote_list) {
|
||||||
iterator.Reset();
|
|
||||||
while (iterator.MoreElements()) {
|
|
||||||
auto &e = iterator.GetData();
|
|
||||||
if (emote_id == e->emoteid) {
|
if (emote_id == e->emoteid) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
@ -40,7 +37,6 @@ void FindEmote(Client *c, const Seperator *sep)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator.Advance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_count == 50) {
|
if (found_count == 50) {
|
||||||
@ -70,10 +66,7 @@ void FindEmote(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
const std::string& search_criteria = sep->argplus[2];
|
const std::string& search_criteria = sep->argplus[2];
|
||||||
|
|
||||||
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
|
for (auto& e : zone->npc_emote_list) {
|
||||||
iterator.Reset();
|
|
||||||
while (iterator.MoreElements()) {
|
|
||||||
auto &e = iterator.GetData();
|
|
||||||
|
|
||||||
const std::string& current_text = Strings::ToLower(e->text);
|
const std::string& current_text = Strings::ToLower(e->text);
|
||||||
|
|
||||||
@ -106,7 +99,6 @@ void FindEmote(Client *c, const Seperator *sep)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator.Advance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_count == 50) {
|
if (found_count == 50) {
|
||||||
|
|||||||
@ -12,10 +12,7 @@ void ShowEmotes(Client *c, const Seperator *sep)
|
|||||||
uint32 emote_count = 0;
|
uint32 emote_count = 0;
|
||||||
const uint32 emote_id = t->GetEmoteID();
|
const uint32 emote_id = t->GetEmoteID();
|
||||||
|
|
||||||
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
|
for (auto& e : zone->npc_emote_list) {
|
||||||
iterator.Reset();
|
|
||||||
while (iterator.MoreElements()) {
|
|
||||||
const auto& e = iterator.GetData();
|
|
||||||
if (emote_id == e->emoteid) {
|
if (emote_id == e->emoteid) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
@ -41,7 +38,6 @@ void ShowEmotes(Client *c, const Seperator *sep)
|
|||||||
emote_count++;
|
emote_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator.Advance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c->Message(
|
c->Message(
|
||||||
|
|||||||
@ -1800,7 +1800,7 @@ void Mob::AI_Event_Engaged(Mob *attacker, bool yell_for_help)
|
|||||||
|
|
||||||
auto emote_id = GetEmoteID();
|
auto emote_id = GetEmoteID();
|
||||||
if (emote_id) {
|
if (emote_id) {
|
||||||
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid);
|
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid, attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mob_name = GetCleanName();
|
std::string mob_name = GetCleanName();
|
||||||
|
|||||||
76
zone/npc.cpp
76
zone/npc.cpp
@ -3046,42 +3046,72 @@ 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 emoteid, uint8 event_) {
|
||||||
LinkedListIterator<NPC_Emote_Struct*> iterator(zone->NPCEmoteList);
|
std::vector<NPC_Emote_Struct *> emotes;
|
||||||
iterator.Reset();
|
for (auto &e: zone->npc_emote_list) {
|
||||||
while(iterator.MoreElements())
|
NPC_Emote_Struct *nes = e;
|
||||||
{
|
|
||||||
NPC_Emote_Struct* nes = iterator.GetData();
|
|
||||||
if (emoteid == nes->emoteid && event_ == nes->event_) {
|
if (emoteid == nes->emoteid && event_ == nes->event_) {
|
||||||
return nes;
|
emotes.push_back(e);
|
||||||
}
|
}
|
||||||
iterator.Advance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (emotes.empty()) {
|
||||||
return nullptr;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPC_Emote_Struct* nes = GetNPCEmote(emoteid,event_);
|
NPC_Emote_Struct *nes = GetNPCEmote(emoteid, event_);
|
||||||
if(nes == nullptr)
|
if (nes == nullptr) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(emoteid == nes->emoteid)
|
std::string processed = nes->text;
|
||||||
{
|
Strings::FindReplace(processed, "$mname", GetCleanName());
|
||||||
if(nes->type == 1)
|
Strings::FindReplace(processed, "$mracep", GetRacePlural() = GetClass());
|
||||||
Emote("%s",nes->text);
|
Strings::FindReplace(processed, "$mrace", GetPlayerRaceName(GetRace()));
|
||||||
else if(nes->type == 2)
|
Strings::FindReplace(processed, "$mclass", GetClassIDName(GetClass()));
|
||||||
Shout("%s",nes->text);
|
if (target) {
|
||||||
else if(nes->type == 3)
|
Strings::FindReplace(processed, "$name", target->GetCleanName());
|
||||||
entity_list.MessageCloseString(this, true, 200, 10, GENERIC_STRING, nes->text);
|
Strings::FindReplace(processed, "$racep", GetRacePlural() = target->GetClass());
|
||||||
else
|
Strings::FindReplace(processed, "$race", GetPlayerRaceName(target->GetRace()));
|
||||||
Say("%s",nes->text);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -476,7 +476,7 @@ public:
|
|||||||
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 emoteid, uint8 event_);
|
||||||
void DoNPCEmote(uint8 event_, uint32 emoteid);
|
void DoNPCEmote(uint8 event_, uint32 emoteid, Mob* target = nullptr);
|
||||||
bool CanTalk();
|
bool CanTalk();
|
||||||
void DoQuestPause(Mob *other);
|
void DoQuestPause(Mob *other);
|
||||||
|
|
||||||
|
|||||||
@ -2015,7 +2015,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
{
|
{
|
||||||
if (zone && zone->IsLoaded()) {
|
if (zone && zone->IsLoaded()) {
|
||||||
zone->SendReloadMessage("NPC Emotes");
|
zone->SendReloadMessage("NPC Emotes");
|
||||||
zone->LoadNPCEmotes(&zone->NPCEmoteList);
|
zone->LoadNPCEmotes(&zone->npc_emote_list);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1056,7 +1056,7 @@ Zone::~Zone() {
|
|||||||
safe_delete_array(short_name);
|
safe_delete_array(short_name);
|
||||||
safe_delete_array(long_name);
|
safe_delete_array(long_name);
|
||||||
safe_delete(Weather_Timer);
|
safe_delete(Weather_Timer);
|
||||||
NPCEmoteList.Clear();
|
npc_emote_list.clear();
|
||||||
zone_point_list.Clear();
|
zone_point_list.Clear();
|
||||||
entity_list.Clear();
|
entity_list.Clear();
|
||||||
ClearBlockedSpells();
|
ClearBlockedSpells();
|
||||||
@ -1152,7 +1152,7 @@ bool Zone::Init(bool is_static) {
|
|||||||
LoadLDoNTrapEntries();
|
LoadLDoNTrapEntries();
|
||||||
LoadVeteranRewards();
|
LoadVeteranRewards();
|
||||||
LoadAlternateCurrencies();
|
LoadAlternateCurrencies();
|
||||||
LoadNPCEmotes(&NPCEmoteList);
|
LoadNPCEmotes(&npc_emote_list);
|
||||||
|
|
||||||
LoadAlternateAdvancement();
|
LoadAlternateAdvancement();
|
||||||
|
|
||||||
@ -1233,8 +1233,8 @@ void Zone::ReloadStaticData() {
|
|||||||
|
|
||||||
LoadVeteranRewards();
|
LoadVeteranRewards();
|
||||||
LoadAlternateCurrencies();
|
LoadAlternateCurrencies();
|
||||||
NPCEmoteList.Clear();
|
npc_emote_list.clear();
|
||||||
LoadNPCEmotes(&NPCEmoteList);
|
LoadNPCEmotes(&npc_emote_list);
|
||||||
|
|
||||||
//load the zone config file.
|
//load the zone config file.
|
||||||
if (!LoadZoneCFG(GetShortName(), GetInstanceVersion())) { // try loading the zone name...
|
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";
|
const std::string query = "SELECT emoteid, event_, type, text FROM npc_emotes";
|
||||||
auto results = content_db.QueryDatabase(query);
|
auto results = content_db.QueryDatabase(query);
|
||||||
if (!results.Success()) {
|
if (!results.Success()) {
|
||||||
@ -2565,7 +2565,7 @@ void Zone::LoadNPCEmotes(LinkedList<NPC_Emote_Struct*>* NPCEmoteList)
|
|||||||
nes->event_ = Strings::ToInt(row[1]);
|
nes->event_ = Strings::ToInt(row[1]);
|
||||||
nes->type = Strings::ToInt(row[2]);
|
nes->type = Strings::ToInt(row[2]);
|
||||||
strn0cpy(nes->text, row[3], sizeof(nes->text));
|
strn0cpy(nes->text, row[3], sizeof(nes->text));
|
||||||
NPCEmoteList->Insert(nes);
|
NPCEmoteList->push_back(nes);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogInfo("Loaded [{}] npc emotes", Strings::Commify(results.RowCount()));
|
LogInfo("Loaded [{}] npc emotes", Strings::Commify(results.RowCount()));
|
||||||
|
|||||||
@ -185,7 +185,7 @@ public:
|
|||||||
DynamicZone *GetDynamicZone();
|
DynamicZone *GetDynamicZone();
|
||||||
|
|
||||||
IPathfinder *pathing;
|
IPathfinder *pathing;
|
||||||
LinkedList<NPC_Emote_Struct *> NPCEmoteList;
|
std::vector<NPC_Emote_Struct *> npc_emote_list;
|
||||||
LinkedList<Spawn2 *> spawn2_list;
|
LinkedList<Spawn2 *> spawn2_list;
|
||||||
LinkedList<ZonePoint *> zone_point_list;
|
LinkedList<ZonePoint *> zone_point_list;
|
||||||
std::vector<ZonePointsRepository::ZonePoints> virtual_zone_point_list;
|
std::vector<ZonePointsRepository::ZonePoints> virtual_zone_point_list;
|
||||||
@ -282,7 +282,7 @@ public:
|
|||||||
void LoadMercSpells();
|
void LoadMercSpells();
|
||||||
void LoadMercTemplates();
|
void LoadMercTemplates();
|
||||||
void LoadNewMerchantData(uint32 merchantid);
|
void LoadNewMerchantData(uint32 merchantid);
|
||||||
void LoadNPCEmotes(LinkedList<NPC_Emote_Struct *> *NPCEmoteList);
|
void LoadNPCEmotes(std::vector<NPC_Emote_Struct *> *NPCEmoteList);
|
||||||
void LoadTempMerchantData();
|
void LoadTempMerchantData();
|
||||||
void LoadTickItems();
|
void LoadTickItems();
|
||||||
void LoadVeteranRewards();
|
void LoadVeteranRewards();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user