diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp index 8e26f2fb6..4d60b4297 100644 --- a/common/emu_constants.cpp +++ b/common/emu_constants.cpp @@ -533,3 +533,49 @@ std::string EQ::constants::GetWeatherTypeName(uint8 weather_type) return std::string(); } + +const std::map &EQ::constants::GetEmoteEventTypeMap() +{ + static const std::map emote_event_type_map = { + { EmoteEventTypes::LeaveCombat, "Leave Combat" }, + { EmoteEventTypes::EnterCombat, "Enter Combat" }, + { EmoteEventTypes::OnDeath, "On Death" }, + { EmoteEventTypes::AfterDeath, "After Death" }, + { EmoteEventTypes::Hailed, "Hailed" }, + { EmoteEventTypes::KilledPC, "Killed PC" }, + { EmoteEventTypes::KilledNPC, "Killed NPC" }, + { EmoteEventTypes::OnSpawn, "On Spawn" }, + { EmoteEventTypes::OnDespawn, "On Despawn" } + }; + + return emote_event_type_map; +} + +std::string EQ::constants::GetEmoteEventTypeName(uint8 emote_event_type) +{ + if (EQ::ValueWithin(emote_event_type, EmoteEventTypes::LeaveCombat, EmoteEventTypes::OnDespawn)) { + return EQ::constants::GetEmoteEventTypeMap().find(emote_event_type)->second; + } + + return std::string(); +} + +const std::map &EQ::constants::GetEmoteTypeMap() +{ + static const std::map emote_type_map = { + { EmoteTypes::Emote, "Emote" }, + { EmoteTypes::Shout, "Shout" }, + { EmoteTypes::Proximity, "Proximity" } + }; + + return emote_type_map; +} + +std::string EQ::constants::GetEmoteTypeName(uint8 emote_type) +{ + if (EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) { + return EQ::constants::GetEmoteTypeMap().find(emote_type)->second; + } + + return std::string(); +} diff --git a/common/emu_constants.h b/common/emu_constants.h index 06330f8dc..7eaf3837b 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -337,6 +337,24 @@ namespace EQ Snowing }; + enum EmoteEventTypes : uint8 { + LeaveCombat, + EnterCombat, + OnDeath, + AfterDeath, + Hailed, + KilledPC, + KilledNPC, + OnSpawn, + OnDespawn + }; + + enum EmoteTypes : uint8 { + Emote, + Shout, + Proximity + }; + const char *GetStanceName(StanceType stance_type); int ConvertStanceTypeToIndex(StanceType stance_type); @@ -373,6 +391,12 @@ namespace EQ extern const std::map& GetWeatherTypeMap(); std::string GetWeatherTypeName(uint8 weather_type); + extern const std::map& GetEmoteEventTypeMap(); + std::string GetEmoteEventTypeName(uint8 emote_event_type); + + extern const std::map& GetEmoteTypeMap(); + std::string GetEmoteTypeName(uint8 emote_type); + const int STANCE_TYPE_FIRST = stancePassive; const int STANCE_TYPE_LAST = stanceBurnAE; const int STANCE_TYPE_COUNT = stanceBurnAE; diff --git a/zone/attack.cpp b/zone/attack.cpp index 15925785e..f71ccbf43 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1802,7 +1802,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill uint32 emoteid = killerMob->GetEmoteID(); if (emoteid != 0) - killerMob->CastToNPC()->DoNPCEmote(KILLEDPC, emoteid); + killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid); killerMob->TrySpellOnKill(killed_level, spell); } @@ -2650,7 +2650,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(AFTERDEATH, emoteid); + corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid); if (killer != 0 && killer->IsClient()) { corpse->AllowPlayerLoot(killer, 0); if (killer->IsGrouped()) { @@ -2734,12 +2734,12 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy uint32 emoteid = GetEmoteID(); if (emoteid != 0) - DoNPCEmote(ONDEATH, emoteid); + DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid); if (oos->IsNPC()) { parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0); uint32 emoteid = oos->GetEmoteID(); if (emoteid != 0) - oos->CastToNPC()->DoNPCEmote(KILLEDNPC, emoteid); + oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emoteid); killer_mob->TrySpellOnKill(killed_level, spell); } } diff --git a/zone/client.cpp b/zone/client.cpp index 3cf149df9..ca887049f 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6249,7 +6249,7 @@ void Client::CheckEmoteHail(Mob *target, const char* message) } uint32 emoteid = target->GetEmoteID(); if(emoteid != 0) - target->CastToNPC()->DoNPCEmote(HAILED,emoteid); + target->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emoteid); } void Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z, uint8 count) diff --git a/zone/command.cpp b/zone/command.cpp index bd3087132..c470266bd 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -133,7 +133,7 @@ int command_init(void) command_add("dzkickplayers", "Removes all players from current expedition. (/kickplayers alternative for pre-RoF clients)", AccountStatus::Player, command_dzkickplayers) || command_add("editmassrespawn", "[name-search] [second-value] - Mass (Zone wide) NPC respawn timer editing command", AccountStatus::GMAdmin, command_editmassrespawn) || command_add("emote", "['name'/'world'/'zone'] [type] [message] - Send an emote message", AccountStatus::QuestTroupe, command_emote) || - command_add("emotesearch", "Searches NPC Emotes", AccountStatus::QuestTroupe, command_emotesearch) || + command_add("emotesearch", "[Search Criteria] - Search for NPC Emotes", AccountStatus::QuestTroupe, command_emotesearch) || command_add("emoteview", "Lists all NPC Emotes", AccountStatus::QuestTroupe, command_emoteview) || command_add("emptyinventory", "Clears your or your target's entire inventory (Equipment, General, Bank, and Shared Bank)", AccountStatus::GMImpossible, command_emptyinventory) || command_add("enablerecipe", "[Recipe ID] - Enables a Recipe", AccountStatus::QuestTroupe, command_enablerecipe) || diff --git a/zone/entity.cpp b/zone/entity.cpp index 7010f86b5..beca9aa3b 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -700,7 +700,7 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) uint32 emoteid = npc->GetEmoteID(); if (emoteid != 0) - npc->DoNPCEmote(ONSPAWN, emoteid); + npc->DoNPCEmote(EQ::constants::EmoteEventTypes::OnSpawn, emoteid); npc->SetSpawned(); if (SendSpawnPacket) { if (dontqueue) { // aka, SEND IT NOW BITCH! diff --git a/zone/gm_commands/emotesearch.cpp b/zone/gm_commands/emotesearch.cpp index c8dcc791f..5b8e9d09e 100755 --- a/zone/gm_commands/emotesearch.cpp +++ b/zone/gm_commands/emotesearch.cpp @@ -2,77 +2,141 @@ void command_emotesearch(Client *c, const Seperator *sep) { - if (sep->arg[1][0] == 0) { - c->Message(Chat::White, "Usage: #emotesearch [search string or emoteid]"); + auto arguments = sep->argnum; + if (!arguments) { + c->Message(Chat::White, "Usage: #emotesearch [Emote ID]"); + c->Message(Chat::White, "Usage: #emotesearch [Search Crteria]"); + return; } - else { - const char *search_criteria = sep->argplus[1]; - int count = 0; - if (Seperator::IsNumber(search_criteria)) { - uint32 emoteid = atoi(search_criteria); - LinkedListIterator iterator(zone->NPCEmoteList); - iterator.Reset(); - while (iterator.MoreElements()) { - NPC_Emote_Struct *nes = iterator.GetData(); - if (emoteid == nes->emoteid) { - c->Message( - Chat::White, - "EmoteID: %i Event: %i Type: %i Text: %s", - nes->emoteid, - nes->event_, - nes->type, - nes->text - ); - count++; - } - iterator.Advance(); + auto emote_count = 0; + auto emote_number = 1; + + std::string search_criteria = sep->argplus[1]; + bool found_by_id = false; + + if (!sep->IsNumber(1)) { + LinkedListIterator iterator(zone->NPCEmoteList); + iterator.Reset(); + while (iterator.MoreElements()) { + auto &e = iterator.GetData(); + auto current_text = Strings::ToLower(e->text); + + if (Strings::Contains(current_text, Strings::ToLower(search_criteria))) { + c->Message( + Chat::White, + fmt::format( + "Emote {} | Emote ID: {}", + emote_number, + e->emoteid + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Emote {} | Event: {} ({}) Type: {} ({})", + emote_number, + EQ::constants::GetEmoteEventTypeName(e->event_), + e->event_, + EQ::constants::GetEmoteTypeName(e->type), + e->type + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Emote {} | Text: {}", + emote_number, + e->text + ).c_str() + ); + + emote_count++; + emote_number++; } - if (count == 0) { - c->Message(Chat::White, "No emotes found."); - } - else { - c->Message(Chat::White, "%i emote(s) found", count); + + if (emote_count == 50) { + break; } + + iterator.Advance(); } - else { - char sText[64]; - char sCriteria[515]; - strn0cpy(sCriteria, search_criteria, sizeof(sCriteria)); - strupr(sCriteria); - char *pdest; + } else { + auto emote_id = std::stoul(search_criteria); + + LinkedListIterator iterator(zone->NPCEmoteList); + iterator.Reset(); + while (iterator.MoreElements()) { + auto &e = iterator.GetData(); + if (emote_id == e->emoteid) { + found_by_id = true; - LinkedListIterator iterator(zone->NPCEmoteList); - iterator.Reset(); - while (iterator.MoreElements()) { - NPC_Emote_Struct *nes = iterator.GetData(); - strn0cpy(sText, nes->text, sizeof(sText)); - strupr(sText); - pdest = strstr(sText, sCriteria); - if (pdest != nullptr) { - c->Message( - Chat::White, - "EmoteID: %i Event: %i Type: %i Text: %s", - nes->emoteid, - nes->event_, - nes->type, - nes->text - ); - count++; - } - if (count == 50) { - break; - } + c->Message( + Chat::White, + fmt::format( + "Emote {} | Event: {} ({}) Type: {} ({})", + emote_number, + EQ::constants::GetEmoteEventTypeName(e->event_), + e->event_, + EQ::constants::GetEmoteTypeName(e->type), + e->type + ).c_str() + ); - iterator.Advance(); + c->Message( + Chat::White, + fmt::format( + "Emote {} | Text: {}", + emote_number, + e->text + ).c_str() + ); + + emote_count++; + emote_number++; } - if (count == 50) { - c->Message(Chat::White, "50 emotes shown...too many results."); - } - else { - c->Message(Chat::White, "%i emote(s) found", count); + + if (emote_count == 50) { + break; } + + iterator.Advance(); } } + + auto found_string = ( + found_by_id ? + fmt::format("ID {}", search_criteria) : + search_criteria + ); + + if (!emote_count) { + c->Message( + Chat::White, + fmt::format( + "No Emotes found matching {}.", + found_string + ).c_str() + ); + } else if (emote_count == 50) { + c->Message( + Chat::White, + fmt::format( + "50 Emotes shown matching {}, too many results.", + found_string + ).c_str() + ); + } else { + c->Message( + Chat::White, + fmt::format( + "{} Emote{} found matching {}.", + emote_count, + emote_count != 1 ? "s" : "", + found_string + ).c_str() + ); + } } - diff --git a/zone/gm_commands/emoteview.cpp b/zone/gm_commands/emoteview.cpp index afbec21aa..c1116f026 100755 --- a/zone/gm_commands/emoteview.cpp +++ b/zone/gm_commands/emoteview.cpp @@ -3,37 +3,70 @@ void command_emoteview(Client *c, const Seperator *sep) { if (!c->GetTarget() || !c->GetTarget()->IsNPC()) { - c->Message(Chat::White, "You must target a NPC to view their emotes."); + c->Message(Chat::White, "You must target an NPC to view their emotes."); return; } - if (c->GetTarget() && c->GetTarget()->IsNPC()) { - int count = 0; - int emoteid = c->GetTarget()->CastToNPC()->GetEmoteID(); + auto target = c->GetTarget()->CastToNPC(); - LinkedListIterator iterator(zone->NPCEmoteList); - iterator.Reset(); - while (iterator.MoreElements()) { - NPC_Emote_Struct *nes = iterator.GetData(); - if (emoteid == nes->emoteid) { - c->Message( - Chat::White, - "EmoteID: %i Event: %i Type: %i Text: %s", - nes->emoteid, - nes->event_, - nes->type, - nes->text - ); - count++; - } - iterator.Advance(); - } - if (count == 0) { - c->Message(Chat::White, "No emotes found."); - } - else { - c->Message(Chat::White, "%i emote(s) found", count); + auto emote_count = 0; + auto emote_id = target->GetEmoteID(); + + auto emote_number = 1; + + LinkedListIterator iterator(zone->NPCEmoteList); + iterator.Reset(); + while (iterator.MoreElements()) { + auto &e = iterator.GetData(); + if (emote_id == e->emoteid) { + c->Message( + Chat::White, + fmt::format( + "Emote {} | Event: {} ({}) Type: {} ({})", + emote_number, + EQ::constants::GetEmoteEventTypeName(e->event_), + e->event_, + EQ::constants::GetEmoteTypeName(e->type), + e->type + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Emote {} | Text: {}", + emote_number, + e->text + ).c_str() + ); + + emote_count++; + emote_number++; } + + iterator.Advance(); } -} + if (!emote_count) { + c->Message( + Chat::White, + fmt::format( + "{} has no emotes on Emote ID {}.", + c->GetTargetDescription(target), + emote_id + ).c_str() + ); + return; + } + + c->Message( + Chat::White, + fmt::format( + "{} has {} emote{} on Emote ID {}.", + c->GetTargetDescription(target), + emote_count, + emote_count != 1 ? "s" : "", + emote_id + ).c_str() + ); +} diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 98cbba88b..e28167c97 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1925,7 +1925,7 @@ void Mob::AI_Event_Engaged(Mob *attacker, bool yell_for_help) parse->EventNPC(EVENT_COMBAT, CastToNPC(), attacker, "1", 0); uint32 emoteid = GetEmoteID(); if (emoteid != 0) { - CastToNPC()->DoNPCEmote(ENTERCOMBAT, emoteid); + CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid); } std::string mob_name = GetCleanName(); combat_record.Start(mob_name); @@ -1958,7 +1958,7 @@ void Mob::AI_Event_NoLongerEngaged() { uint32 emoteid = CastToNPC()->GetEmoteID(); parse->EventNPC(EVENT_COMBAT, CastToNPC(), nullptr, "0", 0); if (emoteid != 0) { - CastToNPC()->DoNPCEmote(LEAVECOMBAT, emoteid); + CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::LeaveCombat, emoteid); } combat_record.Stop(); CastToNPC()->SetCombatEvent(false); diff --git a/zone/npc.cpp b/zone/npc.cpp index df8675282..cb1244288 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -1112,7 +1112,7 @@ void NPC::UpdateEquipmentLight() void NPC::Depop(bool StartSpawnTimer) { uint32 emoteid = GetEmoteID(); if(emoteid != 0) - DoNPCEmote(ONDESPAWN,emoteid); + DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn,emoteid); p_depop = true; if (respawn2) { diff --git a/zone/npc.h b/zone/npc.h index bae25c54f..4aa09bf1a 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -35,16 +35,6 @@ #define M_PI 3.141592 #endif -#define LEAVECOMBAT 0 -#define ENTERCOMBAT 1 -#define ONDEATH 2 -#define AFTERDEATH 3 -#define HAILED 4 -#define KILLEDPC 5 -#define KILLEDNPC 6 -#define ONSPAWN 7 -#define ONDESPAWN 8 - typedef struct { float min_x; float max_x;