mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 14:41:28 +00:00
Mostly done with global base scaling work, dev tooling and various other works
This commit is contained in:
parent
cc920e60d9
commit
775b5fcaf1
@ -272,10 +272,6 @@ enum {
|
||||
commandInvSnapshot = 150 //ability to clear/restore snapshots
|
||||
};
|
||||
|
||||
//default states for logging flag on NPCs and clients (having NPCs on by default is prolly a bad idea)
|
||||
#define CLIENT_DEFAULT_LOGGING_ENABLED true
|
||||
#define NPC_DEFAULT_LOGGING_ENABLED false
|
||||
|
||||
|
||||
// This is the item ID we use for say links, we use the max that fits in 5 ASCII chars
|
||||
#define SAYLINK_ITEM_ID 0xFFFFF
|
||||
|
||||
@ -382,15 +382,18 @@ bool RuleManager::ListRulesets(Database *database, std::map<int, std::string> &i
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 RuleManager::GetIntRule(RuleManager::IntType t) const{
|
||||
int32 RuleManager::GetIntRule(RuleManager::IntType t) const
|
||||
{
|
||||
return (m_RuleIntValues[t]);
|
||||
}
|
||||
|
||||
float RuleManager::GetRealRule(RuleManager::RealType t) const{
|
||||
float RuleManager::GetRealRule(RuleManager::RealType t) const
|
||||
{
|
||||
return (m_RuleRealValues[t]);
|
||||
}
|
||||
|
||||
bool RuleManager::GetBoolRule(RuleManager::BoolType t) const{
|
||||
bool RuleManager::GetBoolRule(RuleManager::BoolType t) const
|
||||
{
|
||||
return (m_RuleBoolValues[t] == 1);
|
||||
}
|
||||
|
||||
|
||||
@ -508,6 +508,7 @@ RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I b
|
||||
RULE_BOOL(Combat, ClassicMasterWu, false) // classic master wu uses a random special, modern doesn't
|
||||
RULE_INT(Combat, LevelToStopDamageCaps, 0) // 1 will effectively disable them, 20 should give basically same results as old incorrect system
|
||||
RULE_BOOL(Combat, ClassicNPCBackstab, false) // true disables npc facestab - npcs get normal attack if not behind
|
||||
RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true) // Uses GetClassLevelDamageMod calc in npc_scale_manager
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
|
||||
@ -29,8 +29,9 @@
|
||||
bool EQEmu::saylink::DegenerateLinkBody(SayLinkBody_Struct &say_link_body_struct, const std::string &say_link_body)
|
||||
{
|
||||
memset(&say_link_body_struct, 0, sizeof(say_link_body_struct));
|
||||
if (say_link_body.length() != EQEmu::constants::SAY_LINK_BODY_SIZE)
|
||||
if (say_link_body.length() != EQEmu::constants::SAY_LINK_BODY_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
say_link_body_struct.action_id = (uint8) strtol(say_link_body.substr(0, 1).c_str(), nullptr, 16);
|
||||
say_link_body_struct.item_id = (uint32) strtol(say_link_body.substr(1, 5).c_str(), nullptr, 16);
|
||||
@ -68,8 +69,9 @@ bool EQEmu::saylink::GenerateLinkBody(std::string& say_link_body, const SayLinkB
|
||||
(0xFFFFFFFF & say_link_body_struct.hash)
|
||||
);
|
||||
|
||||
if (say_link_body.length() != EQEmu::constants::SAY_LINK_BODY_SIZE)
|
||||
if (say_link_body.length() != EQEmu::constants::SAY_LINK_BODY_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -192,36 +194,50 @@ void EQEmu::SayLinkEngine::generate_body()
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_LinkProxyStruct.action_id)
|
||||
if (m_LinkProxyStruct.action_id) {
|
||||
m_LinkBodyStruct.action_id = m_LinkProxyStruct.action_id;
|
||||
if (m_LinkProxyStruct.item_id)
|
||||
}
|
||||
if (m_LinkProxyStruct.item_id) {
|
||||
m_LinkBodyStruct.item_id = m_LinkProxyStruct.item_id;
|
||||
if (m_LinkProxyStruct.augment_1)
|
||||
}
|
||||
if (m_LinkProxyStruct.augment_1) {
|
||||
m_LinkBodyStruct.augment_1 = m_LinkProxyStruct.augment_1;
|
||||
if (m_LinkProxyStruct.augment_2)
|
||||
}
|
||||
if (m_LinkProxyStruct.augment_2) {
|
||||
m_LinkBodyStruct.augment_2 = m_LinkProxyStruct.augment_2;
|
||||
if (m_LinkProxyStruct.augment_3)
|
||||
}
|
||||
if (m_LinkProxyStruct.augment_3) {
|
||||
m_LinkBodyStruct.augment_3 = m_LinkProxyStruct.augment_3;
|
||||
if (m_LinkProxyStruct.augment_4)
|
||||
}
|
||||
if (m_LinkProxyStruct.augment_4) {
|
||||
m_LinkBodyStruct.augment_4 = m_LinkProxyStruct.augment_4;
|
||||
if (m_LinkProxyStruct.augment_5)
|
||||
}
|
||||
if (m_LinkProxyStruct.augment_5) {
|
||||
m_LinkBodyStruct.augment_5 = m_LinkProxyStruct.augment_5;
|
||||
if (m_LinkProxyStruct.augment_6)
|
||||
}
|
||||
if (m_LinkProxyStruct.augment_6) {
|
||||
m_LinkBodyStruct.augment_6 = m_LinkProxyStruct.augment_6;
|
||||
if (m_LinkProxyStruct.is_evolving)
|
||||
}
|
||||
if (m_LinkProxyStruct.is_evolving) {
|
||||
m_LinkBodyStruct.is_evolving = m_LinkProxyStruct.is_evolving;
|
||||
if (m_LinkProxyStruct.evolve_group)
|
||||
}
|
||||
if (m_LinkProxyStruct.evolve_group) {
|
||||
m_LinkBodyStruct.evolve_group = m_LinkProxyStruct.evolve_group;
|
||||
if (m_LinkProxyStruct.evolve_level)
|
||||
}
|
||||
if (m_LinkProxyStruct.evolve_level) {
|
||||
m_LinkBodyStruct.evolve_level = m_LinkProxyStruct.evolve_level;
|
||||
if (m_LinkProxyStruct.ornament_icon)
|
||||
}
|
||||
if (m_LinkProxyStruct.ornament_icon) {
|
||||
m_LinkBodyStruct.ornament_icon = m_LinkProxyStruct.ornament_icon;
|
||||
if (m_LinkProxyStruct.hash)
|
||||
}
|
||||
if (m_LinkProxyStruct.hash) {
|
||||
m_LinkBodyStruct.hash = m_LinkProxyStruct.hash;
|
||||
}
|
||||
|
||||
|
||||
if (m_TaskUse)
|
||||
if (m_TaskUse) {
|
||||
m_LinkBodyStruct.hash = 0x14505DC2;
|
||||
}
|
||||
|
||||
m_LinkBody = StringFormat(
|
||||
"%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X",
|
||||
@ -274,3 +290,53 @@ void EQEmu::SayLinkEngine::generate_text()
|
||||
|
||||
m_LinkText = "null";
|
||||
}
|
||||
|
||||
std::string EQEmu::SayLinkEngine::GenerateQuestSaylink(std::string saylink_text, bool silent, std::string link_name)
|
||||
{
|
||||
uint32 saylink_id = 0;
|
||||
|
||||
/**
|
||||
* Query for an existing phrase and id in the saylink table
|
||||
*/
|
||||
std::string query = StringFormat(
|
||||
"SELECT `id` FROM `saylink` WHERE `phrase` = '%s' LIMIT 1",
|
||||
EscapeString(saylink_text).c_str());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (results.Success()) {
|
||||
if (results.RowCount() >= 1) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
saylink_id = static_cast<uint32>(atoi(row[0]));
|
||||
}
|
||||
else {
|
||||
std::string insert_query = StringFormat(
|
||||
"INSERT INTO `saylink` (`phrase`) VALUES ('%s')",
|
||||
EscapeString(saylink_text).c_str());
|
||||
|
||||
results = database.QueryDatabase(insert_query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "Error in saylink phrase queries %s", results.ErrorMessage().c_str());
|
||||
}
|
||||
else {
|
||||
saylink_id = results.LastInsertedID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the actual link
|
||||
*/
|
||||
EQEmu::SayLinkEngine linker;
|
||||
linker.SetProxyItemID(SAYLINK_ITEM_ID);
|
||||
if (silent) {
|
||||
linker.SetProxyAugment2ID(saylink_id);
|
||||
}
|
||||
else {
|
||||
linker.SetProxyAugment1ID(saylink_id);
|
||||
}
|
||||
|
||||
linker.SetProxyText(link_name.c_str());
|
||||
|
||||
return linker.GenerateLink();
|
||||
}
|
||||
@ -101,6 +101,8 @@ namespace EQEmu
|
||||
const std::string& LinkBody() { return m_LinkBody; } // contains string format: '<LinkBody>'
|
||||
const std::string& LinkText() { return m_LinkText; } // contains string format: '<LinkText>'
|
||||
|
||||
static std::string GenerateQuestSaylink(std::string saylink_text, bool silent, std::string link_name);
|
||||
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
|
||||
@ -1175,19 +1175,17 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
|
||||
}
|
||||
}
|
||||
|
||||
const EQEmu::ItemData* SharedDatabase::GetItem(uint32 id) {
|
||||
if (id == 0)
|
||||
const EQEmu::ItemData *SharedDatabase::GetItem(uint32 id)
|
||||
{
|
||||
if (id == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!items_hash || id > items_hash->max_key())
|
||||
{
|
||||
if (!items_hash || id > items_hash->max_key()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(items_hash->exists(id))
|
||||
{
|
||||
if (items_hash->exists(id)) {
|
||||
return &(items_hash->at(id));
|
||||
}
|
||||
|
||||
|
||||
@ -63,6 +63,33 @@ const std::string vStringFormat(const char* format, va_list args)
|
||||
return output;
|
||||
}
|
||||
|
||||
const std::string str_tolower(std::string s)
|
||||
{
|
||||
std::transform(
|
||||
s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); }
|
||||
);
|
||||
return s;
|
||||
}
|
||||
|
||||
const std::string str_toupper(std::string s)
|
||||
{
|
||||
std::transform(
|
||||
s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c) { return std::toupper(c); }
|
||||
);
|
||||
return s;
|
||||
}
|
||||
|
||||
const std::string ucfirst(std::string s)
|
||||
{
|
||||
std::string output = s;
|
||||
if (!s.empty())
|
||||
output[0] = static_cast<char>(toupper(s[0]));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
const std::string StringFormat(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
@ -24,6 +24,9 @@
|
||||
#include "types.h"
|
||||
|
||||
//std::string based
|
||||
const std::string str_tolower(std::string s);
|
||||
const std::string str_toupper(std::string s);
|
||||
const std::string ucfirst(std::string s);
|
||||
const std::string StringFormat(const char* format, ...);
|
||||
const std::string vStringFormat(const char* format, va_list args);
|
||||
std::vector<std::string> SplitString(const std::string &s, char delim);
|
||||
|
||||
@ -82,10 +82,12 @@ SET(zone_sources
|
||||
merc.cpp
|
||||
mob.cpp
|
||||
mob_ai.cpp
|
||||
mob_info.cpp
|
||||
mod_functions.cpp
|
||||
net.cpp
|
||||
npc.cpp
|
||||
npc_ai.cpp
|
||||
npc_scale_manager.cpp
|
||||
object.cpp
|
||||
oriented_bounding_box.cpp
|
||||
pathfinder_interface.cpp
|
||||
@ -137,8 +139,7 @@ SET(zone_sources
|
||||
zone.cpp
|
||||
zone_config.cpp
|
||||
zonedb.cpp
|
||||
zoning.cpp
|
||||
)
|
||||
zoning.cpp)
|
||||
|
||||
SET(zone_headers
|
||||
aa.h
|
||||
@ -207,6 +208,7 @@ SET(zone_headers
|
||||
net.h
|
||||
npc.h
|
||||
npc_ai.h
|
||||
npc_scale_manager.h
|
||||
object.h
|
||||
oriented_bounding_box.h
|
||||
pathfinder_interface.h
|
||||
@ -242,8 +244,7 @@ SET(zone_headers
|
||||
zone.h
|
||||
zone_config.h
|
||||
zonedb.h
|
||||
zonedump.h
|
||||
)
|
||||
zonedump.h)
|
||||
|
||||
IF(EQEMU_DEPOP_INVALIDATES_CACHE)
|
||||
ADD_DEFINITIONS(-DDEPOP_INVALIDATES_NPC_TYPES_CACHE)
|
||||
|
||||
@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <boost/concept_check.hpp>
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
@ -5463,3 +5464,8 @@ bool Mob::GetWasSpawnedInWater() const {
|
||||
void Mob::SetSpawnedInWater(bool spawned_in_water) {
|
||||
Mob::spawned_in_water = spawned_in_water;
|
||||
}
|
||||
|
||||
int32 Mob::GetHPRegen() const
|
||||
{
|
||||
return hp_regen;
|
||||
}
|
||||
@ -254,7 +254,6 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
InitializeMercInfo();
|
||||
SetMerc(0);
|
||||
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true, false);
|
||||
logging_enabled = CLIENT_DEFAULT_LOGGING_ENABLED;
|
||||
|
||||
//for good measure:
|
||||
memset(&m_pp, 0, sizeof(m_pp));
|
||||
@ -6670,30 +6669,13 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
std::string class_Name = itoa(GetClass());
|
||||
std::string class_List[] = { "WAR", "CLR", "PAL", "RNG", "SHD", "DRU", "MNK", "BRD", "ROG", "SHM", "NEC", "WIZ", "MAG", "ENC", "BST", "BER" };
|
||||
|
||||
if(GetClass() < 17 && GetClass() > 0) { class_Name = class_List[GetClass()-1]; }
|
||||
if (GetClass() < 17 && GetClass() > 0) {
|
||||
class_Name = class_List[GetClass() - 1];
|
||||
}
|
||||
|
||||
// Race
|
||||
std::string race_Name = itoa(GetRace());
|
||||
switch(GetRace())
|
||||
{
|
||||
case 1: race_Name = "Human"; break;
|
||||
case 2: race_Name = "Barbarian"; break;
|
||||
case 3: race_Name = "Erudite"; break;
|
||||
case 4: race_Name = "Wood Elf"; break;
|
||||
case 5: race_Name = "High Elf"; break;
|
||||
case 6: race_Name = "Dark Elf"; break;
|
||||
case 7: race_Name = "Half Elf"; break;
|
||||
case 8: race_Name = "Dwarf"; break;
|
||||
case 9: race_Name = "Troll"; break;
|
||||
case 10: race_Name = "Ogre"; break;
|
||||
case 11: race_Name = "Halfing"; break;
|
||||
case 12: race_Name = "Gnome"; break;
|
||||
case 128: race_Name = "Iksar"; break;
|
||||
case 130: race_Name = "Vah Shir"; break;
|
||||
case 330: race_Name = "Froglok"; break;
|
||||
case 522: race_Name = "Drakkin"; break;
|
||||
default: break;
|
||||
}
|
||||
std::string race_name = GetRaceIDName(GetRace());
|
||||
|
||||
/*##########################################################
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
H/M/E String
|
||||
@ -7122,7 +7104,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
|
||||
std::ostringstream final_string;
|
||||
final_string <<
|
||||
/* C/L/R */ indP << "Class: " << class_Name << indS << "Level: " << static_cast<int>(GetLevel()) << indS << "Race: " << race_Name << "<br>" <<
|
||||
/* C/L/R */ indP << "Class: " << class_Name << indS << "Level: " << static_cast<int>(GetLevel()) << indS << "Race: " << race_name << "<br>" <<
|
||||
/* Runes */ indP << "Rune: " << rune_number << indL << indS << "Spell Rune: " << magic_rune_number << "<br>" <<
|
||||
/* HP/M/E */ HME_row <<
|
||||
/* DS */ indP << "DS: " << (itembonuses.DamageShield + spellbonuses.DamageShield*-1) << " (Spell: " << (spellbonuses.DamageShield*-1) << " + Item: " << itembonuses.DamageShield << " / " << RuleI(Character, ItemDamageShieldCap) << ")<br>" <<
|
||||
|
||||
@ -851,7 +851,6 @@ public:
|
||||
void SetAATitle(const char *Title);
|
||||
void SetTitleSuffix(const char *txt);
|
||||
void MemorizeSpell(uint32 slot, uint32 spellid, uint32 scribing);
|
||||
int32 acmod();
|
||||
|
||||
// Item methods
|
||||
void EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
@ -275,9 +275,10 @@ int32 Client::CalcHPRegen(bool bCombat)
|
||||
if (!skip_innate && m_pp.InnateSkills[InnateRegen] != InnateDisabled) {
|
||||
if (level >= 50) {
|
||||
++base;
|
||||
if (level >= 55)
|
||||
if (level >= 55) {
|
||||
++base;
|
||||
}
|
||||
}
|
||||
base *= 2;
|
||||
}
|
||||
|
||||
@ -331,6 +332,7 @@ int32 Client::CalcMaxHP()
|
||||
if (hp_perc_cap) {
|
||||
int curHP_cap = (max_hp * hp_perc_cap) / 100;
|
||||
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1])) {
|
||||
|
||||
cur_hp = curHP_cap;
|
||||
}
|
||||
}
|
||||
@ -470,6 +472,7 @@ uint32 Mob::GetClassLevelFactor()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
@ -560,537 +563,6 @@ int32 Client::GetRawItemAC()
|
||||
return Total;
|
||||
}
|
||||
|
||||
int32 Client::acmod()
|
||||
{
|
||||
int agility = GetAGI();
|
||||
int level = GetLevel();
|
||||
if (agility < 1 || level < 1) {
|
||||
return (0);
|
||||
}
|
||||
if (agility <= 74) {
|
||||
if (agility == 1) {
|
||||
return -24;
|
||||
}
|
||||
else if (agility <= 3) {
|
||||
return -23;
|
||||
}
|
||||
else if (agility == 4) {
|
||||
return -22;
|
||||
}
|
||||
else if (agility <= 6) {
|
||||
return -21;
|
||||
}
|
||||
else if (agility <= 8) {
|
||||
return -20;
|
||||
}
|
||||
else if (agility == 9) {
|
||||
return -19;
|
||||
}
|
||||
else if (agility <= 11) {
|
||||
return -18;
|
||||
}
|
||||
else if (agility == 12) {
|
||||
return -17;
|
||||
}
|
||||
else if (agility <= 14) {
|
||||
return -16;
|
||||
}
|
||||
else if (agility <= 16) {
|
||||
return -15;
|
||||
}
|
||||
else if (agility == 17) {
|
||||
return -14;
|
||||
}
|
||||
else if (agility <= 19) {
|
||||
return -13;
|
||||
}
|
||||
else if (agility == 20) {
|
||||
return -12;
|
||||
}
|
||||
else if (agility <= 22) {
|
||||
return -11;
|
||||
}
|
||||
else if (agility <= 24) {
|
||||
return -10;
|
||||
}
|
||||
else if (agility == 25) {
|
||||
return -9;
|
||||
}
|
||||
else if (agility <= 27) {
|
||||
return -8;
|
||||
}
|
||||
else if (agility == 28) {
|
||||
return -7;
|
||||
}
|
||||
else if (agility <= 30) {
|
||||
return -6;
|
||||
}
|
||||
else if (agility <= 32) {
|
||||
return -5;
|
||||
}
|
||||
else if (agility == 33) {
|
||||
return -4;
|
||||
}
|
||||
else if (agility <= 35) {
|
||||
return -3;
|
||||
}
|
||||
else if (agility == 36) {
|
||||
return -2;
|
||||
}
|
||||
else if (agility <= 38) {
|
||||
return -1;
|
||||
}
|
||||
else if (agility <= 65) {
|
||||
return 0;
|
||||
}
|
||||
else if (agility <= 70) {
|
||||
return 1;
|
||||
}
|
||||
else if (agility <= 74) {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
else if (agility <= 137) {
|
||||
if (agility == 75) {
|
||||
if (level <= 6) {
|
||||
return 9;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 23;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 33;
|
||||
}
|
||||
else {
|
||||
return 39;
|
||||
}
|
||||
}
|
||||
else if (agility >= 76 && agility <= 79) {
|
||||
if (level <= 6) {
|
||||
return 10;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 23;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 33;
|
||||
}
|
||||
else {
|
||||
return 40;
|
||||
}
|
||||
}
|
||||
else if (agility == 80) {
|
||||
if (level <= 6) {
|
||||
return 11;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 24;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 34;
|
||||
}
|
||||
else {
|
||||
return 41;
|
||||
}
|
||||
}
|
||||
else if (agility >= 81 && agility <= 85) {
|
||||
if (level <= 6) {
|
||||
return 12;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 25;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 35;
|
||||
}
|
||||
else {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
else if (agility >= 86 && agility <= 90) {
|
||||
if (level <= 6) {
|
||||
return 12;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 26;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 36;
|
||||
}
|
||||
else {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
else if (agility >= 91 && agility <= 95) {
|
||||
if (level <= 6) {
|
||||
return 13;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 26;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 36;
|
||||
}
|
||||
else {
|
||||
return 43;
|
||||
}
|
||||
}
|
||||
else if (agility >= 96 && agility <= 99) {
|
||||
if (level <= 6) {
|
||||
return 14;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 27;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 37;
|
||||
}
|
||||
else {
|
||||
return 44;
|
||||
}
|
||||
}
|
||||
else if (agility == 100 && level >= 7) {
|
||||
if (level <= 19) {
|
||||
return 28;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 38;
|
||||
}
|
||||
else {
|
||||
return 45;
|
||||
}
|
||||
}
|
||||
else if (level <= 6) {
|
||||
return 15;
|
||||
}
|
||||
//level is >6
|
||||
else if (agility >= 101 && agility <= 105) {
|
||||
if (level <= 19) {
|
||||
return 29;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 39; // not verified
|
||||
}
|
||||
else {
|
||||
return 45;
|
||||
}
|
||||
}
|
||||
else if (agility >= 106 && agility <= 110) {
|
||||
if (level <= 19) {
|
||||
return 29;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 39; // not verified
|
||||
}
|
||||
else {
|
||||
return 46;
|
||||
}
|
||||
}
|
||||
else if (agility >= 111 && agility <= 115) {
|
||||
if (level <= 19) {
|
||||
return 30;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 40; // not verified
|
||||
}
|
||||
else {
|
||||
return 47;
|
||||
}
|
||||
}
|
||||
else if (agility >= 116 && agility <= 119) {
|
||||
if (level <= 19) {
|
||||
return 31;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 41;
|
||||
}
|
||||
else {
|
||||
return 47;
|
||||
}
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 32;
|
||||
}
|
||||
//level is > 19
|
||||
else if (agility == 120) {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 48;
|
||||
}
|
||||
}
|
||||
else if (agility <= 125) {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 49;
|
||||
}
|
||||
}
|
||||
else if (agility <= 135) {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 50;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 51;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (agility <= 300) {
|
||||
if (level <= 6) {
|
||||
if (agility <= 139) {
|
||||
return (21);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (22);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (23);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (23);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (24);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (25);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (26);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (26);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (27);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (28);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (28);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (29);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (30);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (31);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (31);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (32);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (33);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (34);
|
||||
}
|
||||
else {
|
||||
return (35);
|
||||
}
|
||||
}
|
||||
else if (level <= 19) {
|
||||
if (agility <= 139) {
|
||||
return (34);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (35);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (36);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (37);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (37);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (38);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (39);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (40);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (40);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (41);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (42);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (43);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (43);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (44);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (45);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (45);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (46);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (47);
|
||||
}
|
||||
else {
|
||||
return (48);
|
||||
}
|
||||
}
|
||||
else if (level <= 39) {
|
||||
if (agility <= 139) {
|
||||
return (44);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (45);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (46);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (47);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (47);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (48);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (49);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (50);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (50);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (51);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (52);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (54);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (55);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (55);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (56);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (57);
|
||||
}
|
||||
else {
|
||||
return (58);
|
||||
}
|
||||
}
|
||||
else { //lvl >= 40
|
||||
if (agility <= 139) {
|
||||
return (51);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (52);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (54);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (55);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (56);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (56);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (57);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (58);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (58);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (59);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (60);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (61);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (61);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (62);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (63);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (64);
|
||||
}
|
||||
else {
|
||||
return (65);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//seems about 21 agil per extra AC pt over 300...
|
||||
return (65 + ((agility - 300) / 21));
|
||||
}
|
||||
Log(Logs::Detail, Logs::Error, "Error in Client::acmod(): Agility: %i, Level: %i", agility, level);
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32 Client::CalcMaxMana()
|
||||
{
|
||||
switch (GetCasterClass()) {
|
||||
|
||||
303
zone/command.cpp
303
zone/command.cpp
@ -249,6 +249,7 @@ int command_init(void)
|
||||
command_add("lastname", "[new lastname] - Set your or your player target's lastname", 50, command_lastname) ||
|
||||
command_add("level", "[level] - Set your or your target's level", 10, command_level) ||
|
||||
command_add("listnpcs", "[name/range] - Search NPCs", 20, command_listnpcs) ||
|
||||
command_add("list", "[npc] [name|all] - Search entities", 20, command_list) ||
|
||||
command_add("listpetition", "- List petitions", 50, command_listpetition) ||
|
||||
command_add("load_shared_memory", "[shared_memory_name] - Reloads shared memory and uses the input as output", 250, command_load_shared_memory) ||
|
||||
command_add("loc", "- Print out your or your target's current location and heading", 0, command_loc) ||
|
||||
@ -1328,16 +1329,266 @@ void command_delpetition(Client *c, const Seperator *sep)
|
||||
|
||||
void command_listnpcs(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (strcasecmp(sep->arg[1], "all") == 0)
|
||||
entity_list.ListNPCs(c,sep->arg[1],sep->arg[2],0);
|
||||
else if(sep->IsNumber(1) && sep->IsNumber(2))
|
||||
entity_list.ListNPCs(c,sep->arg[1],sep->arg[2],2);
|
||||
else if(sep->arg[1][0] != 0)
|
||||
entity_list.ListNPCs(c,sep->arg[1],sep->arg[2],1);
|
||||
c->Message(0, "Deprecated, use the #list command (#list npcs <search>)");
|
||||
}
|
||||
|
||||
void command_list(Client *c, const Seperator *sep)
|
||||
{
|
||||
std::string search_type;
|
||||
if (strcasecmp(sep->arg[1], "npcs") == 0) {
|
||||
search_type = "npcs";
|
||||
}
|
||||
|
||||
if (strcasecmp(sep->arg[1], "players") == 0) {
|
||||
search_type = "players";
|
||||
}
|
||||
|
||||
if (strcasecmp(sep->arg[1], "corpses") == 0) {
|
||||
search_type = "corpses";
|
||||
}
|
||||
|
||||
if (strcasecmp(sep->arg[1], "doors") == 0) {
|
||||
search_type = "doors";
|
||||
}
|
||||
|
||||
if (strcasecmp(sep->arg[1], "objects") == 0) {
|
||||
search_type = "objects";
|
||||
}
|
||||
|
||||
if (search_type.length() > 0) {
|
||||
|
||||
int entity_count = 0;
|
||||
int found_count = 0;
|
||||
|
||||
std::string search_string;
|
||||
|
||||
if (sep->arg[2]) {
|
||||
search_string = sep->arg[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* NPC
|
||||
*/
|
||||
if (search_type.find("npcs") != std::string::npos) {
|
||||
auto &entity_list_search = entity_list.GetMobList();
|
||||
|
||||
for (auto &itr : entity_list_search) {
|
||||
Mob *entity = itr.second;
|
||||
if (!entity->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entity_count++;
|
||||
|
||||
std::string entity_name = entity->GetCleanName();
|
||||
|
||||
/**
|
||||
* Filter by name
|
||||
*/
|
||||
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string saylink = StringFormat(
|
||||
"#goto %.0f %0.f %.0f",
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ());
|
||||
|
||||
c->Message(
|
||||
0,
|
||||
"| %s | ID %5d | %s | x %.0f | y %0.f | z %.0f",
|
||||
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Goto").c_str(),
|
||||
entity->GetID(),
|
||||
entity->GetName(),
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Client
|
||||
*/
|
||||
if (search_type.find("players") != std::string::npos) {
|
||||
auto &entity_list_search = entity_list.GetClientList();
|
||||
|
||||
for (auto &itr : entity_list_search) {
|
||||
Client *entity = itr.second;
|
||||
|
||||
entity_count++;
|
||||
|
||||
std::string entity_name = entity->GetCleanName();
|
||||
|
||||
/**
|
||||
* Filter by name
|
||||
*/
|
||||
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string saylink = StringFormat(
|
||||
"#goto %.0f %0.f %.0f",
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ());
|
||||
|
||||
c->Message(
|
||||
0,
|
||||
"| %s | ID %5d | %s | x %.0f | y %0.f | z %.0f",
|
||||
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Goto").c_str(),
|
||||
entity->GetID(),
|
||||
entity->GetName(),
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Corpse
|
||||
*/
|
||||
if (search_type.find("corpses") != std::string::npos) {
|
||||
auto &entity_list_search = entity_list.GetCorpseList();
|
||||
|
||||
for (auto &itr : entity_list_search) {
|
||||
Corpse *entity = itr.second;
|
||||
|
||||
entity_count++;
|
||||
|
||||
std::string entity_name = entity->GetCleanName();
|
||||
|
||||
/**
|
||||
* Filter by name
|
||||
*/
|
||||
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string saylink = StringFormat(
|
||||
"#goto %.0f %0.f %.0f",
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ());
|
||||
|
||||
c->Message(
|
||||
0,
|
||||
"| %s | ID %5d | %s | x %.0f | y %0.f | z %.0f",
|
||||
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Goto").c_str(),
|
||||
entity->GetID(),
|
||||
entity->GetName(),
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Doors
|
||||
*/
|
||||
if (search_type.find("doors") != std::string::npos) {
|
||||
auto &entity_list_search = entity_list.GetDoorsList();
|
||||
|
||||
for (auto &itr : entity_list_search) {
|
||||
Doors * entity = itr.second;
|
||||
|
||||
entity_count++;
|
||||
|
||||
std::string entity_name = entity->GetDoorName();
|
||||
|
||||
/**
|
||||
* Filter by name
|
||||
*/
|
||||
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string saylink = StringFormat(
|
||||
"#goto %.0f %0.f %.0f",
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ());
|
||||
|
||||
c->Message(
|
||||
0,
|
||||
"| %s | Entity ID %5d | Door ID %i | %s | x %.0f | y %0.f | z %.0f",
|
||||
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Goto").c_str(),
|
||||
entity->GetID(),
|
||||
entity->GetDoorID(),
|
||||
entity->GetDoorName(),
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Objects
|
||||
*/
|
||||
if (search_type.find("objects") != std::string::npos) {
|
||||
auto &entity_list_search = entity_list.GetObjectList();
|
||||
|
||||
for (auto &itr : entity_list_search) {
|
||||
Object * entity = itr.second;
|
||||
|
||||
entity_count++;
|
||||
|
||||
std::string entity_name = entity->GetModelName();
|
||||
|
||||
/**
|
||||
* Filter by name
|
||||
*/
|
||||
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string saylink = StringFormat(
|
||||
"#goto %.0f %0.f %.0f",
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ());
|
||||
|
||||
c->Message(
|
||||
0,
|
||||
"| %s | Entity ID %5d | Object DBID %i | %s | x %.0f | y %0.f | z %.0f",
|
||||
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Goto").c_str(),
|
||||
entity->GetID(),
|
||||
entity->GetDBID(),
|
||||
entity->GetModelName(),
|
||||
entity->GetX(),
|
||||
entity->GetY(),
|
||||
entity->GetZ()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_count) {
|
||||
c->Message(
|
||||
0, "Found (%i) of type (%s) in zone (%i) total",
|
||||
found_count,
|
||||
search_type.c_str(),
|
||||
entity_count
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Usage of #listnpcs:");
|
||||
c->Message(0, "#listnpcs [#] [#] (Each number would search by ID, ex. #listnpcs 1 30, searches 1-30)");
|
||||
c->Message(0, "#listnpcs [name] (Would search for a npc with [name])");
|
||||
c->Message(0, "Usage of #list");
|
||||
c->Message(0, "- #list [npcs|players|corpses|doors|objects] [search]");
|
||||
c->Message(0, "- Example: #list npc (Blank for all)");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1460,24 +1711,24 @@ void command_npcstats(Client *c, const Seperator *sep)
|
||||
c->Message(0, "ERROR: Target is not a NPC!");
|
||||
else {
|
||||
auto target_npc = c->GetTarget()->CastToNPC();
|
||||
c->Message(0, "NPC Stats:");
|
||||
c->Message(0, "Name: %s NpcID: %u", target_npc->GetName(), target_npc->GetNPCTypeID());
|
||||
c->Message(0, "Race: %i Level: %i Class: %i Material: %i", target_npc->GetRace(), target_npc->GetLevel(), target_npc->GetClass(), target_npc->GetTexture());
|
||||
c->Message(0, "Current HP: %i Max HP: %i", target_npc->GetHP(), target_npc->GetMaxHP());
|
||||
c->Message(0, "# NPC Stats");
|
||||
c->Message(0, "- Name: %s NpcID: %u", target_npc->GetName(), target_npc->GetNPCTypeID());
|
||||
c->Message(0, "- Race: %i Level: %i Class: %i Material: %i", target_npc->GetRace(), target_npc->GetLevel(), target_npc->GetClass(), target_npc->GetTexture());
|
||||
c->Message(0, "- Current HP: %i Max HP: %i", target_npc->GetHP(), target_npc->GetMaxHP());
|
||||
//c->Message(0, "Weapon Item Number: %s", target_npc->GetWeapNo());
|
||||
c->Message(0, "Gender: %i Size: %f Bodytype: %d", target_npc->GetGender(), target_npc->GetSize(), target_npc->GetBodyType());
|
||||
c->Message(0, "Runspeed: %.3f Walkspeed: %.3f", static_cast<float>(0.025f * target_npc->GetRunspeed()), static_cast<float>(0.025f * target_npc->GetWalkspeed()));
|
||||
c->Message(0, "Spawn Group: %i Grid: %i", target_npc->GetSp2(), target_npc->GetGrid());
|
||||
c->Message(0, "- Gender: %i Size: %f Bodytype: %d", target_npc->GetGender(), target_npc->GetSize(), target_npc->GetBodyType());
|
||||
c->Message(0, "- Runspeed: %.3f Walkspeed: %.3f", static_cast<float>(0.025f * target_npc->GetRunspeed()), static_cast<float>(0.025f * target_npc->GetWalkspeed()));
|
||||
c->Message(0, "- Spawn Group: %i Grid: %i", target_npc->GetSp2(), target_npc->GetGrid());
|
||||
if (target_npc->proximity) {
|
||||
c->Message(0, "Proximity: Enabled");
|
||||
c->Message(0, "Cur_X: %1.3f, Cur_Y: %1.3f, Cur_Z: %1.3f", target_npc->GetX(), target_npc->GetY(), target_npc->GetZ());
|
||||
c->Message(0, "Min_X: %1.3f(%1.3f), Max_X: %1.3f(%1.3f), X_Range: %1.3f", target_npc->proximity->min_x, (target_npc->proximity->min_x - target_npc->GetX()), target_npc->proximity->max_x, (target_npc->proximity->max_x - target_npc->GetX()), (target_npc->proximity->max_x - target_npc->proximity->min_x));
|
||||
c->Message(0, "Min_Y: %1.3f(%1.3f), Max_Y: %1.3f(%1.3f), Y_Range: %1.3f", target_npc->proximity->min_y, (target_npc->proximity->min_y - target_npc->GetY()), target_npc->proximity->max_y, (target_npc->proximity->max_y - target_npc->GetY()), (target_npc->proximity->max_y - target_npc->proximity->min_y));
|
||||
c->Message(0, "Min_Z: %1.3f(%1.3f), Max_Z: %1.3f(%1.3f), Z_Range: %1.3f", target_npc->proximity->min_z, (target_npc->proximity->min_z - target_npc->GetZ()), target_npc->proximity->max_z, (target_npc->proximity->max_z - target_npc->GetZ()), (target_npc->proximity->max_z - target_npc->proximity->min_z));
|
||||
c->Message(0, "Say: %s", (target_npc->proximity->say ? "Enabled" : "Disabled"));
|
||||
c->Message(0, "- Proximity: Enabled");
|
||||
c->Message(0, "-- Cur_X: %1.3f, Cur_Y: %1.3f, Cur_Z: %1.3f", target_npc->GetX(), target_npc->GetY(), target_npc->GetZ());
|
||||
c->Message(0, "-- Min_X: %1.3f(%1.3f), Max_X: %1.3f(%1.3f), X_Range: %1.3f", target_npc->proximity->min_x, (target_npc->proximity->min_x - target_npc->GetX()), target_npc->proximity->max_x, (target_npc->proximity->max_x - target_npc->GetX()), (target_npc->proximity->max_x - target_npc->proximity->min_x));
|
||||
c->Message(0, "-- Min_Y: %1.3f(%1.3f), Max_Y: %1.3f(%1.3f), Y_Range: %1.3f", target_npc->proximity->min_y, (target_npc->proximity->min_y - target_npc->GetY()), target_npc->proximity->max_y, (target_npc->proximity->max_y - target_npc->GetY()), (target_npc->proximity->max_y - target_npc->proximity->min_y));
|
||||
c->Message(0, "-- Min_Z: %1.3f(%1.3f), Max_Z: %1.3f(%1.3f), Z_Range: %1.3f", target_npc->proximity->min_z, (target_npc->proximity->min_z - target_npc->GetZ()), target_npc->proximity->max_z, (target_npc->proximity->max_z - target_npc->GetZ()), (target_npc->proximity->max_z - target_npc->proximity->min_z));
|
||||
c->Message(0, "-- Say: %s", (target_npc->proximity->say ? "Enabled" : "Disabled"));
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Proximity: Disabled");
|
||||
c->Message(0, "-Proximity: Disabled");
|
||||
}
|
||||
c->Message(0, "");
|
||||
c->Message(0, "EmoteID: %i", target_npc->GetEmoteID());
|
||||
@ -2049,9 +2300,10 @@ void command_grid(Client *c, const Seperator *sep)
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
|
||||
Mob *mob = itr->second;
|
||||
if (mob->IsNPC() && mob->GetRace() == 2254)
|
||||
if (mob->IsNPC() && mob->GetRace() == 2254) {
|
||||
mob->Depop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn grid nodes
|
||||
@ -2070,8 +2322,9 @@ void command_grid(Client *c, const Seperator *sep)
|
||||
npc->GMMove(node_position.x, node_position.y, node_position.z, node_position.w);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp("delete", sep->arg[1]) == 0)
|
||||
else if (strcasecmp("delete", sep->arg[1]) == 0) {
|
||||
database.ModifyGrid(c, true, atoi(sep->arg[2]), 0, 0, zone->GetZoneID());
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Usage: #grid add/delete grid_num wandertype pausetype");
|
||||
c->Message(0, "Usage: #grid max - displays the highest grid ID used in this zone (for add)");
|
||||
|
||||
@ -152,6 +152,7 @@ void command_kill(Client *c, const Seperator *sep);
|
||||
void command_lastname(Client *c, const Seperator *sep);
|
||||
void command_level(Client *c, const Seperator *sep);
|
||||
void command_listnpcs(Client *c, const Seperator *sep);
|
||||
void command_list(Client *c, const Seperator *sep);
|
||||
void command_listpetition(Client *c, const Seperator *sep);
|
||||
void command_load_shared_memory(Client *c, const Seperator *sep);
|
||||
void command_loc(Client *c, const Seperator *sep);
|
||||
|
||||
@ -843,3 +843,17 @@ void Doors::CreateDatabaseEntry()
|
||||
);
|
||||
}
|
||||
|
||||
float Doors::GetX()
|
||||
{
|
||||
return m_Position.x;
|
||||
}
|
||||
|
||||
float Doors::GetY()
|
||||
{
|
||||
return m_Position.y;
|
||||
}
|
||||
|
||||
float Doors::GetZ()
|
||||
{
|
||||
return m_Position.z;
|
||||
}
|
||||
|
||||
@ -64,6 +64,10 @@ public:
|
||||
void SetSize(uint16 size);
|
||||
void ToggleState(Mob *sender);
|
||||
|
||||
float GetX();
|
||||
float GetY();
|
||||
float GetZ();
|
||||
|
||||
private:
|
||||
|
||||
uint32 database_id;
|
||||
|
||||
@ -3025,7 +3025,7 @@ XS(XS__saylink) {
|
||||
Perl_croak(aTHX_ "Usage: quest::saylink(string message, [bool silent = false], [link_name = message])");
|
||||
dXSTARG;
|
||||
|
||||
Const_char *RETVAL;
|
||||
std::string RETVAL;
|
||||
char message[250];
|
||||
char link_name[250];
|
||||
bool silent = false;
|
||||
@ -3039,7 +3039,8 @@ XS(XS__saylink) {
|
||||
strcpy(link_name, message);
|
||||
|
||||
RETVAL = quest_manager.saylink(message, silent, link_name);
|
||||
sv_setpv(TARG, RETVAL);
|
||||
|
||||
sv_setpv(TARG, RETVAL.c_str());
|
||||
XSprePUSH;
|
||||
PUSHTARG;
|
||||
XSRETURN(1);
|
||||
|
||||
@ -40,6 +40,8 @@
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
#include "water_map.h"
|
||||
#include "npc_scale_manager.h"
|
||||
#include "../common/say_link.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
@ -2753,58 +2755,6 @@ char *EntityList::RemoveNumbers(char *name)
|
||||
return name;
|
||||
}
|
||||
|
||||
void EntityList::ListNPCs(Client* client, const char *arg1, const char *arg2, uint8 searchtype)
|
||||
{
|
||||
if (arg1 == 0)
|
||||
searchtype = 0;
|
||||
else if (arg2 == 0 && searchtype >= 2)
|
||||
searchtype = 0;
|
||||
uint32 x = 0;
|
||||
uint32 z = 0;
|
||||
char sName[36];
|
||||
|
||||
auto it = npc_list.begin();
|
||||
client->Message(0, "NPCs in the zone:");
|
||||
if (searchtype == 0) {
|
||||
while (it != npc_list.end()) {
|
||||
NPC *n = it->second;
|
||||
|
||||
client->Message(0, " %5d: %s (%.0f, %0.f, %.0f)", n->GetID(), n->GetName(), n->GetX(), n->GetY(), n->GetZ());
|
||||
x++;
|
||||
z++;
|
||||
++it;
|
||||
}
|
||||
} else if (searchtype == 1) {
|
||||
client->Message(0, "Searching by name method. (%s)",arg1);
|
||||
auto tmp = new char[strlen(arg1) + 1];
|
||||
strcpy(tmp, arg1);
|
||||
strupr(tmp);
|
||||
while (it != npc_list.end()) {
|
||||
z++;
|
||||
strcpy(sName, it->second->GetName());
|
||||
strupr(sName);
|
||||
if (strstr(sName, tmp)) {
|
||||
NPC *n = it->second;
|
||||
client->Message(0, " %5d: %s (%.0f, %.0f, %.0f)", n->GetID(), n->GetName(), n->GetX(), n->GetY(), n->GetZ());
|
||||
x++;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
safe_delete_array(tmp);
|
||||
} else if (searchtype == 2) {
|
||||
client->Message(0, "Searching by number method. (%s %s)",arg1,arg2);
|
||||
while (it != npc_list.end()) {
|
||||
z++;
|
||||
if ((it->second->GetID() >= atoi(arg1)) && (it->second->GetID() <= atoi(arg2)) && (atoi(arg1) <= atoi(arg2))) {
|
||||
client->Message(0, " %5d: %s", it->second->GetID(), it->second->GetName());
|
||||
x++;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
client->Message(0, "%d npcs listed. There is a total of %d npcs in this zone.", x, z);
|
||||
}
|
||||
|
||||
void EntityList::ListNPCCorpses(Client *client)
|
||||
{
|
||||
uint32 x = 0;
|
||||
|
||||
@ -382,7 +382,6 @@ public:
|
||||
void SendPetitionToAdmins();
|
||||
void AddLootToNPCS(uint32 item_id, uint32 count);
|
||||
|
||||
void ListNPCs(Client* client, const char* arg1 = 0, const char* arg2 = 0, uint8 searchtype = 0);
|
||||
void ListNPCCorpses(Client* client);
|
||||
void ListPlayerCorpses(Client* client);
|
||||
int32 DeleteNPCCorpses();
|
||||
|
||||
@ -789,33 +789,29 @@ int lua_merchant_count_item(uint32 npc_id, uint32 item_id) {
|
||||
|
||||
std::string lua_item_link(int item_id) {
|
||||
char text[250] = { 0 };
|
||||
quest_manager.varlink(text, item_id);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.varlink(text, item_id);
|
||||
}
|
||||
|
||||
std::string lua_say_link(const char *phrase, bool silent, const char *link_name) {
|
||||
char text[256] = { 0 };
|
||||
strncpy(text, phrase, 255);
|
||||
quest_manager.saylink(text, silent, link_name);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.saylink(text, silent, link_name);
|
||||
}
|
||||
|
||||
std::string lua_say_link(const char *phrase, bool silent) {
|
||||
char text[256] = { 0 };
|
||||
strncpy(text, phrase, 255);
|
||||
quest_manager.saylink(text, silent, text);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.saylink(text, silent, text);
|
||||
}
|
||||
|
||||
std::string lua_say_link(const char *phrase) {
|
||||
char text[256] = { 0 };
|
||||
strncpy(text, phrase, 255);
|
||||
quest_manager.saylink(text, false, text);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.saylink(text, false, text);
|
||||
}
|
||||
|
||||
std::string lua_get_data(std::string bucket_key) {
|
||||
|
||||
91
zone/mob.cpp
91
zone/mob.cpp
@ -38,7 +38,8 @@ extern EntityList entity_list;
|
||||
extern Zone* zone;
|
||||
extern WorldServer worldserver;
|
||||
|
||||
Mob::Mob(const char* in_name,
|
||||
Mob::Mob(
|
||||
const char *in_name,
|
||||
const char *in_lastname,
|
||||
int32 in_cur_hp,
|
||||
int32 in_max_hp,
|
||||
@ -118,6 +119,7 @@ Mob::Mob(const char* in_name,
|
||||
position_update_melee_push_timer(500),
|
||||
hate_list_cleanup_timer(6000)
|
||||
{
|
||||
|
||||
targeted = 0;
|
||||
tar_ndx = 0;
|
||||
tar_vector = 0;
|
||||
@ -140,8 +142,9 @@ Mob::Mob(const char* in_name,
|
||||
strn0cpy(name, in_name, 64);
|
||||
strn0cpy(orig_name, in_name, 64);
|
||||
}
|
||||
if (in_lastname)
|
||||
if (in_lastname) {
|
||||
strn0cpy(lastname, in_lastname, 64);
|
||||
}
|
||||
cur_hp = in_cur_hp;
|
||||
max_hp = in_max_hp;
|
||||
base_hp = in_max_hp;
|
||||
@ -160,8 +163,9 @@ Mob::Mob(const char* in_name,
|
||||
base_size = size;
|
||||
runspeed = in_runspeed;
|
||||
// neotokyo: sanity check
|
||||
if (runspeed < 0 || runspeed > 20)
|
||||
if (runspeed < 0 || runspeed > 20) {
|
||||
runspeed = 1.25f;
|
||||
}
|
||||
base_runspeed = (int) ((float) runspeed * 40.0f);
|
||||
// clients
|
||||
if (runspeed == 0.7f) {
|
||||
@ -188,8 +192,9 @@ Mob::Mob(const char* in_name,
|
||||
|
||||
|
||||
// sanity check
|
||||
if (runspeed < 0 || runspeed > 20)
|
||||
if (runspeed < 0 || runspeed > 20) {
|
||||
runspeed = 1.25f;
|
||||
}
|
||||
|
||||
m_Light.Type[EQEmu::lightsource::LightInnate] = in_light;
|
||||
m_Light.Level[EQEmu::lightsource::LightInnate] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightInnate]);
|
||||
@ -230,10 +235,13 @@ Mob::Mob(const char* in_name,
|
||||
SpellPowerDistanceMod = 0;
|
||||
last_los_check = false;
|
||||
|
||||
if (in_aa_title > 0)
|
||||
if (in_aa_title > 0) {
|
||||
aa_title = in_aa_title;
|
||||
else
|
||||
}
|
||||
else {
|
||||
aa_title = 0xFF;
|
||||
}
|
||||
|
||||
AC = in_ac;
|
||||
ATK = in_atk;
|
||||
STR = in_str;
|
||||
@ -244,10 +252,8 @@ Mob::Mob(const char* in_name,
|
||||
WIS = in_wis;
|
||||
CHA = in_cha;
|
||||
MR = CR = FR = DR = PR = Corrup = 0;
|
||||
|
||||
ExtraHaste = 0;
|
||||
bEnraged = false;
|
||||
|
||||
shield_target = nullptr;
|
||||
current_mana = 0;
|
||||
max_mana = 0;
|
||||
@ -256,7 +262,7 @@ Mob::Mob(const char* in_name,
|
||||
ooc_regen = RuleI(NPC, OOCRegen); //default Out of Combat Regen
|
||||
maxlevel = in_maxlevel;
|
||||
scalerate = in_scalerate;
|
||||
invisible = false;
|
||||
invisible = 0;
|
||||
invisible_undead = false;
|
||||
invisible_animals = false;
|
||||
sneaking = false;
|
||||
@ -271,10 +277,7 @@ Mob::Mob(const char* in_name,
|
||||
InitializeBuffSlots();
|
||||
|
||||
// clear the proc arrays
|
||||
int i;
|
||||
int j;
|
||||
for (j = 0; j < MAX_PROCS; j++)
|
||||
{
|
||||
for (int j = 0; j < MAX_PROCS; j++) {
|
||||
PermaProcs[j].spellID = SPELL_UNKNOWN;
|
||||
PermaProcs[j].chance = 0;
|
||||
PermaProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
@ -293,8 +296,7 @@ Mob::Mob(const char* in_name,
|
||||
RangedProcs[j].level_override = -1;
|
||||
}
|
||||
|
||||
for (i = EQEmu::textures::textureBegin; i < EQEmu::textures::materialCount; i++)
|
||||
{
|
||||
for (int i = EQEmu::textures::textureBegin; i < EQEmu::textures::materialCount; i++) {
|
||||
armor_tint.Slot[i].Color = in_armor_tint.Slot[i].Color;
|
||||
}
|
||||
|
||||
@ -303,7 +305,6 @@ Mob::Mob(const char* in_name,
|
||||
m_Delta = glm::vec4();
|
||||
animation = 0;
|
||||
|
||||
logging_enabled = false;
|
||||
isgrouped = false;
|
||||
israidgrouped = false;
|
||||
|
||||
@ -325,8 +326,7 @@ Mob::Mob(const char* in_name,
|
||||
target = 0;
|
||||
|
||||
ActiveProjectileATK = false;
|
||||
for (int i = 0; i < MAX_SPELL_PROJECTILE; i++)
|
||||
{
|
||||
for (int i = 0; i < MAX_SPELL_PROJECTILE; i++) {
|
||||
ProjectileAtk[i].increment = 0;
|
||||
ProjectileAtk[i].hit_increment = 0;
|
||||
ProjectileAtk[i].target_id = 0;
|
||||
@ -370,8 +370,7 @@ Mob::Mob(const char* in_name,
|
||||
amnesiad = false;
|
||||
inWater = false;
|
||||
int m;
|
||||
for (m = 0; m < MAX_SHIELDERS; m++)
|
||||
{
|
||||
for (m = 0; m < MAX_SHIELDERS; m++) {
|
||||
shielder[m].shielder_id = 0;
|
||||
shielder[m].shielder_bonus = 0;
|
||||
}
|
||||
@ -399,9 +398,11 @@ Mob::Mob(const char* in_name,
|
||||
rooted = false;
|
||||
charmed = false;
|
||||
has_virus = false;
|
||||
for (i = 0; i < MAX_SPELL_TRIGGER * 2; i++) {
|
||||
|
||||
for (int i = 0; i < MAX_SPELL_TRIGGER * 2; i++) {
|
||||
viral_spells[i] = 0;
|
||||
}
|
||||
|
||||
pStandingPetOrder = SPO_Follow;
|
||||
pseudo_rooted = false;
|
||||
|
||||
@ -439,8 +440,14 @@ Mob::Mob(const char* in_name,
|
||||
|
||||
m_AllowBeneficial = false;
|
||||
m_DisableMelee = false;
|
||||
for (int i = 0; i < EQEmu::skills::HIGHEST_SKILL + 2; i++) { SkillDmgTaken_Mod[i] = 0; }
|
||||
for (int i = 0; i < HIGHEST_RESIST + 2; i++) { Vulnerability_Mod[i] = 0; }
|
||||
|
||||
for (int i = 0; i < EQEmu::skills::HIGHEST_SKILL + 2; i++) {
|
||||
SkillDmgTaken_Mod[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < HIGHEST_RESIST + 2; i++) {
|
||||
Vulnerability_Mod[i] = 0;
|
||||
}
|
||||
|
||||
emoteid = 0;
|
||||
endur_upkeep = false;
|
||||
@ -830,6 +837,7 @@ int32 Mob::CalcMaxMana() {
|
||||
int32 Mob::CalcMaxHP() {
|
||||
max_hp = (base_hp + itembonuses.HP + spellbonuses.HP);
|
||||
max_hp += max_hp * ((aabonuses.MaxHPChange + spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
|
||||
|
||||
return max_hp;
|
||||
}
|
||||
|
||||
@ -3466,25 +3474,32 @@ int Mob::GetHaste()
|
||||
return 100 + h;
|
||||
}
|
||||
|
||||
void Mob::SetTarget(Mob* mob) {
|
||||
|
||||
if (target == mob)
|
||||
void Mob::SetTarget(Mob *mob)
|
||||
{
|
||||
if (target == mob) {
|
||||
return;
|
||||
}
|
||||
|
||||
target = mob;
|
||||
entity_list.UpdateHoTT(this);
|
||||
|
||||
if(IsNPC())
|
||||
if (IsNPC()) {
|
||||
parse->EventNPC(EVENT_TARGET_CHANGE, CastToNPC(), mob, "", 0);
|
||||
else if (IsClient())
|
||||
}
|
||||
else if (IsClient()) {
|
||||
parse->EventPlayer(EVENT_TARGET_CHANGE, CastToClient(), "", 0);
|
||||
|
||||
if(IsPet() && GetOwner() && GetOwner()->IsClient())
|
||||
GetOwner()->CastToClient()->UpdateXTargetType(MyPetTarget, mob);
|
||||
this->DisplayInfo(mob);
|
||||
}
|
||||
|
||||
if (this->IsClient() && this->GetTarget() && this->CastToClient()->hp_other_update_throttle_timer.Check())
|
||||
if (IsPet() && GetOwner() && GetOwner()->IsClient()) {
|
||||
GetOwner()->CastToClient()->UpdateXTargetType(MyPetTarget, mob);
|
||||
}
|
||||
|
||||
if (this->IsClient() && this->GetTarget() && this->CastToClient()->hp_other_update_throttle_timer.Check()) {
|
||||
this->GetTarget()->SendHPUpdate(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
// For when we want a Ground Z at a location we are not at yet
|
||||
// Like MoveTo.
|
||||
@ -5553,7 +5568,8 @@ bool Mob::HasSpellEffect(int effectid)
|
||||
return(0);
|
||||
}
|
||||
|
||||
int Mob::GetSpecialAbility(int ability) {
|
||||
int Mob::GetSpecialAbility(int ability)
|
||||
{
|
||||
if (ability >= MAX_SPECIAL_ATTACK || ability < 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -5561,6 +5577,17 @@ int Mob::GetSpecialAbility(int ability) {
|
||||
return SpecialAbilities[ability].level;
|
||||
}
|
||||
|
||||
bool Mob::HasSpecialAbilities()
|
||||
{
|
||||
for (int i = 0; i < MAX_SPECIAL_ATTACK; ++i) {
|
||||
if (GetSpecialAbility(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Mob::GetSpecialAbilityParam(int ability, int param) {
|
||||
if(param >= MAX_SPECIAL_ATTACK_PARAMS || param < 0 || ability >= MAX_SPECIAL_ATTACK || ability < 0) {
|
||||
return 0;
|
||||
|
||||
@ -166,6 +166,10 @@ public:
|
||||
|
||||
bool is_distance_roamer;
|
||||
|
||||
void DisplayInfo(Mob *mob);
|
||||
|
||||
public:
|
||||
|
||||
//Somewhat sorted: needs documenting!
|
||||
|
||||
//Attack
|
||||
@ -1049,6 +1053,7 @@ public:
|
||||
inline bool Sanctuary() const { return spellbonuses.Sanctuary; }
|
||||
|
||||
bool HasNPCSpecialAtk(const char* parse);
|
||||
bool HasSpecialAbilities();
|
||||
int GetSpecialAbility(int ability);
|
||||
int GetSpecialAbilityParam(int ability, int param);
|
||||
void SetSpecialAbility(int ability, int level);
|
||||
@ -1146,6 +1151,8 @@ public:
|
||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);
|
||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
||||
|
||||
int32 GetHPRegen() const;
|
||||
|
||||
// Bots HealRotation methods
|
||||
#ifdef BOTS
|
||||
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
||||
@ -1476,7 +1483,6 @@ protected:
|
||||
|
||||
bool pAIControlled;
|
||||
bool roamer;
|
||||
bool logging_enabled;
|
||||
|
||||
int wandertype;
|
||||
int pausetype;
|
||||
|
||||
367
zone/mob_info.cpp
Normal file
367
zone/mob_info.cpp
Normal file
@ -0,0 +1,367 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "mob.h"
|
||||
#include "../common/races.h"
|
||||
#include "../common/say_link.h"
|
||||
|
||||
inline std::string GetMobAttributeByString(Mob *mob, const std::string &attribute)
|
||||
{
|
||||
if (attribute == "ac") {
|
||||
return std::to_string(mob->GetAC());
|
||||
}
|
||||
|
||||
if (attribute == "atk") {
|
||||
return std::to_string(mob->GetATK());
|
||||
}
|
||||
|
||||
if (attribute == "end") {
|
||||
int endurance = 0;
|
||||
if (mob->IsClient()) {
|
||||
endurance = mob->CastToClient()->GetEndurance();
|
||||
}
|
||||
|
||||
return std::to_string(endurance);
|
||||
}
|
||||
|
||||
if (attribute == "hp") {
|
||||
return std::to_string(mob->GetHP());
|
||||
}
|
||||
|
||||
if (attribute == "mana") {
|
||||
return std::to_string(mob->GetMana());
|
||||
}
|
||||
|
||||
if (attribute == "str") {
|
||||
return std::to_string(mob->GetSTR());
|
||||
}
|
||||
|
||||
if (attribute == "sta") {
|
||||
return std::to_string(mob->GetSTA());
|
||||
}
|
||||
|
||||
if (attribute == "dex") {
|
||||
return std::to_string(mob->GetDEX());
|
||||
}
|
||||
|
||||
if (attribute == "agi") {
|
||||
return std::to_string(mob->GetAGI());
|
||||
}
|
||||
|
||||
if (attribute == "int") {
|
||||
return std::to_string(mob->GetINT());
|
||||
}
|
||||
|
||||
if (attribute == "wis") {
|
||||
return std::to_string(mob->GetWIS());
|
||||
}
|
||||
|
||||
if (attribute == "cha") {
|
||||
return std::to_string(mob->GetCHA());
|
||||
}
|
||||
|
||||
if (attribute == "mr") {
|
||||
return std::to_string(mob->GetMR());
|
||||
}
|
||||
|
||||
if (attribute == "cr") {
|
||||
return std::to_string(mob->GetCR());
|
||||
}
|
||||
|
||||
if (attribute == "fr") {
|
||||
return std::to_string(mob->GetFR());
|
||||
}
|
||||
|
||||
if (attribute == "pr") {
|
||||
return std::to_string(mob->GetPR());
|
||||
}
|
||||
|
||||
if (attribute == "dr") {
|
||||
return std::to_string(mob->GetDR());
|
||||
}
|
||||
|
||||
if (attribute == "cr") {
|
||||
return std::to_string(mob->GetCR());
|
||||
}
|
||||
|
||||
if (attribute == "pr") {
|
||||
return std::to_string(mob->GetPR());
|
||||
}
|
||||
|
||||
if (attribute == "cor") {
|
||||
return std::to_string(mob->GetCorrup());
|
||||
}
|
||||
|
||||
if (attribute == "phy") {
|
||||
return std::to_string(mob->GetPhR());
|
||||
}
|
||||
|
||||
if (attribute == "name") {
|
||||
return mob->GetCleanName();
|
||||
}
|
||||
|
||||
if (attribute == "lastname") {
|
||||
return mob->GetLastName();
|
||||
}
|
||||
|
||||
if (attribute == "race") {
|
||||
return GetRaceIDName(mob->GetRace());
|
||||
}
|
||||
|
||||
if (attribute == "class") {
|
||||
return GetClassIDName(mob->GetClass(), 0);
|
||||
}
|
||||
|
||||
if (attribute == "level") {
|
||||
return std::to_string(mob->GetLevel());
|
||||
}
|
||||
|
||||
if (mob->IsNPC()) {
|
||||
NPC *npc = mob->CastToNPC();
|
||||
|
||||
if (attribute == "npcid") {
|
||||
return std::to_string(npc->GetNPCTypeID());
|
||||
}
|
||||
if (attribute == "texture") {
|
||||
return std::to_string(npc->GetTexture());
|
||||
}
|
||||
if (attribute == "bodytype") {
|
||||
return std::to_string(npc->GetBodyType());
|
||||
}
|
||||
if (attribute == "gender") {
|
||||
return std::to_string(npc->GetGender());
|
||||
}
|
||||
if (attribute == "size") {
|
||||
return std::to_string(npc->GetSize());
|
||||
}
|
||||
if (attribute == "runspeed") {
|
||||
return std::to_string(npc->GetRunspeed());
|
||||
}
|
||||
if (attribute == "walkspeed") {
|
||||
return std::to_string(npc->GetWalkspeed());
|
||||
}
|
||||
if (attribute == "spawngroup") {
|
||||
return std::to_string(npc->GetSp2());
|
||||
}
|
||||
if (attribute == "grid") {
|
||||
return std::to_string(npc->GetGrid());
|
||||
}
|
||||
if (attribute == "emote") {
|
||||
return std::to_string(npc->GetEmoteID());
|
||||
}
|
||||
npc->GetNPCEmote(npc->GetEmoteID(), 0);
|
||||
}
|
||||
|
||||
if (attribute == "type") {
|
||||
std::string entity_type = "Mob";
|
||||
|
||||
if (mob->IsCorpse()) {
|
||||
entity_type = "Corpse";
|
||||
}
|
||||
|
||||
if (mob->IsNPC()) {
|
||||
entity_type = "NPC";
|
||||
}
|
||||
|
||||
if (mob->IsClient()) {
|
||||
entity_type = "Client";
|
||||
}
|
||||
|
||||
return entity_type;
|
||||
}
|
||||
|
||||
return "null";
|
||||
}
|
||||
|
||||
inline std::string WriteDisplayInfoSection(
|
||||
Mob *mob,
|
||||
const std::string §ion_name,
|
||||
std::vector<std::string> attributes_list,
|
||||
int column_count = 3,
|
||||
bool display_section_name = false
|
||||
)
|
||||
{
|
||||
std::string text;
|
||||
|
||||
if (display_section_name) {
|
||||
text += "<c \"#FFFF66\">" + section_name + "</c><br>";
|
||||
}
|
||||
|
||||
text += "<table><tbody>";
|
||||
|
||||
int index = 0;
|
||||
bool first_row = true;
|
||||
|
||||
for (const auto &attribute : attributes_list) {
|
||||
if (index == 0) {
|
||||
if (first_row) {
|
||||
text += "<tr>\n";
|
||||
first_row = false;
|
||||
}
|
||||
else {
|
||||
text += "</tr><tr>\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string attribute_name = attribute;
|
||||
if (attribute_name.length() <= 3) {
|
||||
attribute_name = str_toupper(attribute_name);
|
||||
}
|
||||
if (attribute_name.length() > 3) {
|
||||
attribute_name = ucfirst(attribute_name);
|
||||
}
|
||||
|
||||
std::string attribute_value = GetMobAttributeByString(mob, attribute);
|
||||
|
||||
if (attribute_value.length() <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
text += "<td>" + attribute_name + "</td><td>" + GetMobAttributeByString(mob, attribute) + "</td>";
|
||||
|
||||
if (index == column_count) {
|
||||
index = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
text += "</tr></tbody></table>";
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
inline void NPCCommandsMenu(Client* client, NPC* npc)
|
||||
{
|
||||
std::string menu_commands;
|
||||
|
||||
if (npc->GetGrid() > 0) {
|
||||
menu_commands += EQEmu::SayLinkEngine::GenerateQuestSaylink("#grid show", false, "Grid Points") + " ";
|
||||
}
|
||||
|
||||
if (npc->GetEmoteID() > 0) {
|
||||
std::string saylink = StringFormat("#emotesearch %u", npc->GetEmoteID());
|
||||
menu_commands += EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Emotes") + " ";
|
||||
}
|
||||
|
||||
if (menu_commands.length() > 0) {
|
||||
client->Message(0, "# Show Commmands");
|
||||
client->Message(0, " - %s", menu_commands.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::DisplayInfo(Mob *mob)
|
||||
{
|
||||
if (!this || !mob) {
|
||||
return;
|
||||
}
|
||||
|
||||
// std::vector<std::string> general_stats = {
|
||||
//
|
||||
// // "accuracy",
|
||||
// // "slow_mitigation",
|
||||
// // "atk",
|
||||
// // "min_hit",
|
||||
// // "max_hit",
|
||||
// // "hp_regen",
|
||||
// // "attack_delay",
|
||||
// // "special_abilities"
|
||||
// };
|
||||
|
||||
if (this->IsClient()) {
|
||||
std::string window_text = "*Drag / Maximize Window to see all info<br><br>";
|
||||
|
||||
Client *client = this->CastToClient();
|
||||
|
||||
std::vector<std::string> who_attributes = {
|
||||
"name",
|
||||
"lastname",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Who", who_attributes, 1, false);
|
||||
|
||||
std::vector<std::string> type_attributes = {
|
||||
"race",
|
||||
"class",
|
||||
"type"
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Type", type_attributes, 3, true);
|
||||
|
||||
std::vector<std::string> basic_attributes = {
|
||||
"level",
|
||||
"hp",
|
||||
"mana",
|
||||
"end",
|
||||
"ac",
|
||||
"atk"
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Main", basic_attributes, 7, true);
|
||||
|
||||
std::vector<std::string> stat_attributes = {
|
||||
"str",
|
||||
"sta",
|
||||
"agi",
|
||||
"dex",
|
||||
"wis",
|
||||
"int",
|
||||
"cha",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Statistics", stat_attributes, 7, true);
|
||||
|
||||
std::vector<std::string> resist_attributes = {
|
||||
"pr",
|
||||
"mr",
|
||||
"dr",
|
||||
"fr",
|
||||
"cr",
|
||||
"cor",
|
||||
"phy",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Resists", resist_attributes, 7, true);
|
||||
|
||||
if (mob->IsNPC()) {
|
||||
std::vector<std::string> npc_attributes = {
|
||||
"npcid",
|
||||
"texture",
|
||||
"bodytype",
|
||||
"gender",
|
||||
"size",
|
||||
"runspeed",
|
||||
"walkspeed",
|
||||
"spawngroup",
|
||||
"grid",
|
||||
"emote",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "NPC Attributes", npc_attributes, 2, true);
|
||||
|
||||
client->Message(0, " ");
|
||||
mob->CastToNPC()->QueryLoot(client);
|
||||
|
||||
NPCCommandsMenu(client, mob->CastToNPC());
|
||||
}
|
||||
|
||||
std::cout << "Window Length: " << window_text.length() << std::endl;
|
||||
// std::cout << "Window " << window_text << std::endl;
|
||||
|
||||
client->SendPopupToClient("Entity Info", window_text.c_str());
|
||||
}
|
||||
}
|
||||
10
zone/net.cpp
10
zone/net.cpp
@ -42,7 +42,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
|
||||
#include "zone_config.h"
|
||||
#include "masterentity.h"
|
||||
#include "worldserver.h"
|
||||
@ -62,6 +61,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "embparser.h"
|
||||
#include "lua_parser.h"
|
||||
#include "questmgr.h"
|
||||
#include "npc_scale_manager.h"
|
||||
|
||||
#include "../common/event/event_loop.h"
|
||||
#include "../common/event/timer.h"
|
||||
@ -104,6 +104,7 @@ npcDecayTimes_Struct npcCorpseDecayTimes[100];
|
||||
TitleManager title_manager;
|
||||
QueryServ *QServ = 0;
|
||||
TaskManager *taskmanager = 0;
|
||||
NpcScaleManager *npc_scale_manager;
|
||||
QuestParserCollection *parse = 0;
|
||||
EQEmuLogSys LogSys;
|
||||
const SPDat_Spell_Struct* spells;
|
||||
@ -222,7 +223,6 @@ int main(int argc, char** argv) {
|
||||
worldserver.SetLauncherName("NONE");
|
||||
}
|
||||
|
||||
|
||||
Log(Logs::General, Logs::Zone_Server, "Connecting to MySQL...");
|
||||
if (!database.Connect(
|
||||
Config->DatabaseHost.c_str(),
|
||||
@ -255,6 +255,12 @@ int main(int argc, char** argv) {
|
||||
guild_mgr.SetDatabase(&database);
|
||||
GuildBanks = nullptr;
|
||||
|
||||
/**
|
||||
* NPC Scale Manager
|
||||
*/
|
||||
npc_scale_manager = new NpcScaleManager;
|
||||
npc_scale_manager->LoadScaleData();
|
||||
|
||||
#ifdef _EQDEBUG
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
#endif
|
||||
|
||||
749
zone/npc.cpp
749
zone/npc.cpp
@ -39,6 +39,7 @@
|
||||
#include "spawn2.h"
|
||||
#include "zone.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "npc_scale_manager.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <stdio.h>
|
||||
@ -57,59 +58,61 @@ extern Zone* zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern EntityList entity_list;
|
||||
|
||||
NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int iflymode, bool IsCorpse)
|
||||
: Mob(d->name,
|
||||
d->lastname,
|
||||
d->max_hp,
|
||||
d->max_hp,
|
||||
d->gender,
|
||||
d->race,
|
||||
d->class_,
|
||||
(bodyType)d->bodytype,
|
||||
d->deity,
|
||||
d->level,
|
||||
d->npc_id,
|
||||
d->size,
|
||||
d->runspeed,
|
||||
NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &position, int iflymode, bool IsCorpse)
|
||||
: Mob(
|
||||
npc_type_data->name,
|
||||
npc_type_data->lastname,
|
||||
npc_type_data->max_hp,
|
||||
npc_type_data->max_hp,
|
||||
npc_type_data->gender,
|
||||
npc_type_data->race,
|
||||
npc_type_data->class_,
|
||||
(bodyType) npc_type_data->bodytype,
|
||||
npc_type_data->deity,
|
||||
npc_type_data->level,
|
||||
npc_type_data->npc_id,
|
||||
npc_type_data->size,
|
||||
npc_type_data->runspeed,
|
||||
position,
|
||||
d->light, // innate_light
|
||||
d->texture,
|
||||
d->helmtexture,
|
||||
d->AC,
|
||||
d->ATK,
|
||||
d->STR,
|
||||
d->STA,
|
||||
d->DEX,
|
||||
d->AGI,
|
||||
d->INT,
|
||||
d->WIS,
|
||||
d->CHA,
|
||||
d->haircolor,
|
||||
d->beardcolor,
|
||||
d->eyecolor1,
|
||||
d->eyecolor2,
|
||||
d->hairstyle,
|
||||
d->luclinface,
|
||||
d->beard,
|
||||
d->drakkin_heritage,
|
||||
d->drakkin_tattoo,
|
||||
d->drakkin_details,
|
||||
d->armor_tint,
|
||||
npc_type_data->light, // innate_light
|
||||
npc_type_data->texture,
|
||||
npc_type_data->helmtexture,
|
||||
npc_type_data->AC,
|
||||
npc_type_data->ATK,
|
||||
npc_type_data->STR,
|
||||
npc_type_data->STA,
|
||||
npc_type_data->DEX,
|
||||
npc_type_data->AGI,
|
||||
npc_type_data->INT,
|
||||
npc_type_data->WIS,
|
||||
npc_type_data->CHA,
|
||||
npc_type_data->haircolor,
|
||||
npc_type_data->beardcolor,
|
||||
npc_type_data->eyecolor1,
|
||||
npc_type_data->eyecolor2,
|
||||
npc_type_data->hairstyle,
|
||||
npc_type_data->luclinface,
|
||||
npc_type_data->beard,
|
||||
npc_type_data->drakkin_heritage,
|
||||
npc_type_data->drakkin_tattoo,
|
||||
npc_type_data->drakkin_details,
|
||||
npc_type_data->armor_tint,
|
||||
0,
|
||||
d->see_invis, // pass see_invis/see_ivu flags to mob constructor
|
||||
d->see_invis_undead,
|
||||
d->see_hide,
|
||||
d->see_improved_hide,
|
||||
d->hp_regen,
|
||||
d->mana_regen,
|
||||
d->qglobal,
|
||||
d->maxlevel,
|
||||
d->scalerate,
|
||||
d->armtexture,
|
||||
d->bracertexture,
|
||||
d->handtexture,
|
||||
d->legtexture,
|
||||
d->feettexture),
|
||||
npc_type_data->see_invis, // pass see_invis/see_ivu flags to mob constructor
|
||||
npc_type_data->see_invis_undead,
|
||||
npc_type_data->see_hide,
|
||||
npc_type_data->see_improved_hide,
|
||||
npc_type_data->hp_regen,
|
||||
npc_type_data->mana_regen,
|
||||
npc_type_data->qglobal,
|
||||
npc_type_data->maxlevel,
|
||||
npc_type_data->scalerate,
|
||||
npc_type_data->armtexture,
|
||||
npc_type_data->bracertexture,
|
||||
npc_type_data->handtexture,
|
||||
npc_type_data->legtexture,
|
||||
npc_type_data->feettexture
|
||||
),
|
||||
attacked_timer(CombatEventTimer_expire),
|
||||
swarm_timer(100),
|
||||
classattack_timer(1000),
|
||||
@ -125,18 +128,21 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
{
|
||||
//What is the point of this, since the names get mangled..
|
||||
Mob *mob = entity_list.GetMob(name);
|
||||
if(mob != 0)
|
||||
if (mob != nullptr) {
|
||||
entity_list.RemoveEntity(mob->GetID());
|
||||
}
|
||||
|
||||
int moblevel = GetLevel();
|
||||
|
||||
NPCTypedata = d;
|
||||
NPCTypedata = npc_type_data;
|
||||
NPCTypedata_ours = nullptr;
|
||||
respawn2 = in_respawn;
|
||||
|
||||
swarm_timer.Disable();
|
||||
|
||||
if (size <= 0.0f)
|
||||
if (size <= 0.0f) {
|
||||
size = GetRaceGenderDefaultHeight(race, gender);
|
||||
}
|
||||
|
||||
taunting = false;
|
||||
proximity = nullptr;
|
||||
@ -144,41 +150,36 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
silver = 0;
|
||||
gold = 0;
|
||||
platinum = 0;
|
||||
max_dmg = d->max_dmg;
|
||||
min_dmg = d->min_dmg;
|
||||
attack_count = d->attack_count;
|
||||
max_dmg = npc_type_data->max_dmg;
|
||||
min_dmg = npc_type_data->min_dmg;
|
||||
attack_count = npc_type_data->attack_count;
|
||||
grid = 0;
|
||||
wp_m = 0;
|
||||
max_wp = 0;
|
||||
save_wp = 0;
|
||||
spawn_group = 0;
|
||||
swarmInfoPtr = nullptr;
|
||||
spellscale = d->spellscale;
|
||||
healscale = d->healscale;
|
||||
|
||||
logging_enabled = NPC_DEFAULT_LOGGING_ENABLED;
|
||||
|
||||
pAggroRange = d->aggroradius;
|
||||
pAssistRange = d->assistradius;
|
||||
findable = d->findable;
|
||||
trackable = d->trackable;
|
||||
|
||||
MR = d->MR;
|
||||
CR = d->CR;
|
||||
DR = d->DR;
|
||||
FR = d->FR;
|
||||
PR = d->PR;
|
||||
Corrup = d->Corrup;
|
||||
PhR = d->PhR;
|
||||
|
||||
STR = d->STR;
|
||||
STA = d->STA;
|
||||
AGI = d->AGI;
|
||||
DEX = d->DEX;
|
||||
INT = d->INT;
|
||||
WIS = d->WIS;
|
||||
CHA = d->CHA;
|
||||
npc_mana = d->Mana;
|
||||
spellscale = npc_type_data->spellscale;
|
||||
healscale = npc_type_data->healscale;
|
||||
pAggroRange = npc_type_data->aggroradius;
|
||||
pAssistRange = npc_type_data->assistradius;
|
||||
findable = npc_type_data->findable;
|
||||
trackable = npc_type_data->trackable;
|
||||
MR = npc_type_data->MR;
|
||||
CR = npc_type_data->CR;
|
||||
DR = npc_type_data->DR;
|
||||
FR = npc_type_data->FR;
|
||||
PR = npc_type_data->PR;
|
||||
Corrup = npc_type_data->Corrup;
|
||||
PhR = npc_type_data->PhR;
|
||||
STR = npc_type_data->STR;
|
||||
STA = npc_type_data->STA;
|
||||
AGI = npc_type_data->AGI;
|
||||
DEX = npc_type_data->DEX;
|
||||
INT = npc_type_data->INT;
|
||||
WIS = npc_type_data->WIS;
|
||||
CHA = npc_type_data->CHA;
|
||||
npc_mana = npc_type_data->Mana;
|
||||
|
||||
//quick fix of ordering if they screwed it up in the DB
|
||||
if (max_dmg < min_dmg) {
|
||||
@ -188,53 +189,40 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
}
|
||||
|
||||
// Max Level and Stat Scaling if maxlevel is set
|
||||
if(maxlevel > level)
|
||||
{
|
||||
if (maxlevel > level) {
|
||||
LevelScale();
|
||||
}
|
||||
|
||||
// Set Resists if they are 0 in the DB
|
||||
CalcNPCResists();
|
||||
|
||||
// Set Mana and HP Regen Rates if they are 0 in the DB
|
||||
CalcNPCRegen();
|
||||
|
||||
// Set Min and Max Damage if they are 0 in the DB
|
||||
if(max_dmg == 0){
|
||||
CalcNPCDamage();
|
||||
}
|
||||
|
||||
base_damage = round((max_dmg - min_dmg) / 1.9);
|
||||
min_damage = min_dmg - round(base_damage / 10.0);
|
||||
|
||||
accuracy_rating = d->accuracy_rating;
|
||||
avoidance_rating = d->avoidance_rating;
|
||||
ATK = d->ATK;
|
||||
accuracy_rating = npc_type_data->accuracy_rating;
|
||||
avoidance_rating = npc_type_data->avoidance_rating;
|
||||
ATK = npc_type_data->ATK;
|
||||
|
||||
// used for when switch back to charm
|
||||
default_ac = d->AC;
|
||||
default_ac = npc_type_data->AC;
|
||||
default_min_dmg = min_dmg;
|
||||
default_max_dmg = max_dmg;
|
||||
default_attack_delay = d->attack_delay;
|
||||
default_accuracy_rating = d->accuracy_rating;
|
||||
default_avoidance_rating = d->avoidance_rating;
|
||||
default_atk = d->ATK;
|
||||
default_attack_delay = npc_type_data->attack_delay;
|
||||
default_accuracy_rating = npc_type_data->accuracy_rating;
|
||||
default_avoidance_rating = npc_type_data->avoidance_rating;
|
||||
default_atk = npc_type_data->ATK;
|
||||
|
||||
// used for when getting charmed, if 0, doesn't swap
|
||||
charm_ac = d->charm_ac;
|
||||
charm_min_dmg = d->charm_min_dmg;
|
||||
charm_max_dmg = d->charm_max_dmg;
|
||||
charm_attack_delay = d->charm_attack_delay;
|
||||
charm_accuracy_rating = d->charm_accuracy_rating;
|
||||
charm_avoidance_rating = d->charm_avoidance_rating;
|
||||
charm_atk = d->charm_atk;
|
||||
charm_ac = npc_type_data->charm_ac;
|
||||
charm_min_dmg = npc_type_data->charm_min_dmg;
|
||||
charm_max_dmg = npc_type_data->charm_max_dmg;
|
||||
charm_attack_delay = npc_type_data->charm_attack_delay;
|
||||
charm_accuracy_rating = npc_type_data->charm_accuracy_rating;
|
||||
charm_avoidance_rating = npc_type_data->charm_avoidance_rating;
|
||||
charm_atk = npc_type_data->charm_atk;
|
||||
|
||||
CalcMaxMana();
|
||||
SetMana(GetMaxMana());
|
||||
|
||||
MerchantType = d->merchanttype;
|
||||
MerchantType = npc_type_data->merchanttype;
|
||||
merchant_open = GetClass() == MERCHANT;
|
||||
adventure_template_id = d->adventure_template;
|
||||
adventure_template_id = npc_type_data->adventure_template;
|
||||
flymode = iflymode;
|
||||
guard_anim = eaStanding;
|
||||
roambox_distance = 0;
|
||||
@ -247,22 +235,20 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
roambox_min_delay = 1000;
|
||||
roambox_delay = 1000;
|
||||
p_depop = false;
|
||||
loottable_id = d->loottable_id;
|
||||
skip_global_loot = d->skip_global_loot;
|
||||
rare_spawn = d->rare_spawn;
|
||||
|
||||
no_target_hotkey = d->no_target_hotkey;
|
||||
|
||||
loottable_id = npc_type_data->loottable_id;
|
||||
skip_global_loot = npc_type_data->skip_global_loot;
|
||||
rare_spawn = npc_type_data->rare_spawn;
|
||||
no_target_hotkey = npc_type_data->no_target_hotkey;
|
||||
primary_faction = 0;
|
||||
SetNPCFactionID(d->npc_faction_id);
|
||||
|
||||
SetNPCFactionID(npc_type_data->npc_faction_id);
|
||||
|
||||
npc_spells_id = 0;
|
||||
HasAISpell = false;
|
||||
HasAISpellEffects = false;
|
||||
innate_proc_spell_id = 0;
|
||||
|
||||
if(GetClass() == MERCERNARY_MASTER && RuleB(Mercs, AllowMercs))
|
||||
{
|
||||
if (GetClass() == MERCERNARY_MASTER && RuleB(Mercs, AllowMercs)) {
|
||||
LoadMercTypes();
|
||||
LoadMercs();
|
||||
}
|
||||
@ -274,33 +260,35 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
|
||||
delaytimer = false;
|
||||
combat_event = false;
|
||||
attack_speed = d->attack_speed;
|
||||
attack_delay = d->attack_delay;
|
||||
slow_mitigation = d->slow_mitigation;
|
||||
attack_speed = npc_type_data->attack_speed;
|
||||
attack_delay = npc_type_data->attack_delay;
|
||||
slow_mitigation = npc_type_data->slow_mitigation;
|
||||
|
||||
EntityList::RemoveNumbers(name);
|
||||
entity_list.MakeNameUnique(name);
|
||||
|
||||
npc_aggro = d->npc_aggro;
|
||||
npc_aggro = npc_type_data->npc_aggro;
|
||||
|
||||
AI_Init();
|
||||
AI_Start();
|
||||
|
||||
d_melee_texture1 = d->d_melee_texture1;
|
||||
d_melee_texture2 = d->d_melee_texture2;
|
||||
herosforgemodel = d->herosforgemodel;
|
||||
d_melee_texture1 = npc_type_data->d_melee_texture1;
|
||||
d_melee_texture2 = npc_type_data->d_melee_texture2;
|
||||
herosforgemodel = npc_type_data->herosforgemodel;
|
||||
|
||||
ammo_idfile = d->ammo_idfile;
|
||||
ammo_idfile = npc_type_data->ammo_idfile;
|
||||
memset(equipment, 0, sizeof(equipment));
|
||||
prim_melee_type = d->prim_melee_type;
|
||||
sec_melee_type = d->sec_melee_type;
|
||||
ranged_type = d->ranged_type;
|
||||
prim_melee_type = npc_type_data->prim_melee_type;
|
||||
sec_melee_type = npc_type_data->sec_melee_type;
|
||||
ranged_type = npc_type_data->ranged_type;
|
||||
|
||||
// If Melee Textures are not set, set attack type to Hand to Hand as default
|
||||
if(!d_melee_texture1)
|
||||
if (!d_melee_texture1) {
|
||||
prim_melee_type = 28;
|
||||
if(!d_melee_texture2)
|
||||
}
|
||||
if (!d_melee_texture2) {
|
||||
sec_melee_type = 28;
|
||||
}
|
||||
|
||||
//give NPCs skill values...
|
||||
int r;
|
||||
@ -313,105 +301,86 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
if (moblevel > 50) {
|
||||
skills[EQEmu::skills::SkillDoubleAttack] = 250;
|
||||
skills[EQEmu::skills::SkillDualWield] = 250;
|
||||
} else if (moblevel > 3) {
|
||||
}
|
||||
else if (moblevel > 3) {
|
||||
skills[EQEmu::skills::SkillDoubleAttack] = moblevel * 5;
|
||||
skills[EQEmu::skills::SkillDualWield] = skills[EQEmu::skills::SkillDoubleAttack];
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
skills[EQEmu::skills::SkillDoubleAttack] = moblevel * 5;
|
||||
}
|
||||
|
||||
if(d->trap_template > 0)
|
||||
{
|
||||
ldon_trapped = false;
|
||||
ldon_trap_type = 0;
|
||||
ldon_spell_id = 0;
|
||||
ldon_locked = false;
|
||||
ldon_locked_skill = 0;
|
||||
ldon_trap_detected = false;
|
||||
|
||||
if (npc_type_data->trap_template > 0) {
|
||||
std::map<uint32, std::list<LDoNTrapTemplate *> >::iterator trap_ent_iter;
|
||||
std::list<LDoNTrapTemplate *> trap_list;
|
||||
|
||||
trap_ent_iter = zone->ldon_trap_entry_list.find(d->trap_template);
|
||||
if(trap_ent_iter != zone->ldon_trap_entry_list.end())
|
||||
{
|
||||
trap_ent_iter = zone->ldon_trap_entry_list.find(npc_type_data->trap_template);
|
||||
if (trap_ent_iter != zone->ldon_trap_entry_list.end()) {
|
||||
trap_list = trap_ent_iter->second;
|
||||
if(trap_list.size() > 0)
|
||||
{
|
||||
if (trap_list.size() > 0) {
|
||||
auto trap_list_iter = trap_list.begin();
|
||||
std::advance(trap_list_iter, zone->random.Int(0, trap_list.size() - 1));
|
||||
LDoNTrapTemplate* tt = (*trap_list_iter);
|
||||
if(tt)
|
||||
{
|
||||
if((uint8)tt->spell_id > 0)
|
||||
{
|
||||
LDoNTrapTemplate *trap_template = (*trap_list_iter);
|
||||
if (trap_template) {
|
||||
if ((uint8) trap_template->spell_id > 0) {
|
||||
ldon_trapped = true;
|
||||
ldon_spell_id = tt->spell_id;
|
||||
ldon_spell_id = trap_template->spell_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ldon_trapped = false;
|
||||
ldon_spell_id = 0;
|
||||
}
|
||||
|
||||
ldon_trap_type = (uint8)tt->type;
|
||||
if(tt->locked > 0)
|
||||
{
|
||||
ldon_trap_type = (uint8) trap_template->type;
|
||||
if (trap_template->locked > 0) {
|
||||
ldon_locked = true;
|
||||
ldon_locked_skill = tt->skill;
|
||||
ldon_locked_skill = trap_template->skill;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ldon_locked = false;
|
||||
ldon_locked_skill = 0;
|
||||
}
|
||||
|
||||
ldon_trap_detected = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ldon_trapped = false;
|
||||
ldon_trap_type = 0;
|
||||
ldon_spell_id = 0;
|
||||
ldon_locked = false;
|
||||
ldon_locked_skill = 0;
|
||||
ldon_trap_detected = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ldon_trapped = false;
|
||||
ldon_trap_type = 0;
|
||||
ldon_spell_id = 0;
|
||||
ldon_locked = false;
|
||||
ldon_locked_skill = 0;
|
||||
ldon_trap_detected = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ldon_trapped = false;
|
||||
ldon_trap_type = 0;
|
||||
ldon_spell_id = 0;
|
||||
ldon_locked = false;
|
||||
ldon_locked_skill = 0;
|
||||
ldon_trap_detected = 0;
|
||||
}
|
||||
|
||||
reface_timer = new Timer(15000);
|
||||
reface_timer->Disable();
|
||||
|
||||
qGlobals = nullptr;
|
||||
SetEmoteID(d->emoteid);
|
||||
|
||||
SetEmoteID(static_cast<uint16>(npc_type_data->emoteid));
|
||||
InitializeBuffSlots();
|
||||
CalcBonuses();
|
||||
raid_target = d->raid_target;
|
||||
ignore_despawn = d->ignore_despawn;
|
||||
m_targetable = !d->untargetable;
|
||||
|
||||
AISpellVar.fail_recast = RuleI(Spells, AI_SpellCastFinishedFailRecast);
|
||||
AISpellVar.engaged_no_sp_recast_min = RuleI(Spells, AI_EngagedNoSpellMinRecast);
|
||||
AISpellVar.engaged_no_sp_recast_max = RuleI(Spells, AI_EngagedNoSpellMaxRecast);
|
||||
AISpellVar.engaged_beneficial_self_chance = RuleI(Spells, AI_EngagedBeneficialSelfChance);
|
||||
AISpellVar.engaged_beneficial_other_chance = RuleI(Spells, AI_EngagedBeneficialOtherChance);
|
||||
AISpellVar.engaged_detrimental_chance = RuleI(Spells, AI_EngagedDetrimentalChance);
|
||||
AISpellVar.pursue_no_sp_recast_min = RuleI(Spells, AI_PursueNoSpellMinRecast);
|
||||
AISpellVar.pursue_no_sp_recast_max = RuleI(Spells, AI_PursueNoSpellMaxRecast);
|
||||
AISpellVar.pursue_detrimental_chance = RuleI(Spells, AI_PursueDetrimentalChance);
|
||||
AISpellVar.idle_no_sp_recast_min = RuleI(Spells, AI_IdleNoSpellMinRecast);
|
||||
AISpellVar.idle_no_sp_recast_max = RuleI(Spells, AI_IdleNoSpellMaxRecast);
|
||||
AISpellVar.idle_beneficial_chance = RuleI(Spells, AI_IdleBeneficialChance);
|
||||
raid_target = npc_type_data->raid_target;
|
||||
ignore_despawn = npc_type_data->ignore_despawn;
|
||||
m_targetable = !npc_type_data->untargetable;
|
||||
|
||||
npc_scale_manager->ScaleMob(this);
|
||||
|
||||
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_max = static_cast<uint32>(RuleI(Spells, AI_EngagedNoSpellMaxRecast));
|
||||
AISpellVar.engaged_beneficial_self_chance = static_cast<uint8> (RuleI(Spells, AI_EngagedBeneficialSelfChance));
|
||||
AISpellVar.engaged_beneficial_other_chance = static_cast<uint8> (RuleI(Spells, AI_EngagedBeneficialOtherChance));
|
||||
AISpellVar.engaged_detrimental_chance = static_cast<uint8> (RuleI(Spells, AI_EngagedDetrimentalChance));
|
||||
AISpellVar.pursue_no_sp_recast_min = static_cast<uint32>(RuleI(Spells, AI_PursueNoSpellMinRecast));
|
||||
AISpellVar.pursue_no_sp_recast_max = static_cast<uint32>(RuleI(Spells, AI_PursueNoSpellMaxRecast));
|
||||
AISpellVar.pursue_detrimental_chance = static_cast<uint8> (RuleI(Spells, AI_PursueDetrimentalChance));
|
||||
AISpellVar.idle_no_sp_recast_min = static_cast<uint32>(RuleI(Spells, AI_IdleNoSpellMinRecast));
|
||||
AISpellVar.idle_no_sp_recast_max = static_cast<uint32>(RuleI(Spells, AI_IdleNoSpellMaxRecast));
|
||||
AISpellVar.idle_beneficial_chance = static_cast<uint8> (RuleI(Spells, AI_IdleBeneficialChance));
|
||||
}
|
||||
|
||||
NPC::~NPC()
|
||||
@ -582,10 +551,10 @@ void NPC::ClearItemList() {
|
||||
|
||||
void NPC::QueryLoot(Client* to)
|
||||
{
|
||||
to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper);
|
||||
to->Message(0, "# Loot %s", GetName());
|
||||
|
||||
int x = 0;
|
||||
for (auto cur = itemlist.begin(); cur != itemlist.end(); ++cur, ++x) {
|
||||
int item_count = 0;
|
||||
for (auto cur = itemlist.begin(); cur != itemlist.end(); ++cur, ++item_count) {
|
||||
if (!(*cur)) {
|
||||
Log(Logs::General, Logs::Error, "NPC::QueryLoot() - ItemList error, null item");
|
||||
continue;
|
||||
@ -599,10 +568,18 @@ void NPC::QueryLoot(Client* to)
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkLootItem);
|
||||
linker.SetLootData(*cur);
|
||||
|
||||
to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", linker.GenerateLink().c_str(), (*cur)->item_id, (*cur)->min_level, (*cur)->max_level);
|
||||
to->Message(
|
||||
0,
|
||||
"-- Item %i: %s ID: %u min_level: %u max_level: %u",
|
||||
item_count,
|
||||
linker.GenerateLink().c_str(),
|
||||
(*cur)->item_id,
|
||||
(*cur)->min_level,
|
||||
(*cur)->max_level
|
||||
);
|
||||
}
|
||||
|
||||
to->Message(0, "%i items on %s.", x, GetName());
|
||||
to->Message(0, "- %i Platinum %i Gold %i Silver %i Copper", platinum, gold, silver, copper);
|
||||
}
|
||||
|
||||
void NPC::AddCash(uint16 in_copper, uint16 in_silver, uint16 in_gold, uint16 in_platinum) {
|
||||
@ -627,7 +604,8 @@ void NPC::AddCash(uint16 in_copper, uint16 in_silver, uint16 in_gold, uint16 in_
|
||||
platinum = 0;
|
||||
}
|
||||
|
||||
void NPC::AddCash() {
|
||||
void NPC::AddCash()
|
||||
{
|
||||
copper = zone->random.Int(1, 100);
|
||||
silver = zone->random.Int(1, 50);
|
||||
gold = zone->random.Int(1, 10);
|
||||
@ -1004,7 +982,7 @@ NPC * NPC::SpawnGridNodeNPC(std::string name, const glm::vec4 &position, uint32
|
||||
npc_type->loottable_id = 0;
|
||||
npc_type->texture = 1;
|
||||
npc_type->light = 1;
|
||||
npc_type->size = 3;
|
||||
npc_type->size = 1;
|
||||
npc_type->runspeed = 0;
|
||||
npc_type->d_melee_texture1 = 1;
|
||||
npc_type->d_melee_texture2 = 1;
|
||||
@ -2138,30 +2116,94 @@ void NPC::SetLevel(uint8 in_level, bool command)
|
||||
SendAppearancePacket(AT_WhoLevel, in_level);
|
||||
}
|
||||
|
||||
void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
void NPC::ModifyNPCStat(const char *identifier, const char *new_value)
|
||||
{
|
||||
std::string id = identifier;
|
||||
std::string val = newValue;
|
||||
for(int i = 0; i < id.length(); ++i) {
|
||||
id[i] = std::tolower(id[i]);
|
||||
std::string id = str_tolower(identifier);
|
||||
std::string val = new_value;
|
||||
|
||||
std::string variable_key = StringFormat("modify_stat_%s", id.c_str());
|
||||
SetEntityVariable(variable_key.c_str(), new_value);
|
||||
|
||||
Log(Logs::Detail, Logs::NPCScaling, "NPC::ModifyNPCStat key: %s val: %s ", variable_key.c_str(), new_value);
|
||||
|
||||
if (id == "ac") {
|
||||
AC = atoi(val.c_str());
|
||||
CalcAC();
|
||||
return;
|
||||
}
|
||||
else if (id == "str") {
|
||||
STR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "sta") {
|
||||
STA = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "agi") {
|
||||
AGI = atoi(val.c_str());
|
||||
CalcAC();
|
||||
return;
|
||||
}
|
||||
else if (id == "dex") {
|
||||
DEX = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "wis") {
|
||||
WIS = atoi(val.c_str());
|
||||
CalcMaxMana();
|
||||
return;
|
||||
}
|
||||
else if (id == "int" || id == "_int") {
|
||||
INT = atoi(val.c_str());
|
||||
CalcMaxMana();
|
||||
return;
|
||||
}
|
||||
else if (id == "cha") {
|
||||
CHA = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "max_hp") {
|
||||
base_hp = atoi(val.c_str());
|
||||
|
||||
CalcMaxHP();
|
||||
if (cur_hp > max_hp) {
|
||||
cur_hp = max_hp;
|
||||
}
|
||||
|
||||
if(id == "ac") { AC = atoi(val.c_str()); CalcAC(); return; }
|
||||
else if(id == "str") { STR = atoi(val.c_str()); return; }
|
||||
else if(id == "sta") { STA = atoi(val.c_str()); return; }
|
||||
else if(id == "agi") { AGI = atoi(val.c_str()); CalcAC(); return; }
|
||||
else if(id == "dex") { DEX = atoi(val.c_str()); return; }
|
||||
else if(id == "wis") { WIS = atoi(val.c_str()); CalcMaxMana(); return; }
|
||||
else if(id == "int" || id == "_int") { INT = atoi(val.c_str()); CalcMaxMana(); return; }
|
||||
else if(id == "cha") { CHA = atoi(val.c_str()); return; }
|
||||
else if(id == "max_hp") { base_hp = atoi(val.c_str()); CalcMaxHP(); if (cur_hp > max_hp) { cur_hp = max_hp; } return; }
|
||||
else if(id == "max_mana") { npc_mana = atoi(val.c_str()); CalcMaxMana(); if (current_mana > max_mana){ current_mana = max_mana; } return; }
|
||||
else if(id == "mr") { MR = atoi(val.c_str()); return; }
|
||||
else if(id == "fr") { FR = atoi(val.c_str()); return; }
|
||||
else if(id == "cr") { CR = atoi(val.c_str()); return; }
|
||||
else if(id == "pr") { PR = atoi(val.c_str()); return; }
|
||||
else if(id == "dr") { DR = atoi(val.c_str()); return; }
|
||||
else if(id == "phr") { PhR = atoi(val.c_str()); return; }
|
||||
return;
|
||||
}
|
||||
else if (id == "max_mana") {
|
||||
npc_mana = atoi(val.c_str());
|
||||
CalcMaxMana();
|
||||
if (current_mana > max_mana) {
|
||||
current_mana = max_mana;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (id == "mr") {
|
||||
MR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "fr") {
|
||||
FR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "cr") {
|
||||
CR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "pr") {
|
||||
PR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "dr") {
|
||||
DR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "phr") {
|
||||
PhR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "runspeed") {
|
||||
runspeed = (float) atof(val.c_str());
|
||||
base_runspeed = (int) ((float) runspeed * 40.0f);
|
||||
@ -2169,16 +2211,44 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
walkspeed = ((float) base_walkspeed) * 0.025f;
|
||||
base_fearspeed = base_runspeed * 100 / 127;
|
||||
fearspeed = ((float) base_fearspeed) * 0.025f;
|
||||
CalcBonuses(); return;
|
||||
CalcBonuses();
|
||||
return;
|
||||
}
|
||||
else if (id == "special_attacks") {
|
||||
NPCSpecialAttacks(val.c_str(), 0, 1);
|
||||
return;
|
||||
}
|
||||
else if (id == "special_abilities") {
|
||||
ProcessSpecialAbilities(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "attack_speed") {
|
||||
attack_speed = (float) atof(val.c_str());
|
||||
CalcBonuses();
|
||||
return;
|
||||
}
|
||||
else if (id == "attack_delay") {
|
||||
/* TODO: fix DB */
|
||||
attack_delay = atoi(val.c_str()) * 100;
|
||||
CalcBonuses();
|
||||
return;
|
||||
}
|
||||
else if (id == "atk") {
|
||||
ATK = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "accuracy") {
|
||||
accuracy_rating = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "avoidance") {
|
||||
avoidance_rating = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "trackable") {
|
||||
trackable = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; }
|
||||
else if(id == "special_abilities") { ProcessSpecialAbilities(val.c_str()); return; }
|
||||
else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "attack_delay") { /* TODO: fix DB */attack_delay = atoi(val.c_str()) * 100; CalcBonuses(); return; }
|
||||
else if(id == "atk") { ATK = atoi(val.c_str()); return; }
|
||||
else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; }
|
||||
else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; }
|
||||
else if(id == "trackable") { trackable = atoi(val.c_str()); return; }
|
||||
else if (id == "min_hit") {
|
||||
min_dmg = atoi(val.c_str());
|
||||
// TODO: fix DB
|
||||
@ -2193,22 +2263,71 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
min_damage = min_dmg - round(base_damage / 10.0);
|
||||
return;
|
||||
}
|
||||
else if(id == "attack_count") { attack_count = atoi(val.c_str()); return; }
|
||||
else if(id == "see_invis") { see_invis = atoi(val.c_str()); return; }
|
||||
else if(id == "see_invis_undead") { see_invis_undead = atoi(val.c_str()); return; }
|
||||
else if(id == "see_hide") { see_hide = atoi(val.c_str()); return; }
|
||||
else if(id == "see_improved_hide") { see_improved_hide = atoi(val.c_str()); return; }
|
||||
else if(id == "hp_regen") { hp_regen = atoi(val.c_str()); return; }
|
||||
else if(id == "mana_regen") { mana_regen = atoi(val.c_str()); return; }
|
||||
else if(id == "level") { SetLevel(atoi(val.c_str())); return; }
|
||||
else if(id == "aggro") { pAggroRange = atof(val.c_str()); return; }
|
||||
else if(id == "assist") { pAssistRange = atof(val.c_str()); return; }
|
||||
else if(id == "slow_mitigation") { slow_mitigation = atoi(val.c_str()); return; }
|
||||
else if(id == "loottable_id") { loottable_id = atof(val.c_str()); return; }
|
||||
else if(id == "healscale") { healscale = atof(val.c_str()); return; }
|
||||
else if(id == "spellscale") { spellscale = atof(val.c_str()); return; }
|
||||
else if(id == "npc_spells_id") { AI_AddNPCSpells(atoi(val.c_str())); return; }
|
||||
else if(id == "npc_spells_effects_id") { AI_AddNPCSpellsEffects(atoi(val.c_str())); CalcBonuses(); return; }
|
||||
else if (id == "attack_count") {
|
||||
attack_count = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "see_invis") {
|
||||
see_invis = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "see_invis_undead") {
|
||||
see_invis_undead = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "see_hide") {
|
||||
see_hide = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "see_improved_hide") {
|
||||
see_improved_hide = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "hp_regen") {
|
||||
hp_regen = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "mana_regen") {
|
||||
mana_regen = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "level") {
|
||||
SetLevel(atoi(val.c_str()));
|
||||
return;
|
||||
}
|
||||
else if (id == "aggro") {
|
||||
pAggroRange = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "assist") {
|
||||
pAssistRange = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "slow_mitigation") {
|
||||
slow_mitigation = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "loottable_id") {
|
||||
loottable_id = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "healscale") {
|
||||
healscale = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "spellscale") {
|
||||
spellscale = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
else if (id == "npc_spells_id") {
|
||||
AI_AddNPCSpells(atoi(val.c_str()));
|
||||
return;
|
||||
}
|
||||
else if (id == "npc_spells_effects_id") {
|
||||
AI_AddNPCSpellsEffects(atoi(val.c_str()));
|
||||
CalcBonuses();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void NPC::LevelScale() {
|
||||
@ -2308,120 +2427,9 @@ void NPC::LevelScale() {
|
||||
return;
|
||||
}
|
||||
|
||||
void NPC::CalcNPCResists() {
|
||||
|
||||
if (!MR)
|
||||
MR = (GetLevel() * 11)/10;
|
||||
if (!CR)
|
||||
CR = (GetLevel() * 11)/10;
|
||||
if (!DR)
|
||||
DR = (GetLevel() * 11)/10;
|
||||
if (!FR)
|
||||
FR = (GetLevel() * 11)/10;
|
||||
if (!PR)
|
||||
PR = (GetLevel() * 11)/10;
|
||||
if (!Corrup)
|
||||
Corrup = 15;
|
||||
if (!PhR)
|
||||
PhR = 10;
|
||||
return;
|
||||
}
|
||||
|
||||
void NPC::CalcNPCRegen() {
|
||||
|
||||
// Fix for lazy db-updaters (regen values left at 0)
|
||||
if (GetCasterClass() != 'N' && mana_regen == 0)
|
||||
mana_regen = (GetLevel() / 10) + 4;
|
||||
else if(mana_regen < 0)
|
||||
mana_regen = 0;
|
||||
else
|
||||
mana_regen = mana_regen;
|
||||
|
||||
// Gives low end monsters no regen if set to 0 in database. Should make low end monsters killable
|
||||
// Might want to lower this to /5 rather than 10.
|
||||
if(hp_regen == 0)
|
||||
{
|
||||
if(GetLevel() <= 6)
|
||||
hp_regen = 1;
|
||||
else if(GetLevel() > 6 && GetLevel() <= 10)
|
||||
hp_regen = 2;
|
||||
else if(GetLevel() > 10 && GetLevel() <= 15)
|
||||
hp_regen = 3;
|
||||
else if(GetLevel() > 15 && GetLevel() <= 20)
|
||||
hp_regen = 5;
|
||||
else if(GetLevel() > 20 && GetLevel() <= 30)
|
||||
hp_regen = 7;
|
||||
else if(GetLevel() > 30 && GetLevel() <= 35)
|
||||
hp_regen = 9;
|
||||
else if(GetLevel() > 35 && GetLevel() <= 40)
|
||||
hp_regen = 12;
|
||||
else if(GetLevel() > 40 && GetLevel() <= 45)
|
||||
hp_regen = 18;
|
||||
else if(GetLevel() > 45 && GetLevel() <= 50)
|
||||
hp_regen = 21;
|
||||
else
|
||||
hp_regen = 30;
|
||||
} else if(hp_regen < 0) {
|
||||
hp_regen = 0;
|
||||
} else
|
||||
hp_regen = hp_regen;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void NPC::CalcNPCDamage() {
|
||||
|
||||
int AC_adjust=12;
|
||||
|
||||
if (GetLevel() >= 66) {
|
||||
if (min_dmg==0)
|
||||
min_dmg = 220;
|
||||
if (max_dmg==0)
|
||||
max_dmg = ((((99000)*(GetLevel()-64))/400)*AC_adjust/10);
|
||||
}
|
||||
else if (GetLevel() >= 60 && GetLevel() <= 65){
|
||||
if(min_dmg==0)
|
||||
min_dmg = (GetLevel()+(GetLevel()/3));
|
||||
if(max_dmg==0)
|
||||
max_dmg = (GetLevel()*3)*AC_adjust/10;
|
||||
}
|
||||
else if (GetLevel() >= 51 && GetLevel() <= 59){
|
||||
if(min_dmg==0)
|
||||
min_dmg = (GetLevel()+(GetLevel()/3));
|
||||
if(max_dmg==0)
|
||||
max_dmg = (GetLevel()*3)*AC_adjust/10;
|
||||
}
|
||||
else if (GetLevel() >= 40 && GetLevel() <= 50) {
|
||||
if (min_dmg==0)
|
||||
min_dmg = GetLevel();
|
||||
if(max_dmg==0)
|
||||
max_dmg = (GetLevel()*3)*AC_adjust/10;
|
||||
}
|
||||
else if (GetLevel() >= 28 && GetLevel() <= 39) {
|
||||
if (min_dmg==0)
|
||||
min_dmg = GetLevel() / 2;
|
||||
if (max_dmg==0)
|
||||
max_dmg = ((GetLevel()*2)+2)*AC_adjust/10;
|
||||
}
|
||||
else if (GetLevel() <= 27) {
|
||||
if (min_dmg==0)
|
||||
min_dmg=1;
|
||||
if (max_dmg==0)
|
||||
max_dmg = (GetLevel()*2)*AC_adjust/10;
|
||||
}
|
||||
|
||||
int32 clfact = GetClassLevelFactor();
|
||||
min_dmg = (min_dmg * clfact) / 220;
|
||||
max_dmg = (max_dmg * clfact) / 220;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint32 NPC::GetSpawnPointID() const
|
||||
{
|
||||
if(respawn2)
|
||||
{
|
||||
if (respawn2) {
|
||||
return respawn2->GetID();
|
||||
}
|
||||
return 0;
|
||||
@ -2438,7 +2446,6 @@ void NPC::NPCSlotTexture(uint8 slot, uint16 texture)
|
||||
else if (slot < 6) {
|
||||
// Reserved for texturing individual armor slots
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 NPC::GetSwarmOwner()
|
||||
@ -2468,7 +2475,8 @@ void NPC::SetSwarmTarget(int target_id)
|
||||
return;
|
||||
}
|
||||
|
||||
int32 NPC::CalcMaxMana() {
|
||||
int32 NPC::CalcMaxMana()
|
||||
{
|
||||
if (npc_mana == 0) {
|
||||
switch (GetCasterClass()) {
|
||||
case 'I':
|
||||
@ -2487,7 +2495,8 @@ int32 NPC::CalcMaxMana() {
|
||||
}
|
||||
|
||||
return max_mana;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
switch (GetCasterClass()) {
|
||||
case 'I':
|
||||
max_mana = npc_mana + spellbonuses.Mana + itembonuses.Mana;
|
||||
|
||||
28
zone/npc.h
28
zone/npc.h
@ -106,7 +106,7 @@ public:
|
||||
static bool SpawnZoneController();
|
||||
static int8 GetAILevel(bool iForceReRead = false);
|
||||
|
||||
NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false);
|
||||
NPC(const NPCType* npc_type_data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false);
|
||||
|
||||
virtual ~NPC();
|
||||
|
||||
@ -142,9 +142,6 @@ public:
|
||||
virtual void AI_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot);
|
||||
|
||||
void LevelScale();
|
||||
void CalcNPCResists();
|
||||
void CalcNPCRegen();
|
||||
void CalcNPCDamage();
|
||||
|
||||
virtual void SetTarget(Mob* mob);
|
||||
virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { if (skill_num <= EQEmu::skills::HIGHEST_SKILL) { return skills[skill_num]; } return 0; }
|
||||
@ -255,12 +252,23 @@ public:
|
||||
|
||||
void SignalNPC(int _signal_id);
|
||||
|
||||
inline int32 GetNPCFactionID() const { return npc_faction_id; }
|
||||
inline int32 GetPrimaryFaction() const { return primary_faction; }
|
||||
int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHateAmount(in_ent);}
|
||||
bool IsOnHatelist(Mob*p) { return hate_list.IsEntOnHateList(p);}
|
||||
inline int32 GetNPCFactionID() const
|
||||
{ return npc_faction_id; }
|
||||
|
||||
void SetNPCFactionID(int32 in) { npc_faction_id = in; database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction); }
|
||||
inline int32 GetPrimaryFaction() const
|
||||
{ return primary_faction; }
|
||||
|
||||
int32 GetNPCHate(Mob *in_ent)
|
||||
{ return hate_list.GetEntHateAmount(in_ent); }
|
||||
|
||||
bool IsOnHatelist(Mob *p)
|
||||
{ return hate_list.IsEntOnHateList(p); }
|
||||
|
||||
void SetNPCFactionID(int32 in)
|
||||
{
|
||||
npc_faction_id = in;
|
||||
database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction);
|
||||
}
|
||||
|
||||
glm::vec4 m_SpawnPoint;
|
||||
|
||||
@ -357,7 +365,7 @@ public:
|
||||
void SetAvoidanceRating(int32 d) { avoidance_rating = d;}
|
||||
int32 GetRawAC() const { return AC; }
|
||||
|
||||
void ModifyNPCStat(const char *identifier, const char *newValue);
|
||||
void ModifyNPCStat(const char *identifier, const char *new_value);
|
||||
virtual void SetLevel(uint8 in_level, bool command = false);
|
||||
|
||||
bool IsLDoNTrapped() const { return (ldon_trapped); }
|
||||
|
||||
439
zone/npc_scale_manager.cpp
Normal file
439
zone/npc_scale_manager.cpp
Normal file
@ -0,0 +1,439 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "npc_scale_manager.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
/**
|
||||
* @param mob
|
||||
*/
|
||||
void NpcScaleManager::ScaleMob(Mob *mob)
|
||||
{
|
||||
Log(Logs::General, Logs::NPCScaling, "Attempting scale on %s", mob->GetCleanName());
|
||||
|
||||
if (mob->IsClient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
NPC *npc = mob->CastToNPC();
|
||||
|
||||
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) {
|
||||
Log(Logs::General, Logs::NPCScaling, "NPC: %s - scaling data not found for type: %i level: %i",
|
||||
mob->GetCleanName(),
|
||||
mob_type,
|
||||
mob_level
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (npc->GetAC() == 0) {
|
||||
npc->ModifyNPCStat("ac", std::to_string(scale_data.ac).c_str());
|
||||
}
|
||||
if (npc->GetMaxHP() == 0) {
|
||||
npc->ModifyNPCStat("max_hp", std::to_string(scale_data.hp).c_str());
|
||||
npc->Heal();
|
||||
}
|
||||
if (npc->GetAccuracyRating() == 0) {
|
||||
npc->ModifyNPCStat("accuracy", std::to_string(scale_data.accuracy).c_str());
|
||||
}
|
||||
if (npc->GetSlowMitigation() == 0) {
|
||||
npc->ModifyNPCStat("slow_mitigation", std::to_string(scale_data.slow_mitigation).c_str());
|
||||
}
|
||||
if (npc->GetATK() == 0) {
|
||||
npc->ModifyNPCStat("atk", std::to_string(scale_data.attack).c_str());
|
||||
}
|
||||
if (npc->GetSTR() == 0) {
|
||||
npc->ModifyNPCStat("str", std::to_string(scale_data.strength).c_str());
|
||||
}
|
||||
if (npc->GetSTA() == 0) {
|
||||
npc->ModifyNPCStat("sta", std::to_string(scale_data.stamina).c_str());
|
||||
}
|
||||
if (npc->GetDEX() == 0) {
|
||||
npc->ModifyNPCStat("dex", std::to_string(scale_data.dexterity).c_str());
|
||||
}
|
||||
if (npc->GetAGI() == 0) {
|
||||
npc->ModifyNPCStat("agi", std::to_string(scale_data.agility).c_str());
|
||||
}
|
||||
if (npc->GetINT() == 0) {
|
||||
npc->ModifyNPCStat("int", std::to_string(scale_data.intelligence).c_str());
|
||||
}
|
||||
if (npc->GetWIS() == 0) {
|
||||
npc->ModifyNPCStat("wis", std::to_string(scale_data.wisdom).c_str());
|
||||
}
|
||||
if (npc->GetCHA() == 0) {
|
||||
npc->ModifyNPCStat("cha", std::to_string(scale_data.charisma).c_str());
|
||||
}
|
||||
if (npc->GetMR() == 0) {
|
||||
npc->ModifyNPCStat("mr", std::to_string(scale_data.magic_resist).c_str());
|
||||
}
|
||||
if (npc->GetCR() == 0) {
|
||||
npc->ModifyNPCStat("cr", std::to_string(scale_data.cold_resist).c_str());
|
||||
}
|
||||
if (npc->GetFR() == 0) {
|
||||
npc->ModifyNPCStat("fr", std::to_string(scale_data.fire_resist).c_str());
|
||||
}
|
||||
if (npc->GetPR() == 0) {
|
||||
npc->ModifyNPCStat("pr", std::to_string(scale_data.poison_resist).c_str());
|
||||
}
|
||||
if (npc->GetDR() == 0) {
|
||||
npc->ModifyNPCStat("dr", std::to_string(scale_data.disease_resist).c_str());
|
||||
}
|
||||
if (npc->GetCR() == 0) {
|
||||
npc->ModifyNPCStat("cr", std::to_string(scale_data.corruption_resist).c_str());
|
||||
}
|
||||
if (npc->GetPR() == 0) {
|
||||
npc->ModifyNPCStat("pr", std::to_string(scale_data.physical_resist).c_str());
|
||||
}
|
||||
if (npc->GetMinDMG() == 0) {
|
||||
int min_dmg = scale_data.min_dmg;
|
||||
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
|
||||
int32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
|
||||
min_dmg = (min_dmg * class_level_damage_mod) / 220;
|
||||
|
||||
Log(Logs::Moderate,
|
||||
Logs::NPCScaling,
|
||||
"ClassLevelDamageMod::min_dmg base: %i calc: %i",
|
||||
scale_data.min_dmg,
|
||||
min_dmg);
|
||||
}
|
||||
|
||||
npc->ModifyNPCStat("min_hit", std::to_string(min_dmg).c_str());
|
||||
}
|
||||
if (npc->GetMaxDMG() == 0) {
|
||||
int max_dmg = scale_data.max_dmg;
|
||||
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
|
||||
int32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
|
||||
max_dmg = (scale_data.max_dmg * class_level_damage_mod) / 220;
|
||||
|
||||
Log(Logs::Moderate,
|
||||
Logs::NPCScaling,
|
||||
"ClassLevelDamageMod::max_dmg base: %i calc: %i",
|
||||
scale_data.max_dmg,
|
||||
max_dmg
|
||||
);
|
||||
}
|
||||
|
||||
npc->ModifyNPCStat("max_hit", std::to_string(max_dmg).c_str());
|
||||
}
|
||||
if (npc->GetHPRegen() == 0) {
|
||||
npc->ModifyNPCStat("hp_regen", std::to_string(scale_data.hp_regen_rate).c_str());
|
||||
}
|
||||
if (npc->GetAttackDelay() == 0) {
|
||||
npc->ModifyNPCStat("attack_delay", std::to_string(scale_data.attack_delay).c_str());
|
||||
}
|
||||
if (!npc->HasSpecialAbilities()) {
|
||||
npc->ModifyNPCStat("special_abilities", scale_data.special_abilities.c_str());
|
||||
}
|
||||
|
||||
ListStats(npc);
|
||||
}
|
||||
|
||||
void NpcScaleManager::ListStats(Mob *mob)
|
||||
{
|
||||
std::string stats[] = {
|
||||
"ac",
|
||||
"max_hp",
|
||||
"accuracy",
|
||||
"slow_mitigation",
|
||||
"atk",
|
||||
"str",
|
||||
"sta",
|
||||
"dex",
|
||||
"agi",
|
||||
"int",
|
||||
"wis",
|
||||
"cha",
|
||||
"mr",
|
||||
"cr",
|
||||
"fr",
|
||||
"pr",
|
||||
"dr",
|
||||
"cr",
|
||||
"pr",
|
||||
"min_hit",
|
||||
"max_hit",
|
||||
"hp_regen",
|
||||
"attack_delay",
|
||||
"special_abilities"
|
||||
};
|
||||
|
||||
int stat_elements = sizeof(stats) / sizeof(stats[0]);
|
||||
|
||||
for (int i = 0; i < stat_elements; i++) {
|
||||
std::string variable = StringFormat("modify_stat_%s", stats[i].c_str());
|
||||
if (mob->EntityVariableExists(variable.c_str())) {
|
||||
Log(Logs::Detail,
|
||||
Logs::NPCScaling,
|
||||
"NpcScaleManager::ListStats: %s - %s ",
|
||||
stats[i].c_str(),
|
||||
mob->GetEntityVariable(variable.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NpcScaleManager::LoadScaleData()
|
||||
{
|
||||
auto results = database.QueryDatabase(
|
||||
"SELECT "
|
||||
"type,"
|
||||
"level,"
|
||||
"ac,"
|
||||
"hp,"
|
||||
"accuracy,"
|
||||
"slow_mitigation,"
|
||||
"attack,"
|
||||
"strength,"
|
||||
"stamina,"
|
||||
"dexterity,"
|
||||
"agility,"
|
||||
"intelligence,"
|
||||
"wisdom,"
|
||||
"charisma,"
|
||||
"magic_resist,"
|
||||
"cold_resist,"
|
||||
"fire_resist,"
|
||||
"poison_resist,"
|
||||
"disease_resist,"
|
||||
"corruption_resist,"
|
||||
"physical_resist,"
|
||||
"min_dmg,"
|
||||
"max_dmg,"
|
||||
"hp_regen_rate,"
|
||||
"attack_delay,"
|
||||
"special_abilities"
|
||||
" FROM `npc_scale_global_base`"
|
||||
);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
global_npc_scale scale_data;
|
||||
|
||||
scale_data.type = atoi(row[0]);
|
||||
scale_data.level = atoi(row[1]);
|
||||
scale_data.ac = atoi(row[2]);
|
||||
scale_data.hp = atoi(row[3]);
|
||||
scale_data.accuracy = atoi(row[4]);
|
||||
scale_data.slow_mitigation = atoi(row[5]);
|
||||
scale_data.attack = atoi(row[6]);
|
||||
scale_data.strength = atoi(row[7]);
|
||||
scale_data.stamina = atoi(row[8]);
|
||||
scale_data.dexterity = atoi(row[9]);
|
||||
scale_data.agility = atoi(row[10]);
|
||||
scale_data.intelligence = atoi(row[11]);
|
||||
scale_data.wisdom = atoi(row[12]);
|
||||
scale_data.charisma = atoi(row[13]);
|
||||
scale_data.magic_resist = atoi(row[14]);
|
||||
scale_data.cold_resist = atoi(row[15]);
|
||||
scale_data.fire_resist = atoi(row[16]);
|
||||
scale_data.poison_resist = atoi(row[17]);
|
||||
scale_data.disease_resist = atoi(row[18]);
|
||||
scale_data.corruption_resist = atoi(row[19]);
|
||||
scale_data.physical_resist = atoi(row[20]);
|
||||
scale_data.min_dmg = atoi(row[21]);
|
||||
scale_data.max_dmg = atoi(row[22]);
|
||||
scale_data.hp_regen_rate = atoi(row[23]);
|
||||
scale_data.attack_delay = atoi(row[24]);
|
||||
|
||||
if (row[25]) {
|
||||
scale_data.special_abilities = row[25];
|
||||
}
|
||||
|
||||
npc_global_base_scaling_data.insert(
|
||||
std::make_pair(
|
||||
std::make_pair(scale_data.type, scale_data.level),
|
||||
scale_data
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::NPCScaling, "Global Base Scaling Data Loaded...");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mob_type
|
||||
* @param mob_level
|
||||
* @return NpcScaleManager::global_npc_scale
|
||||
*/
|
||||
NpcScaleManager::global_npc_scale NpcScaleManager::GetGlobalScaleDataForTypeLevel(int8 mob_type, int mob_level)
|
||||
{
|
||||
auto iter = npc_global_base_scaling_data.find(std::make_pair(mob_type, mob_level));
|
||||
if (iter != npc_global_base_scaling_data.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param level
|
||||
* @param npc_class
|
||||
* @return
|
||||
*/
|
||||
uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
|
||||
{
|
||||
uint32 multiplier = 0;
|
||||
|
||||
switch (npc_class) {
|
||||
case WARRIOR: {
|
||||
if (level < 20) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (level < 30) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (level < 40) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (level < 53) {
|
||||
multiplier = 270;
|
||||
}
|
||||
else if (level < 57) {
|
||||
multiplier = 280;
|
||||
}
|
||||
else if (level < 60) {
|
||||
multiplier = 290;
|
||||
}
|
||||
else if (level < 70) {
|
||||
multiplier = 300;
|
||||
}
|
||||
else {
|
||||
multiplier = 311;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DRUID:
|
||||
case CLERIC:
|
||||
case SHAMAN: {
|
||||
if (level < 70) {
|
||||
multiplier = 150;
|
||||
}
|
||||
else {
|
||||
multiplier = 157;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BERSERKER:
|
||||
case PALADIN:
|
||||
case SHADOWKNIGHT: {
|
||||
if (level < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (level < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (level < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (level < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (level < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (level < 68) {
|
||||
multiplier = 260;
|
||||
}
|
||||
else {
|
||||
multiplier = 270;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MONK:
|
||||
case BARD:
|
||||
case ROGUE:
|
||||
case BEASTLORD: {
|
||||
if (level < 51) {
|
||||
multiplier = 180;
|
||||
}
|
||||
else if (level < 58) {
|
||||
multiplier = 190;
|
||||
}
|
||||
else if (level < 70) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else {
|
||||
multiplier = 210;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RANGER: {
|
||||
if (level < 58) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else if (level < 70) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else {
|
||||
multiplier = 220;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAGICIAN:
|
||||
case WIZARD:
|
||||
case NECROMANCER:
|
||||
case ENCHANTER: {
|
||||
if (level < 70) {
|
||||
multiplier = 120;
|
||||
}
|
||||
else {
|
||||
multiplier = 127;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (level < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (level < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (level < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (level < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (level < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else {
|
||||
multiplier = 260;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
73
zone/npc_scale_manager.h
Normal file
73
zone/npc_scale_manager.h
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_NPC_SCALE_MANAGER_H
|
||||
#define EQEMU_NPC_SCALE_MANAGER_H
|
||||
|
||||
|
||||
#include "npc.h"
|
||||
|
||||
class NpcScaleManager {
|
||||
public:
|
||||
struct global_npc_scale {
|
||||
int type;
|
||||
int level;
|
||||
int ac;
|
||||
int hp;
|
||||
int accuracy;
|
||||
int slow_mitigation;
|
||||
int attack;
|
||||
int strength;
|
||||
int stamina;
|
||||
int dexterity;
|
||||
int agility;
|
||||
int intelligence;
|
||||
int wisdom;
|
||||
int charisma;
|
||||
int magic_resist;
|
||||
int cold_resist;
|
||||
int fire_resist;
|
||||
int poison_resist;
|
||||
int disease_resist;
|
||||
int corruption_resist;
|
||||
int physical_resist;
|
||||
int min_dmg;
|
||||
int max_dmg;
|
||||
int hp_regen_rate;
|
||||
int attack_delay;
|
||||
|
||||
std::string special_abilities;
|
||||
};
|
||||
|
||||
void ScaleMob(Mob *mob);
|
||||
bool LoadScaleData();
|
||||
|
||||
global_npc_scale GetGlobalScaleDataForTypeLevel(int8 mob_type, int mob_level);
|
||||
|
||||
std::map<std::pair<int, int>, global_npc_scale> npc_global_base_scaling_data;
|
||||
|
||||
void ListStats(Mob * mob);
|
||||
|
||||
uint32 GetClassLevelDamageMod(uint32 level, uint32 npc_class);
|
||||
};
|
||||
|
||||
extern NpcScaleManager *npc_scale_manager;
|
||||
|
||||
#endif //EQEMU_NPC_SCALE_MANAGER_H
|
||||
@ -2761,47 +2761,11 @@ void QuestManager::FlagInstanceByRaidLeader(uint32 zone, int16 version)
|
||||
}
|
||||
}
|
||||
|
||||
const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkName) {
|
||||
std::string QuestManager::saylink(char *saylink_text, bool silent, const char *link_name)
|
||||
{
|
||||
QuestManagerCurrentQuestVars();
|
||||
|
||||
int sayid = 0;
|
||||
|
||||
int sz = strlen(Phrase);
|
||||
auto escaped_string = new char[sz * 2];
|
||||
database.DoEscapeString(escaped_string, Phrase, sz);
|
||||
|
||||
// Query for an existing phrase and id in the saylink table
|
||||
std::string query = StringFormat("SELECT `id` FROM `saylink` WHERE `phrase` = '%s'", escaped_string);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success()) {
|
||||
if (results.RowCount() >= 1) {
|
||||
for (auto row = results.begin();row != results.end(); ++row)
|
||||
sayid = atoi(row[0]);
|
||||
} else {
|
||||
std::string insert_query = StringFormat("INSERT INTO `saylink` (`phrase`) VALUES ('%s')", escaped_string);
|
||||
results = database.QueryDatabase(insert_query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "Error in saylink phrase queries", results.ErrorMessage().c_str());
|
||||
}
|
||||
else {
|
||||
sayid = results.LastInsertedID();
|
||||
}
|
||||
}
|
||||
}
|
||||
safe_delete_array(escaped_string);
|
||||
|
||||
//Create the say link as an item link hash
|
||||
EQEmu::SayLinkEngine linker;
|
||||
linker.SetProxyItemID(SAYLINK_ITEM_ID);
|
||||
if (silent)
|
||||
linker.SetProxyAugment2ID(sayid);
|
||||
else
|
||||
linker.SetProxyAugment1ID(sayid);
|
||||
linker.SetProxyText(LinkName);
|
||||
|
||||
strcpy(Phrase, linker.GenerateLink().c_str());
|
||||
|
||||
return Phrase;
|
||||
return EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink_text, silent, link_name);
|
||||
}
|
||||
|
||||
const char* QuestManager::getguildnamebyid(int guild_id) {
|
||||
|
||||
@ -245,7 +245,7 @@ public:
|
||||
void FlagInstanceByGroupLeader(uint32 zone, int16 version);
|
||||
void FlagInstanceByRaidLeader(uint32 zone, int16 version);
|
||||
const char* varlink(char* perltext, int item_id);
|
||||
const char* saylink(char* Phrase, bool silent, const char* LinkName);
|
||||
std::string saylink(char *saylink_text, bool silent, const char *link_name);
|
||||
const char* getguildnamebyid(int guild_id);
|
||||
void SetRunning(bool val);
|
||||
bool IsRunning();
|
||||
|
||||
@ -5644,8 +5644,7 @@ void NPC::InitializeBuffSlots()
|
||||
{
|
||||
int max_slots = GetMaxTotalSlots();
|
||||
buffs = new Buffs_Struct[max_slots];
|
||||
for(int x = 0; x < max_slots; ++x)
|
||||
{
|
||||
for (int x = 0; x < max_slots; ++x) {
|
||||
buffs[x].spellid = SPELL_UNKNOWN;
|
||||
buffs[x].UpdateClient = false;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user