mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Commands] Add #show special_abilities (#4043)
* [Commands] Add #show special_abilities # Notes - Allows operators to see what special abilities an NPC has. - Move special ability values to `common/emu_constants.h`. - Add `EQ::constants::GetSpecialAbilityMap()` and `EQ::constants::GetSpecialAbilityName()`. - Add `NPC::DescribeSpecialAbilities(client)` to describe special abilities to a specified client. # Images * Update npc.cpp
This commit is contained in:
parent
0ffea36905
commit
fcbf5cae47
@ -639,3 +639,76 @@ std::string EQ::constants::GetAppearanceTypeName(uint32 appearance_type)
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint32, std::string>& EQ::constants::GetSpecialAbilityMap()
|
||||
{
|
||||
static const std::map<uint32, std::string> special_ability_map = {
|
||||
{ SPECATK_SUMMON, "Summon" },
|
||||
{ SPECATK_ENRAGE, "Enrage" },
|
||||
{ SPECATK_RAMPAGE, "Rampage" },
|
||||
{ SPECATK_AREA_RAMPAGE, "Area Rampage" },
|
||||
{ SPECATK_FLURRY, "Flurry" },
|
||||
{ SPECATK_TRIPLE, "Triple Attack" },
|
||||
{ SPECATK_QUAD, "Quadruple Attack" },
|
||||
{ SPECATK_INNATE_DW, "Dual Wield" },
|
||||
{ SPECATK_BANE, "Bane Attack" },
|
||||
{ SPECATK_MAGICAL, "Magical Attack" },
|
||||
{ SPECATK_RANGED_ATK, "Ranged Attack" },
|
||||
{ UNSLOWABLE, "Immune to Slow" },
|
||||
{ UNMEZABLE, "Immune to Mesmerize" },
|
||||
{ UNCHARMABLE, "Immune to Charm" },
|
||||
{ UNSTUNABLE, "Immune to Stun" },
|
||||
{ UNSNAREABLE, "Immune to Snare" },
|
||||
{ UNFEARABLE, "Immune to Fear" },
|
||||
{ UNDISPELLABLE, "Immune to Dispell" },
|
||||
{ IMMUNE_MELEE, "Immune to Melee" },
|
||||
{ IMMUNE_MAGIC, "Immune to Magic" },
|
||||
{ IMMUNE_FLEEING, "Immune to Fleeing" },
|
||||
{ IMMUNE_MELEE_EXCEPT_BANE, "Immune to Melee except Bane" },
|
||||
{ IMMUNE_MELEE_NONMAGICAL, "Immune to Non-Magical Melee" },
|
||||
{ IMMUNE_AGGRO, "Immune to Aggro" },
|
||||
{ IMMUNE_AGGRO_ON, "Immune to Being Aggro" },
|
||||
{ IMMUNE_CASTING_FROM_RANGE, "Immune to Ranged Spells" },
|
||||
{ IMMUNE_FEIGN_DEATH, "Immune to Feign Death" },
|
||||
{ IMMUNE_TAUNT, "Immune to Taunt" },
|
||||
{ NPC_TUNNELVISION, "Tunnel Vision" },
|
||||
{ NPC_NO_BUFFHEAL_FRIENDS, "Does Not Heal of Buff Allies" },
|
||||
{ IMMUNE_PACIFY, "Immune to Pacify" },
|
||||
{ LEASH, "Leashed" },
|
||||
{ TETHER, "Tethered" },
|
||||
{ DESTRUCTIBLE_OBJECT, "Destructible Object" },
|
||||
{ NO_HARM_FROM_CLIENT, "Immune to Harm from Client" },
|
||||
{ ALWAYS_FLEE, "Always Flees" },
|
||||
{ FLEE_PERCENT, "Flee Percentage" },
|
||||
{ ALLOW_BENEFICIAL, "Allows Beneficial Spells" },
|
||||
{ DISABLE_MELEE, "Melee is Disabled" },
|
||||
{ NPC_CHASE_DISTANCE, "Chase Distance" },
|
||||
{ ALLOW_TO_TANK, "Allowed to Tank" },
|
||||
{ IGNORE_ROOT_AGGRO_RULES, "Ignores Root Aggro" },
|
||||
{ CASTING_RESIST_DIFF, "Casting Resist Difficulty" },
|
||||
{ COUNTER_AVOID_DAMAGE, "Counter Damage Avoidance" },
|
||||
{ PROX_AGGRO, "Proximity Aggro" },
|
||||
{ IMMUNE_RANGED_ATTACKS, "Immune to Ranged Attacks" },
|
||||
{ IMMUNE_DAMAGE_CLIENT, "Immune to Client Damage" },
|
||||
{ IMMUNE_DAMAGE_NPC, "Immune to NPC Damage" },
|
||||
{ IMMUNE_AGGRO_CLIENT, "Immune to Client Aggro" },
|
||||
{ IMMUNE_AGGRO_NPC, "Immune to NPC Aggro" },
|
||||
{ MODIFY_AVOID_DAMAGE, "Modify Damage Avoidance" },
|
||||
{ IMMUNE_FADING_MEMORIES, "Immune to Memory Fades" },
|
||||
{ IMMUNE_OPEN, "Immune to Open" },
|
||||
{ IMMUNE_ASSASSINATE, "Immune to Assassinate" },
|
||||
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
|
||||
};
|
||||
|
||||
return special_ability_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetSpecialAbilityName(uint32 ability_id)
|
||||
{
|
||||
const auto& a = EQ::constants::GetSpecialAbilityMap().find(ability_id);
|
||||
if (a != EQ::constants::GetSpecialAbilityMap().end()) {
|
||||
return a->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@ -401,6 +401,9 @@ namespace EQ
|
||||
extern const std::map<uint32, std::string>& GetAppearanceTypeMap();
|
||||
std::string GetAppearanceTypeName(uint32 animation_type);
|
||||
|
||||
extern const std::map<uint32, std::string>& GetSpecialAbilityMap();
|
||||
std::string GetSpecialAbilityName(uint32 ability_id);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
@ -597,6 +600,65 @@ enum class ApplySpellType {
|
||||
Raid
|
||||
};
|
||||
|
||||
enum {
|
||||
SPECATK_SUMMON = 1,
|
||||
SPECATK_ENRAGE = 2,
|
||||
SPECATK_RAMPAGE = 3,
|
||||
SPECATK_AREA_RAMPAGE = 4,
|
||||
SPECATK_FLURRY = 5,
|
||||
SPECATK_TRIPLE = 6,
|
||||
SPECATK_QUAD = 7,
|
||||
SPECATK_INNATE_DW = 8,
|
||||
SPECATK_BANE = 9,
|
||||
SPECATK_MAGICAL = 10,
|
||||
SPECATK_RANGED_ATK = 11,
|
||||
UNSLOWABLE = 12,
|
||||
UNMEZABLE = 13,
|
||||
UNCHARMABLE = 14,
|
||||
UNSTUNABLE = 15,
|
||||
UNSNAREABLE = 16,
|
||||
UNFEARABLE = 17,
|
||||
UNDISPELLABLE = 18,
|
||||
IMMUNE_MELEE = 19,
|
||||
IMMUNE_MAGIC = 20,
|
||||
IMMUNE_FLEEING = 21,
|
||||
IMMUNE_MELEE_EXCEPT_BANE = 22,
|
||||
IMMUNE_MELEE_NONMAGICAL = 23,
|
||||
IMMUNE_AGGRO = 24,
|
||||
IMMUNE_AGGRO_ON = 25,
|
||||
IMMUNE_CASTING_FROM_RANGE = 26,
|
||||
IMMUNE_FEIGN_DEATH = 27,
|
||||
IMMUNE_TAUNT = 28,
|
||||
NPC_TUNNELVISION = 29,
|
||||
NPC_NO_BUFFHEAL_FRIENDS = 30,
|
||||
IMMUNE_PACIFY = 31,
|
||||
LEASH = 32,
|
||||
TETHER = 33,
|
||||
DESTRUCTIBLE_OBJECT = 34,
|
||||
NO_HARM_FROM_CLIENT = 35,
|
||||
ALWAYS_FLEE = 36,
|
||||
FLEE_PERCENT = 37,
|
||||
ALLOW_BENEFICIAL = 38,
|
||||
DISABLE_MELEE = 39,
|
||||
NPC_CHASE_DISTANCE = 40,
|
||||
ALLOW_TO_TANK = 41,
|
||||
IGNORE_ROOT_AGGRO_RULES = 42,
|
||||
CASTING_RESIST_DIFF = 43,
|
||||
COUNTER_AVOID_DAMAGE = 44, // Modify by percent NPC's opponents chance to riposte, block, parry or dodge individually, or for all skills
|
||||
PROX_AGGRO = 45,
|
||||
IMMUNE_RANGED_ATTACKS = 46,
|
||||
IMMUNE_DAMAGE_CLIENT = 47,
|
||||
IMMUNE_DAMAGE_NPC = 48,
|
||||
IMMUNE_AGGRO_CLIENT = 49,
|
||||
IMMUNE_AGGRO_NPC = 50,
|
||||
MODIFY_AVOID_DAMAGE = 51, // Modify by percent the NPCs chance to riposte, block, parry or dodge individually, or for all skills
|
||||
IMMUNE_FADING_MEMORIES = 52,
|
||||
IMMUNE_OPEN = 53,
|
||||
IMMUNE_ASSASSINATE = 54,
|
||||
IMMUNE_HEADSHOT = 55,
|
||||
MAX_SPECIAL_ATTACK = 56
|
||||
};
|
||||
|
||||
|
||||
namespace HeroicBonusBucket
|
||||
{
|
||||
|
||||
@ -153,65 +153,6 @@ typedef enum { //focus types
|
||||
} focusType; //Any new FocusType needs to be added to the Mob::IsFocus function
|
||||
#define HIGHEST_FOCUS focusFcHealAmtCrit //Should always be last focusType in enum
|
||||
|
||||
enum {
|
||||
SPECATK_SUMMON = 1,
|
||||
SPECATK_ENRAGE = 2,
|
||||
SPECATK_RAMPAGE = 3,
|
||||
SPECATK_AREA_RAMPAGE = 4,
|
||||
SPECATK_FLURRY = 5,
|
||||
SPECATK_TRIPLE = 6,
|
||||
SPECATK_QUAD = 7,
|
||||
SPECATK_INNATE_DW = 8,
|
||||
SPECATK_BANE = 9,
|
||||
SPECATK_MAGICAL = 10,
|
||||
SPECATK_RANGED_ATK = 11,
|
||||
UNSLOWABLE = 12,
|
||||
UNMEZABLE = 13,
|
||||
UNCHARMABLE = 14,
|
||||
UNSTUNABLE = 15,
|
||||
UNSNAREABLE = 16,
|
||||
UNFEARABLE = 17,
|
||||
UNDISPELLABLE = 18,
|
||||
IMMUNE_MELEE = 19,
|
||||
IMMUNE_MAGIC = 20,
|
||||
IMMUNE_FLEEING = 21,
|
||||
IMMUNE_MELEE_EXCEPT_BANE = 22,
|
||||
IMMUNE_MELEE_NONMAGICAL = 23,
|
||||
IMMUNE_AGGRO = 24,
|
||||
IMMUNE_AGGRO_ON = 25,
|
||||
IMMUNE_CASTING_FROM_RANGE = 26,
|
||||
IMMUNE_FEIGN_DEATH = 27,
|
||||
IMMUNE_TAUNT = 28,
|
||||
NPC_TUNNELVISION = 29,
|
||||
NPC_NO_BUFFHEAL_FRIENDS = 30,
|
||||
IMMUNE_PACIFY = 31,
|
||||
LEASH = 32,
|
||||
TETHER = 33,
|
||||
DESTRUCTIBLE_OBJECT = 34,
|
||||
NO_HARM_FROM_CLIENT = 35,
|
||||
ALWAYS_FLEE = 36,
|
||||
FLEE_PERCENT = 37,
|
||||
ALLOW_BENEFICIAL = 38,
|
||||
DISABLE_MELEE = 39,
|
||||
NPC_CHASE_DISTANCE = 40,
|
||||
ALLOW_TO_TANK = 41,
|
||||
IGNORE_ROOT_AGGRO_RULES = 42,
|
||||
CASTING_RESIST_DIFF = 43,
|
||||
COUNTER_AVOID_DAMAGE = 44, //Modify by percent NPC's opponents chance to riposte, block, parry or dodge individually, or for all skills
|
||||
PROX_AGGRO = 45,
|
||||
IMMUNE_RANGED_ATTACKS = 46,
|
||||
IMMUNE_DAMAGE_CLIENT = 47,
|
||||
IMMUNE_DAMAGE_NPC = 48,
|
||||
IMMUNE_AGGRO_CLIENT = 49,
|
||||
IMMUNE_AGGRO_NPC = 50,
|
||||
MODIFY_AVOID_DAMAGE = 51, //Modify by percent the NPCs chance to riposte, block, parry or dodge individually, or for all skills
|
||||
IMMUNE_FADING_MEMORIES = 52,
|
||||
IMMUNE_OPEN = 53,
|
||||
IMMUNE_ASSASSINATE = 54,
|
||||
IMMUNE_HEADSHOT = 55,
|
||||
MAX_SPECIAL_ATTACK
|
||||
};
|
||||
|
||||
typedef enum { //fear states
|
||||
fearStateNotFeared = 0,
|
||||
fearStateRunning, //I am running, hoping to find a grid at my WP
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include "show/server_info.cpp"
|
||||
#include "show/skills.cpp"
|
||||
#include "show/spawn_status.cpp"
|
||||
#include "show/special_abilities.cpp"
|
||||
#include "show/spells.cpp"
|
||||
#include "show/spells_list.cpp"
|
||||
#include "show/stats.cpp"
|
||||
@ -88,6 +89,7 @@ void command_show(Client *c, const Seperator *sep)
|
||||
Cmd{.cmd = "server_info", .u = "server_info", .fn = ShowServerInfo, .a = {"#serverinfo"}},
|
||||
Cmd{.cmd = "skills", .u = "skills", .fn = ShowSkills, .a = {"#showskills"}},
|
||||
Cmd{.cmd = "spawn_status", .u = "spawn_status [all|disabled|enabled|Spawn ID]", .fn = ShowSpawnStatus, .a = {"#spawnstatus"}},
|
||||
Cmd{.cmd = "special_abilities", .u = "special_abilities", .fn = ShowSpecialAbilities, .a = {"#showspecialabilities"}},
|
||||
Cmd{.cmd = "spells", .u = "spells [disciplines|spells]", .fn = ShowSpells, .a = {"#showspells"}},
|
||||
Cmd{.cmd = "spells_list", .u = "spells_list", .fn = ShowSpellsList, .a = {"#showspellslist"}},
|
||||
Cmd{.cmd = "stats", .u = "stats", .fn = ShowStats, .a = {"#showstats"}},
|
||||
|
||||
13
zone/gm_commands/show/special_abilities.cpp
Normal file
13
zone/gm_commands/show/special_abilities.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "../../client.h"
|
||||
|
||||
void ShowSpecialAbilities(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
|
||||
c->Message(Chat::White, "You must target an NPC to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
NPC* t = c->GetTarget()->CastToNPC();
|
||||
|
||||
t->DescribeSpecialAbilities(c);
|
||||
}
|
||||
212
zone/npc.cpp
212
zone/npc.cpp
@ -3995,3 +3995,215 @@ bool NPC::CanPathTo(float x, float y, float z)
|
||||
|
||||
return !route.empty();
|
||||
}
|
||||
|
||||
void NPC::DescribeSpecialAbilities(Client* c)
|
||||
{
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
// These abilities are simple on/off flags
|
||||
static const std::vector<uint32> toggleable_special_abilities = {
|
||||
SPECATK_TRIPLE,
|
||||
SPECATK_QUAD,
|
||||
SPECATK_INNATE_DW,
|
||||
SPECATK_BANE,
|
||||
SPECATK_MAGICAL,
|
||||
UNSLOWABLE,
|
||||
UNMEZABLE,
|
||||
UNCHARMABLE,
|
||||
UNSTUNABLE,
|
||||
UNSNAREABLE,
|
||||
UNFEARABLE,
|
||||
UNDISPELLABLE,
|
||||
IMMUNE_MELEE,
|
||||
IMMUNE_MAGIC,
|
||||
IMMUNE_FLEEING,
|
||||
IMMUNE_MELEE_EXCEPT_BANE,
|
||||
IMMUNE_MELEE_NONMAGICAL,
|
||||
IMMUNE_AGGRO,
|
||||
IMMUNE_AGGRO_ON,
|
||||
IMMUNE_CASTING_FROM_RANGE,
|
||||
IMMUNE_FEIGN_DEATH,
|
||||
IMMUNE_TAUNT,
|
||||
NPC_NO_BUFFHEAL_FRIENDS,
|
||||
IMMUNE_PACIFY,
|
||||
DESTRUCTIBLE_OBJECT,
|
||||
NO_HARM_FROM_CLIENT,
|
||||
ALWAYS_FLEE,
|
||||
ALLOW_BENEFICIAL,
|
||||
DISABLE_MELEE,
|
||||
ALLOW_TO_TANK,
|
||||
IGNORE_ROOT_AGGRO_RULES,
|
||||
PROX_AGGRO,
|
||||
IMMUNE_RANGED_ATTACKS,
|
||||
IMMUNE_DAMAGE_CLIENT,
|
||||
IMMUNE_DAMAGE_NPC,
|
||||
IMMUNE_AGGRO_CLIENT,
|
||||
IMMUNE_AGGRO_NPC,
|
||||
IMMUNE_FADING_MEMORIES,
|
||||
IMMUNE_OPEN,
|
||||
IMMUNE_ASSASSINATE,
|
||||
IMMUNE_HEADSHOT,
|
||||
};
|
||||
|
||||
// These abilities have parameters that need to be parsed out individually
|
||||
static const std::map<uint32, std::vector<std::string>> parameter_special_abilities = {
|
||||
{ SPECATK_SUMMON, { "Cooldown in Milliseconds", "Health Percentage" } },
|
||||
{
|
||||
SPECATK_ENRAGE,
|
||||
{
|
||||
"Health Percentage",
|
||||
"Duration in Milliseconds",
|
||||
"Cooldown in Milliseconds"
|
||||
}
|
||||
},
|
||||
{
|
||||
SPECATK_RAMPAGE,
|
||||
{
|
||||
"Chance",
|
||||
"Targets",
|
||||
"Flat Damage Bonus",
|
||||
"Ignore Armor Percentage",
|
||||
"Ignore Flat Armor Amount",
|
||||
"Critical Chance",
|
||||
"Flat Critical Chance Bonus"
|
||||
}
|
||||
},
|
||||
{
|
||||
SPECATK_AREA_RAMPAGE,
|
||||
{
|
||||
"Targets",
|
||||
"Normal Attack Damage Percentage",
|
||||
"Flat Damage Bonus",
|
||||
"Ignore Armor Percentage",
|
||||
"Ignore Flat Armor Amount",
|
||||
"Critical Chance",
|
||||
"Flat Critical Chance Bonus"
|
||||
}
|
||||
},
|
||||
{
|
||||
SPECATK_FLURRY,
|
||||
{
|
||||
"Attacks",
|
||||
"Normal Attack Damage Percentage",
|
||||
"Flat Damage Bonus",
|
||||
"Ignore Armor Percentage",
|
||||
"Ignore Flat Armor Amount",
|
||||
"Critical Chance",
|
||||
"Flat Critical Chance Bonus"
|
||||
}
|
||||
},
|
||||
{
|
||||
SPECATK_RANGED_ATK,
|
||||
{
|
||||
"Attacks",
|
||||
"Maximum Range",
|
||||
"Chance",
|
||||
"Damage Percentage",
|
||||
"Minimum Range"
|
||||
}
|
||||
},
|
||||
{ NPC_TUNNELVISION, { "Aggro Modifier on Non-Tanks" } },
|
||||
{ LEASH, { "Range" } },
|
||||
{ TETHER, { "Range" } },
|
||||
{ FLEE_PERCENT, { "Health Percentage", "Chance" } },
|
||||
{
|
||||
NPC_CHASE_DISTANCE,
|
||||
{
|
||||
"Maximum Distance",
|
||||
"Minimum Distance",
|
||||
"Ignore Line of Sight"
|
||||
}
|
||||
},
|
||||
{ CASTING_RESIST_DIFF, { "Resist Difficulty Value" } },
|
||||
{
|
||||
COUNTER_AVOID_DAMAGE,
|
||||
{
|
||||
"Reduction Percentage for Block, Dodge, Parry, and Riposte",
|
||||
"Reduction Percentage for Riposte",
|
||||
"Reduction Percentage for Block",
|
||||
"Reduction Percentage for Parry",
|
||||
"Reduction Percentage for Dodge",
|
||||
}
|
||||
},
|
||||
{
|
||||
MODIFY_AVOID_DAMAGE,
|
||||
{
|
||||
"Addition Percentage for Block, Dodge, Parry, and Riposte",
|
||||
"Addition Percentage for Riposte",
|
||||
"Addition Percentage for Block",
|
||||
"Addition Percentage for Parry",
|
||||
"Addition Percentage for Dodge",
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
std::vector<std::string> messages = { };
|
||||
|
||||
for (const auto& e : toggleable_special_abilities) {
|
||||
if (GetSpecialAbility(e)) {
|
||||
messages.emplace_back(
|
||||
fmt::format(
|
||||
"{} ({})",
|
||||
EQ::constants::GetSpecialAbilityName(e),
|
||||
e
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int slot_id;
|
||||
|
||||
for (const auto& e : parameter_special_abilities) {
|
||||
if (GetSpecialAbility(e.first)) {
|
||||
slot_id = 0;
|
||||
|
||||
for (const auto& a : e.second) {
|
||||
messages.emplace_back(
|
||||
fmt::format(
|
||||
"{} ({}) | {}: {}",
|
||||
EQ::constants::GetSpecialAbilityName(e.first),
|
||||
e.first,
|
||||
a,
|
||||
GetSpecialAbilityParam(e.first, slot_id)
|
||||
)
|
||||
);
|
||||
|
||||
slot_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (messages.empty()) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} has no special abilities.",
|
||||
c->GetTargetDescription(this)
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} has the following special abilit{}:",
|
||||
c->GetTargetDescription(this),
|
||||
messages.size() != 1 ? "ies" : "y"
|
||||
).c_str()
|
||||
);
|
||||
|
||||
std::sort(
|
||||
messages.begin(),
|
||||
messages.end(),
|
||||
[](const std::string& a, const std::string& b) {
|
||||
return a < b;
|
||||
}
|
||||
);
|
||||
|
||||
for (const auto& e : messages) {
|
||||
c->Message(Chat::White, e.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,6 +369,8 @@ public:
|
||||
inline bool IsGuarding() const { return(m_GuardPoint.w != 0); }
|
||||
void SaveGuardSpotCharm();
|
||||
|
||||
void DescribeSpecialAbilities(Client* c);
|
||||
|
||||
uint16 GetMeleeTexture1() const;
|
||||
uint16 GetMeleeTexture2() const;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user