Add single target and zonewide dynamic and static scaling methods / commands

This commit is contained in:
Akkadius 2018-11-07 02:34:55 -06:00
parent 10fd51a1f9
commit 17ca995aa9
6 changed files with 331 additions and 41 deletions

View File

@ -67,6 +67,7 @@
#include "water_map.h" #include "water_map.h"
#include "worldserver.h" #include "worldserver.h"
#include "fastmath.h" #include "fastmath.h"
#include "npc_scale_manager.h"
extern QueryServ* QServ; extern QueryServ* QServ;
extern WorldServer worldserver; extern WorldServer worldserver;
@ -335,6 +336,7 @@ int command_init(void)
command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) || command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) ||
command_add("rules", "(subcommand) - Manage server rules", 250, command_rules) || command_add("rules", "(subcommand) - Manage server rules", 250, command_rules) ||
command_add("save", "- Force your player or player corpse target to be saved to the database", 50, command_save) || command_add("save", "- Force your player or player corpse target to be saved to the database", 50, command_save) ||
command_add("scale", "- Handles npc scaling", 150, command_scale) ||
command_add("scribespell", "[spellid] - Scribe specified spell in your target's spell book.", 180, command_scribespell) || command_add("scribespell", "[spellid] - Scribe specified spell in your target's spell book.", 180, command_scribespell) ||
command_add("scribespells", "[max level] [min level] - Scribe all spells for you or your player target that are usable by them, up to level specified. (may freeze client for a few seconds)", 150, command_scribespells) || command_add("scribespells", "[max level] [min level] - Scribe all spells for you or your player target that are usable by them, up to level specified. (may freeze client for a few seconds)", 150, command_scribespells) ||
command_add("sendzonespawns", "- Refresh spawn list for all clients in zone", 150, command_sendzonespawns) || command_add("sendzonespawns", "- Refresh spawn list for all clients in zone", 150, command_sendzonespawns) ||
@ -1380,7 +1382,7 @@ void command_list(Client *c, const Seperator *sep)
entity_count++; entity_count++;
std::string entity_name = entity->GetCleanName(); std::string entity_name = entity->GetName();
/** /**
* Filter by name * Filter by name
@ -1421,7 +1423,7 @@ void command_list(Client *c, const Seperator *sep)
entity_count++; entity_count++;
std::string entity_name = entity->GetCleanName(); std::string entity_name = entity->GetName();
/** /**
* Filter by name * Filter by name
@ -1462,7 +1464,7 @@ void command_list(Client *c, const Seperator *sep)
entity_count++; entity_count++;
std::string entity_name = entity->GetCleanName(); std::string entity_name = entity->GetName();
/** /**
* Filter by name * Filter by name
@ -11400,6 +11402,133 @@ void command_reloadtraps(Client *c, const Seperator *sep)
c->Message(CC_Default, "Traps reloaded for %s.", zone->GetShortName()); c->Message(CC_Default, "Traps reloaded for %s.", zone->GetShortName());
} }
void command_scale(Client *c, const Seperator *sep)
{
if (sep->argnum == 0) {
c->Message(15, "# Usage # ");
c->Message(15, "#scale [static/dynamic] (With targeted NPC)");
c->Message(15, "#scale [npc_name_search] [static/dynamic] (To make zone-wide changes)");
c->Message(15, "#scale all [static/dynamic]");
return;
}
/**
* Targeted changes
*/
if (c->GetTarget() && c->GetTarget()->IsNPC() && sep->argnum < 2) {
NPC * npc = c->GetTarget()->CastToNPC();
bool apply_status = false;
if (strcasecmp(sep->arg[1], "dynamic") == 0) {
c->Message(15, "Applying global base scaling to npc dynamically (All stats set to zeroes)...");
apply_status = npc_scale_manager->ApplyGlobalBaseScalingToNPCDynamically(npc);
}
else if (strcasecmp(sep->arg[1], "static") == 0) {
c->Message(15, "Applying global base scaling to npc statically (Copying base stats onto NPC)...");
apply_status = npc_scale_manager->ApplyGlobalBaseScalingToNPCStatically(npc);
}
else {
return;
}
if (apply_status) {
c->Message(15, "Applied to NPC '%s' successfully!", npc->GetName());
}
else {
c->Message(15, "Failed to load scaling data from the database "
"for this npc / type, see 'NPCScaling' log for more info");
}
}
else if (c->GetTarget() && sep->argnum < 2) {
c->Message(15, "Target must be an npc!");
}
/**
* Zonewide
*/
if (sep->argnum > 1) {
std::string scale_type;
if (strcasecmp(sep->arg[2], "dynamic") == 0) {
scale_type = "dynamic";
}
else if (strcasecmp(sep->arg[2], "static") == 0) {
scale_type = "static";
}
if (scale_type.length() <= 0) {
c->Message(15, "You must first set if you intend on using static versus dynamic for these changes");
c->Message(15, "#scale [npc_name_search] [static/dynamic]");
c->Message(15, "#scale all [static/dynamic]");
return;
}
std::string search_string = sep->arg[1];
auto &entity_list_search = entity_list.GetNPCList();
int found_count = 0;
for (auto &itr : entity_list_search) {
NPC *entity = itr.second;
std::string entity_name = entity->GetName();
/**
* Filter by name
*/
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos && strcasecmp(sep->arg[1], "all") != 0) {
continue;
}
std::string status = "(Searching)";
if (strcasecmp(sep->arg[3], "apply") == 0) {
status = "(Applying)";
if (strcasecmp(sep->arg[2], "dynamic") == 0) {
npc_scale_manager->ApplyGlobalBaseScalingToNPCDynamically(entity);
}
if (strcasecmp(sep->arg[2], "static") == 0) {
npc_scale_manager->ApplyGlobalBaseScalingToNPCStatically(entity);
}
}
c->Message(
15,
"| ID %5d | %s | x %.0f | y %0.f | z %.0f | DBID %u %s",
entity->GetID(),
entity->GetName(),
entity->GetX(),
entity->GetY(),
entity->GetZ(),
entity->GetNPCTypeID(),
status.c_str()
);
found_count++;
}
if (strcasecmp(sep->arg[3], "apply") == 0) {
c->Message(15, "%s scaling applied against (%i) NPC's", sep->arg[2], found_count);
}
else {
std::string saylink = StringFormat(
"#scale %s %s apply",
sep->arg[1],
sep->arg[2]
);
c->Message(15, "Found (%i) NPC's that match this search...", found_count);
c->Message(
15, "To apply these changes, click <%s> or type %s",
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Apply").c_str(),
saylink.c_str()
);
}
}
}
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block. // All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
#ifdef BOTS #ifdef BOTS
#include "bot_command.h" #include "bot_command.h"

View File

@ -242,6 +242,7 @@ void command_resetaa_timer(Client *c, const Seperator *sep);
void command_revoke(Client *c, const Seperator *sep); void command_revoke(Client *c, const Seperator *sep);
void command_rules(Client *c, const Seperator *sep); void command_rules(Client *c, const Seperator *sep);
void command_save(Client *c, const Seperator *sep); void command_save(Client *c, const Seperator *sep);
void command_scale(Client *c, const Seperator *sep);
void command_scribespell(Client *c, const Seperator *sep); void command_scribespell(Client *c, const Seperator *sep);
void command_scribespells(Client *c, const Seperator *sep); void command_scribespells(Client *c, const Seperator *sep);
void command_sendop(Client *c, const Seperator *sep); void command_sendop(Client *c, const Seperator *sep);

View File

@ -3247,8 +3247,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str)
const char *Mob::GetCleanName() const char *Mob::GetCleanName()
{ {
if(!strlen(clean_name)) if (!strlen(clean_name)) {
{
CleanMobName(GetName(), clean_name); CleanMobName(GetName(), clean_name);
} }
@ -3650,11 +3649,10 @@ void Mob::SetEntityVariable(const char *id, const char *m_var)
m_EntityVariables[id] = n_m_var; m_EntityVariables[id] = n_m_var;
} }
const char* Mob::GetEntityVariable(const char *id) const char *Mob::GetEntityVariable(const char *id)
{ {
auto iter = m_EntityVariables.find(id); auto iter = m_EntityVariables.find(id);
if(iter != m_EntityVariables.end()) if (iter != m_EntityVariables.end()) {
{
return iter->second.c_str(); return iter->second.c_str();
} }
return nullptr; return nullptr;

View File

@ -367,7 +367,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
ignore_despawn = npc_type_data->ignore_despawn; ignore_despawn = npc_type_data->ignore_despawn;
m_targetable = !npc_type_data->untargetable; m_targetable = !npc_type_data->untargetable;
npc_scale_manager->ScaleMob(this); npc_scale_manager->ScaleNPC(this);
AISpellVar.fail_recast = static_cast<uint32>(RuleI(Spells, AI_SpellCastFinishedFailRecast)); AISpellVar.fail_recast = static_cast<uint32>(RuleI(Spells, AI_SpellCastFinishedFailRecast));
AISpellVar.engaged_no_sp_recast_min = static_cast<uint32>(RuleI(Spells, AI_EngagedNoSpellMinRecast)); AISpellVar.engaged_no_sp_recast_min = static_cast<uint32>(RuleI(Spells, AI_EngagedNoSpellMinRecast));

View File

@ -24,34 +24,20 @@
/** /**
* @param mob * @param mob
*/ */
void NpcScaleManager::ScaleMob(Mob *mob) void NpcScaleManager::ScaleNPC(NPC * npc)
{ {
Log(Logs::General, Logs::NPCScaling, "Attempting scale on %s", mob->GetCleanName()); Log(Logs::General, Logs::NPCScaling, "Attempting scale on %s", npc->GetCleanName());
if (mob->IsClient()) { int8 npc_type = GetNPCScalingType(npc);
return; int npc_level = npc->GetLevel();
}
NPC *npc = mob->CastToNPC(); global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
int8 mob_type = 0;
int mob_level = npc->GetLevel();
if (npc->IsRareSpawn()) {
mob_type = 1;
}
if (npc->IsRaidTarget()) {
mob_type = 2;
}
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(mob_type, mob_level);
if (!scale_data.level) { if (!scale_data.level) {
Log(Logs::General, Logs::NPCScaling, "NPC: %s - scaling data not found for type: %i level: %i", Log(Logs::General, Logs::NPCScaling, "NPC: %s - scaling data not found for type: %i level: %i",
mob->GetCleanName(), npc->GetCleanName(),
mob_type, npc_type,
mob_level npc_level
); );
return; return;
@ -165,16 +151,19 @@ void NpcScaleManager::ScaleMob(Mob *mob)
ListStats(npc); ListStats(npc);
} }
void NpcScaleManager::ListStats(Mob *mob) /**
* @param mob
*/
void NpcScaleManager::ListStats(NPC *&npc)
{ {
for (const auto &stat : scaling_stats) { for (const auto &stat : scaling_stats) {
std::string variable = StringFormat("modify_stat_%s", stat.c_str()); std::string variable = StringFormat("modify_stat_%s", stat.c_str());
if (mob->EntityVariableExists(variable.c_str())) { if (npc->EntityVariableExists(variable.c_str())) {
Log(Logs::Detail, Log(Logs::Detail,
Logs::NPCScaling, Logs::NPCScaling,
"NpcScaleManager::ListStats: %s - %s ", "NpcScaleManager::ListStats: %s - %s ",
stat.c_str(), stat.c_str(),
mob->GetEntityVariable(variable.c_str())); npc->GetEntityVariable(variable.c_str()));
} }
} }
} }
@ -263,13 +252,13 @@ bool NpcScaleManager::LoadScaleData()
} }
/** /**
* @param mob_type * @param npc_type
* @param mob_level * @param npc_level
* @return NpcScaleManager::global_npc_scale * @return NpcScaleManager::global_npc_scale
*/ */
NpcScaleManager::global_npc_scale NpcScaleManager::GetGlobalScaleDataForTypeLevel(int8 mob_type, int mob_level) NpcScaleManager::global_npc_scale NpcScaleManager::GetGlobalScaleDataForTypeLevel(int8 npc_type, int npc_level)
{ {
auto iter = npc_global_base_scaling_data.find(std::make_pair(mob_type, mob_level)); auto iter = npc_global_base_scaling_data.find(std::make_pair(npc_type, npc_level));
if (iter != npc_global_base_scaling_data.end()) { if (iter != npc_global_base_scaling_data.end()) {
return iter->second; return iter->second;
} }
@ -417,4 +406,173 @@ uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
} }
return multiplier; return multiplier;
}
/**
* @param npc
* @return
*/
int8 NpcScaleManager::GetNPCScalingType(NPC *&npc)
{
std::string npc_name = npc->GetName();
if (npc->IsRareSpawn() || npc_name.find('#') != std::string::npos) {
return 1;
}
if (npc->IsRaidTarget()) {
return 2;
}
return 0;
}
/**
* Returns false if scaling data not found
* @param npc
* @return
*/
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCStatically(NPC *&npc)
{
int8 npc_type = GetNPCScalingType(npc);
int npc_level = npc->GetLevel();
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
if (!scale_data.level) {
Log(
Logs::General,
Logs::NPCScaling,
"NpcScaleManager::ApplyGlobalBaseScalingToNPCStatically NPC: %s - scaling data not found for type: %i level: %i",
npc->GetCleanName(),
npc_type,
npc_level
);
return false;
}
std::string query = StringFormat(
"UPDATE `npc_types` SET "
"AC = %i, "
"hp = %i, "
"Accuracy = %i, "
"slow_mitigation = %i, "
"ATK = %i, "
"STR = %i, "
"STA = %i, "
"DEX = %i, "
"AGI = %i, "
"_INT = %i, "
"WIS = %i, "
"CHA = %i, "
"MR = %i, "
"CR = %i, "
"FR = %i, "
"PR = %i, "
"DR = %i, "
"Corrup = %i, "
"PhR = %i, "
"mindmg = %i, "
"maxdmg = %i, "
"hp_regen_rate = %i, "
"attack_delay = %i, "
"spellscale = %i, "
"healscale = %i, "
"special_abilities = '%s' "
"WHERE `id` = %i",
scale_data.ac,
scale_data.hp,
scale_data.accuracy,
scale_data.slow_mitigation,
scale_data.attack,
scale_data.strength,
scale_data.stamina,
scale_data.dexterity,
scale_data.agility,
scale_data.intelligence,
scale_data.wisdom,
scale_data.charisma,
scale_data.magic_resist,
scale_data.cold_resist,
scale_data.fire_resist,
scale_data.poison_resist,
scale_data.disease_resist,
scale_data.corruption_resist,
scale_data.physical_resist,
scale_data.min_dmg,
scale_data.max_dmg,
scale_data.hp_regen_rate,
scale_data.attack_delay,
scale_data.spell_scale,
scale_data.heal_scale,
EscapeString(scale_data.special_abilities).c_str(),
npc->GetNPCTypeID()
);
auto results = database.QueryDatabase(query);
return results.Success();
}
/**
* Returns false if scaling data not found
* @param npc
* @return
*/
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically(NPC *&npc)
{
int8 npc_type = GetNPCScalingType(npc);
int npc_level = npc->GetLevel();
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
if (!scale_data.level) {
Log(
Logs::General,
Logs::NPCScaling,
"NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically NPC: %s - scaling data not found for type: %i level: %i",
npc->GetCleanName(),
npc_type,
npc_level
);
return false;
}
std::string query = StringFormat(
"UPDATE `npc_types` SET "
"AC = 0, "
"hp = 0, "
"Accuracy = 0, "
"slow_mitigation = 0, "
"ATK = 0, "
"STR = 0, "
"STA = 0, "
"DEX = 0, "
"AGI = 0, "
"_INT = 0, "
"WIS = 0, "
"CHA = 0, "
"MR = 0, "
"CR = 0, "
"FR = 0, "
"PR = 0, "
"DR = 0, "
"Corrup = 0, "
"PhR = 0, "
"mindmg = 0, "
"maxdmg = 0, "
"hp_regen_rate = 0, "
"attack_delay = 0, "
"spellscale = 0, "
"healscale = 0, "
"special_abilities = '' "
"WHERE `id` = %i",
npc->GetNPCTypeID()
);
auto results = database.QueryDatabase(query);
return results.Success();
} }

View File

@ -87,14 +87,18 @@ public:
"special_abilities" "special_abilities"
}; };
void ScaleMob(Mob *mob); void ScaleNPC(NPC * npc);
bool LoadScaleData(); bool LoadScaleData();
global_npc_scale GetGlobalScaleDataForTypeLevel(int8 mob_type, int mob_level); global_npc_scale GetGlobalScaleDataForTypeLevel(int8 npc_type, int npc_level);
std::map<std::pair<int, int>, global_npc_scale> npc_global_base_scaling_data; std::map<std::pair<int, int>, global_npc_scale> npc_global_base_scaling_data;
void ListStats(Mob * mob); void ListStats(NPC * &npc);
int8 GetNPCScalingType(NPC * &npc);
bool ApplyGlobalBaseScalingToNPCStatically(NPC * &npc);
bool ApplyGlobalBaseScalingToNPCDynamically(NPC * &npc);
uint32 GetClassLevelDamageMod(uint32 level, uint32 npc_class); uint32 GetClassLevelDamageMod(uint32 level, uint32 npc_class);
}; };