Merge branch 'master' into master

This commit is contained in:
Paul Coene
2018-12-18 11:33:52 -05:00
committed by GitHub
49 changed files with 4241 additions and 1991 deletions
+5 -4
View File
@@ -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)
+11
View File
@@ -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,13 @@ 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;
}
int32 Mob::GetManaRegen() const
{
return mana_regen;
}
+3 -3
View File
@@ -62,12 +62,12 @@ void Mob::CalcBonuses()
void NPC::CalcBonuses()
{
memset(&itembonuses, 0, sizeof(StatBonuses));
if(RuleB(NPC, UseItemBonusesForNonPets)){
if (RuleB(NPC, UseItemBonusesForNonPets)) {
memset(&itembonuses, 0, sizeof(StatBonuses));
CalcItemBonuses(&itembonuses);
}
else{
if(GetOwner()){
else {
if (GetOwner()) {
memset(&itembonuses, 0, sizeof(StatBonuses));
CalcItemBonuses(&itembonuses);
}
+106 -57
View File
@@ -38,6 +38,7 @@ extern volatile bool RunLoops;
#include "../common/rulesys.h"
#include "../common/string_util.h"
#include "../common/data_verification.h"
#include "data_bucket.h"
#include "position.h"
#include "net.h"
#include "worldserver.h"
@@ -254,7 +255,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));
@@ -263,6 +263,16 @@ Client::Client(EQStreamInterface* ieqs)
PendingSacrifice = false;
controlling_boat_id = 0;
if (!RuleB(Character, PerCharacterQglobalMaxLevel) && !RuleB(Character, PerCharacterBucketMaxLevel)) {
SetClientMaxLevel(0);
} else if (RuleB(Character, PerCharacterQglobalMaxLevel)) {
int client_max_level = GetCharMaxLevelFromQGlobal();
SetClientMaxLevel(client_max_level);
} else if (RuleB(Character, PerCharacterBucketMaxLevel)) {
int client_max_level = GetCharMaxLevelFromBucket();
SetClientMaxLevel(client_max_level);
}
KarmaUpdateTimer = new Timer(RuleI(Chat, KarmaUpdateIntervalMS));
GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS));
AttemptedMessages = 0;
@@ -335,6 +345,12 @@ Client::Client(EQStreamInterface* ieqs)
temp_pvp = false;
is_client_moving = false;
/**
* GM
*/
display_mob_info_window = true;
dev_tools_window_enabled = true;
#ifdef BOTS
bot_owner_options = DefaultBotOwnerOptions;
#endif
@@ -1648,7 +1664,6 @@ void Client::FriendsWho(char *FriendsString) {
}
}
void Client::UpdateAdmin(bool iFromDB) {
int16 tmp = admin;
if (iFromDB)
@@ -1966,7 +1981,6 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
ns->spawn.show_name = true;
strcpy(ns->spawn.title, m_pp.title);
strcpy(ns->spawn.suffix, m_pp.suffix);
@@ -4032,9 +4046,9 @@ void Client::SetHoTT(uint32 mobid) {
void Client::SendPopupToClient(const char *Title, const char *Text, uint32 PopupID, uint32 Buttons, uint32 Duration)
{
auto outapp = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct));
OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *)outapp->pBuffer;
OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *) outapp->pBuffer;
if ((strlen(Title) > (sizeof(olms->Title) - 1)) || (strlen(Text) > (sizeof(olms->Text) - 1))) {
safe_delete(outapp);
@@ -4046,12 +4060,14 @@ void Client::SendPopupToClient(const char *Title, const char *Text, uint32 Popup
olms->Buttons = Buttons;
if (Duration > 0)
if (Duration > 0) {
olms->Duration = Duration * 1000;
else
}
else {
olms->Duration = 0xffffffff;
}
olms->PopupID = PopupID;
olms->PopupID = PopupID;
olms->NegativeID = 0;
sprintf(olms->ButtonName0, "%s", "Yes");
@@ -4060,16 +4076,29 @@ void Client::SendPopupToClient(const char *Title, const char *Text, uint32 Popup
safe_delete(outapp);
}
void Client::SendFullPopup(const char *Title, const char *Text, uint32 PopupID, uint32 NegativeID, uint32 Buttons, uint32 Duration, const char *ButtonName0, const char *ButtonName1, uint32 SoundControls) {
void Client::SendFullPopup(
const char *Title,
const char *Text,
uint32 PopupID,
uint32 NegativeID,
uint32 Buttons,
uint32 Duration,
const char *ButtonName0,
const char *ButtonName1,
uint32 SoundControls
)
{
auto outapp = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct));
OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *)outapp->pBuffer;
if((strlen(Text) > (sizeof(olms->Text)-1)) || (strlen(Title) > (sizeof(olms->Title) - 1)) ) {
OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *) outapp->pBuffer;
if ((strlen(Text) > (sizeof(olms->Text) - 1)) || (strlen(Title) > (sizeof(olms->Title) - 1))) {
safe_delete(outapp);
return;
}
if (ButtonName0 && ButtonName1 && ( (strlen(ButtonName0) > (sizeof(olms->ButtonName0) - 1)) || (strlen(ButtonName1) > (sizeof(olms->ButtonName1) - 1)) ) ) {
if (ButtonName0 && ButtonName1 && ((strlen(ButtonName0) > (sizeof(olms->ButtonName0) - 1)) ||
(strlen(ButtonName1) > (sizeof(olms->ButtonName1) - 1)))) {
safe_delete(outapp);
return;
}
@@ -4078,31 +4107,47 @@ void Client::SendFullPopup(const char *Title, const char *Text, uint32 PopupID,
strcpy(olms->Text, Text);
olms->Buttons = Buttons;
if (ButtonName0 == NULL || ButtonName1 == NULL) {
if (ButtonName0 == nullptr || ButtonName1 == nullptr) {
sprintf(olms->ButtonName0, "%s", "Yes");
sprintf(olms->ButtonName1, "%s", "No");
} else {
}
else {
strcpy(olms->ButtonName0, ButtonName0);
strcpy(olms->ButtonName1, ButtonName1);
}
if(Duration > 0)
if (Duration > 0) {
olms->Duration = Duration * 1000;
else
}
else {
olms->Duration = 0xffffffff;
}
olms->PopupID = PopupID;
olms->NegativeID = NegativeID;
olms->PopupID = PopupID;
olms->NegativeID = NegativeID;
olms->SoundControls = SoundControls;
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const char *ButtonName0, const char *ButtonName1, uint32 Duration, int title_type, Client* target, const char *Title, const char *Text, ...) {
void Client::SendWindow(
uint32 PopupID,
uint32 NegativeID,
uint32 Buttons,
const char *ButtonName0,
const char *ButtonName1,
uint32 Duration,
int title_type,
Client *target,
const char *Title,
const char *Text,
...
)
{
va_list argptr;
char buffer[4096];
char buffer[4096];
va_start(argptr, Text);
vsnprintf(buffer, sizeof(buffer), Text, argptr);
@@ -4110,23 +4155,23 @@ void Client::SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const
size_t len = strlen(buffer);
auto app = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct));
OnLevelMessage_Struct* olms=(OnLevelMessage_Struct*)app->pBuffer;
auto app = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct));
OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *) app->pBuffer;
if(strlen(Text) > (sizeof(olms->Text)-1)) {
if (strlen(Text) > (sizeof(olms->Text) - 1)) {
safe_delete(app);
return;
}
if(!target)
if (!target) {
title_type = 0;
}
switch (title_type)
{
switch (title_type) {
case 1: {
char name[64] = "";
strcpy(name, target->GetName());
if(target->GetLastName()) {
if (target->GetLastName()) {
char last_name[64] = "";
strcpy(last_name, target->GetLastName());
strcat(name, " ");
@@ -4136,8 +4181,8 @@ void Client::SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const
break;
}
case 2: {
if(target->GuildID()) {
char *guild_name = (char*)guild_mgr.GetGuildName(target->GuildID());
if (target->GuildID()) {
char *guild_name = (char *) guild_mgr.GetGuildName(target->GuildID());
strcpy(olms->Title, guild_name);
}
else {
@@ -4151,19 +4196,21 @@ void Client::SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const
}
}
memcpy(olms->Text, buffer, len+1);
memcpy(olms->Text, buffer, len + 1);
olms->Buttons = Buttons;
sprintf(olms->ButtonName0, "%s", ButtonName0);
sprintf(olms->ButtonName1, "%s", ButtonName1);
if(Duration > 0)
if (Duration > 0) {
olms->Duration = Duration * 1000;
else
}
else {
olms->Duration = 0xffffffff;
}
olms->PopupID = PopupID;
olms->PopupID = PopupID;
olms->NegativeID = NegativeID;
FastQueuePacket(&app);
@@ -6670,30 +6717,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 +7152,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>" <<
@@ -9306,3 +9336,22 @@ void Client::InitInnates()
}
}
bool Client::GetDisplayMobInfoWindow() const
{
return display_mob_info_window;
}
void Client::SetDisplayMobInfoWindow(bool display_mob_info_window)
{
Client::display_mob_info_window = display_mob_info_window;
}
bool Client::IsDevToolsWindowEnabled() const
{
return dev_tools_window_enabled;
}
void Client::SetDevToolsWindowEnabled(bool in_dev_tools_window_enabled)
{
Client::dev_tools_window_enabled = in_dev_tools_window_enabled;
}
+17 -3
View File
@@ -246,6 +246,12 @@ public:
std::unordered_map<Mob *, float> close_mobs;
bool is_client_moving;
void SetDisplayMobInfoWindow(bool display_mob_info_window);
bool GetDisplayMobInfoWindow() const;
bool IsDevToolsWindowEnabled() const;
void SetDevToolsWindowEnabled(bool dev_tools_window_enabled);
//abstract virtual function implementations required by base abstract class
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
@@ -697,7 +703,9 @@ public:
void SendGuildJoin(GuildJoin_Struct* gj);
void RefreshGuildInfo();
int GetClientMaxLevel() const { return client_max_level; }
void SetClientMaxLevel(int max_level) { client_max_level = max_level; }
void CheckManaEndUpdate();
void SendManaUpdate();
void SendEnduranceUpdate();
@@ -773,8 +781,10 @@ public:
void UnscribeSpellAll(bool update_client = true);
void UntrainDisc(int slot, bool update_client = true);
void UntrainDiscAll(bool update_client = true);
bool SpellGlobalCheck(uint16 Spell_ID, uint32 Char_ID);
bool SpellGlobalCheck(uint16 spell_id, uint32 char_id);
bool SpellBucketCheck(uint16 spell_id, uint32 char_id);
uint32 GetCharMaxLevelFromQGlobal();
uint32 GetCharMaxLevelFromBucket();
inline bool IsSitting() const {return (playeraction == 1);}
inline bool IsBecomeNPC() const { return npcflag; }
@@ -851,7 +861,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();
@@ -1459,6 +1468,9 @@ private:
int Haste; //precalced value
uint32 tmSitting; // time stamp started sitting, used for HP regen bonus added on MAY 5, 2004
bool display_mob_info_window;
bool dev_tools_window_enabled;
int32 max_end;
int32 current_endurance;
@@ -1642,6 +1654,8 @@ private:
void InterrogateInventory_(bool errorcheck, Client* requester, int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, bool log, bool silent, bool &error, int depth);
bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth);
int client_max_level;
#ifdef BOTS
struct BotOwnerOptions {
bool death_marquee;
+108 -636
View File
@@ -275,8 +275,9 @@ 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;
}
}
@@ -340,136 +342,137 @@ int32 Client::CalcMaxHP()
uint32 Mob::GetClassLevelFactor()
{
uint32 multiplier = 0;
uint8 mlevel = GetLevel();
uint8 mlevel = GetLevel();
switch (GetClass()) {
case WARRIOR: {
if (mlevel < 20) {
multiplier = 220;
}
else if (mlevel < 30) {
multiplier = 230;
}
else if (mlevel < 40) {
multiplier = 250;
}
else if (mlevel < 53) {
multiplier = 270;
}
else if (mlevel < 57) {
multiplier = 280;
}
else if (mlevel < 60) {
multiplier = 290;
}
else if (mlevel < 70) {
multiplier = 300;
}
else {
multiplier = 311;
}
break;
if (mlevel < 20) {
multiplier = 220;
}
else if (mlevel < 30) {
multiplier = 230;
}
else if (mlevel < 40) {
multiplier = 250;
}
else if (mlevel < 53) {
multiplier = 270;
}
else if (mlevel < 57) {
multiplier = 280;
}
else if (mlevel < 60) {
multiplier = 290;
}
else if (mlevel < 70) {
multiplier = 300;
}
else {
multiplier = 311;
}
break;
}
case DRUID:
case CLERIC:
case SHAMAN: {
if (mlevel < 70) {
multiplier = 150;
}
else {
multiplier = 157;
}
break;
if (mlevel < 70) {
multiplier = 150;
}
else {
multiplier = 157;
}
break;
}
case BERSERKER:
case PALADIN:
case SHADOWKNIGHT: {
if (mlevel < 35) {
multiplier = 210;
}
else if (mlevel < 45) {
multiplier = 220;
}
else if (mlevel < 51) {
multiplier = 230;
}
else if (mlevel < 56) {
multiplier = 240;
}
else if (mlevel < 60) {
multiplier = 250;
}
else if (mlevel < 68) {
multiplier = 260;
}
else {
multiplier = 270;
}
break;
if (mlevel < 35) {
multiplier = 210;
}
else if (mlevel < 45) {
multiplier = 220;
}
else if (mlevel < 51) {
multiplier = 230;
}
else if (mlevel < 56) {
multiplier = 240;
}
else if (mlevel < 60) {
multiplier = 250;
}
else if (mlevel < 68) {
multiplier = 260;
}
else {
multiplier = 270;
}
break;
}
case MONK:
case BARD:
case ROGUE:
case BEASTLORD: {
if (mlevel < 51) {
multiplier = 180;
}
else if (mlevel < 58) {
multiplier = 190;
}
else if (mlevel < 70) {
multiplier = 200;
}
else {
multiplier = 210;
}
break;
if (mlevel < 51) {
multiplier = 180;
}
else if (mlevel < 58) {
multiplier = 190;
}
else if (mlevel < 70) {
multiplier = 200;
}
else {
multiplier = 210;
}
break;
}
case RANGER: {
if (mlevel < 58) {
multiplier = 200;
}
else if (mlevel < 70) {
multiplier = 210;
}
else {
multiplier = 220;
}
break;
if (mlevel < 58) {
multiplier = 200;
}
else if (mlevel < 70) {
multiplier = 210;
}
else {
multiplier = 220;
}
break;
}
case MAGICIAN:
case WIZARD:
case NECROMANCER:
case ENCHANTER: {
if (mlevel < 70) {
multiplier = 120;
}
else {
multiplier = 127;
}
break;
if (mlevel < 70) {
multiplier = 120;
}
else {
multiplier = 127;
}
break;
}
default: {
if (mlevel < 35) {
multiplier = 210;
}
else if (mlevel < 45) {
multiplier = 220;
}
else if (mlevel < 51) {
multiplier = 230;
}
else if (mlevel < 56) {
multiplier = 240;
}
else if (mlevel < 60) {
multiplier = 250;
}
else {
multiplier = 260;
}
break;
if (mlevel < 35) {
multiplier = 210;
}
else if (mlevel < 45) {
multiplier = 220;
}
else if (mlevel < 51) {
multiplier = 230;
}
else if (mlevel < 56) {
multiplier = 240;
}
else if (mlevel < 60) {
multiplier = 250;
}
else {
multiplier = 260;
}
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()) {
+48 -16
View File
@@ -47,6 +47,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/spdat.h"
#include "../common/string_util.h"
#include "../common/zone_numbers.h"
#include "data_bucket.h"
#include "event_codes.h"
#include "guild_mgr.h"
#include "merc.h"
@@ -1419,6 +1420,15 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
drakkin_tattoo = m_pp.drakkin_tattoo;
drakkin_details = m_pp.drakkin_details;
// Max Level for Character:PerCharacterQglobalMaxLevel and Character:PerCharacterBucketMaxLevel
int client_max_level = 0;
if (RuleB(Character, PerCharacterQglobalMaxLevel)) {
client_max_level = GetCharMaxLevelFromQGlobal();
} else if (RuleB(Character, PerCharacterBucketMaxLevel)) {
client_max_level = GetCharMaxLevelFromBucket();
}
SetClientMaxLevel(client_max_level);
// we know our class now, so we might have to fix our consume timer!
if (class_ == MONK)
consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER);
@@ -1746,6 +1756,15 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/* Task Packets */
LoadClientTaskState();
/**
* DevTools Load Settings
*/
if (Admin() >= 200) {
std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", AccountID());
if (DataBucket::GetData(dev_tools_window_key) == "true") {
dev_tools_window_enabled = false;
}
}
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
outapp = new EQApplicationPacket(OP_XTargetResponse, 8);
@@ -10885,33 +10904,46 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
{
if (app->size != sizeof(PopupResponse_Struct)) {
Log(Logs::General, Logs::None, "Size mismatch in OP_PopupResponse expected %i got %i",
sizeof(PopupResponse_Struct), app->size);
Log(Logs::General,
Logs::None,
"Size mismatch in OP_PopupResponse expected %i got %i",
sizeof(PopupResponse_Struct),
app->size);
DumpPacket(app);
return;
}
PopupResponse_Struct *prs = (PopupResponse_Struct*)app->pBuffer;
// Handle any EQEmu defined popup Ids first
switch (prs->popupid)
{
case POPUPID_UPDATE_SHOWSTATSWINDOW:
if (GetTarget() && GetTarget()->IsClient())
GetTarget()->CastToClient()->SendStatsWindow(this, true);
else
SendStatsWindow(this, true);
return;
PopupResponse_Struct *popup_response = (PopupResponse_Struct *) app->pBuffer;
default:
break;
/**
* Handle any EQEmu defined popup Ids first
*/
switch (popup_response->popupid) {
case POPUPID_UPDATE_SHOWSTATSWINDOW:
if (GetTarget() && GetTarget()->IsClient()) {
GetTarget()->CastToClient()->SendStatsWindow(this, true);
}
else {
SendStatsWindow(this, true);
}
return;
break;
case EQEmu::popupresponse::MOB_INFO_DISMISS:
this->SetDisplayMobInfoWindow(false);
this->Message(15, "[DevTools] Window snoozed in this zone...");
break;
default:
break;
}
char buf[16];
sprintf(buf, "%d\0", prs->popupid);
sprintf(buf, "%d\0", popup_response->popupid);
parse->EventPlayer(EVENT_POPUP_RESPONSE, this, buf, 0);
Mob* Target = GetTarget();
Mob *Target = GetTarget();
if (Target && Target->IsNPC()) {
parse->EventNPC(EVENT_POPUP_RESPONSE, Target->CastToNPC(), this, buf, 0);
}
+468 -42
View File
@@ -55,7 +55,7 @@
#include "../say_link.h"
#include "../common/eqemu_logsys.h"
#include "data_bucket.h"
#include "command.h"
#include "guild_mgr.h"
#include "map.h"
@@ -67,6 +67,7 @@
#include "water_map.h"
#include "worldserver.h"
#include "fastmath.h"
#include "npc_scale_manager.h"
extern QueryServ* QServ;
extern WorldServer worldserver;
@@ -184,6 +185,7 @@ int command_init(void)
command_add("delpetition", "[petition number] - Delete a petition", 20, command_delpetition) ||
command_add("depop", "- Depop your NPC target", 50, command_depop) ||
command_add("depopzone", "- Depop the zone", 100, command_depopzone) ||
command_add("devtools", "- Manages devtools", 200, command_devtools) ||
command_add("details", "- Change the details of your target (Drakkin Only)", 80, command_details) ||
command_add("disablerecipe", "[recipe_id] - Disables a recipe using the recipe id.", 80, command_disablerecipe) ||
command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", 80, command_disarmtrap) ||
@@ -249,6 +251,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", "[npcs|players|corpses|doors|objects] [search] - 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) ||
@@ -334,6 +337,7 @@ int command_init(void)
command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) ||
command_add("rules", "(subcommand) - Manage server rules", 250, command_rules) ||
command_add("save", "- Force your player or player corpse target to be saved to the database", 50, command_save) ||
command_add("scale", "- Handles npc scaling", 150, command_scale) ||
command_add("scribespell", "[spellid] - Scribe specified spell in your target's spell book.", 180, command_scribespell) ||
command_add("scribespells", "[max level] [min level] - Scribe all spells for you or your player target that are usable by them, up to level specified. (may freeze client for a few seconds)", 150, command_scribespells) ||
command_add("sendzonespawns", "- Refresh spawn list for all clients in zone", 150, command_sendzonespawns) ||
@@ -1328,16 +1332,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->GetName();
/**
* 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->GetName();
/**
* 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->GetName();
/**
* 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 +1714,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());
@@ -2024,12 +2278,12 @@ void command_grid(Client *c, const Seperator *sep)
}
std::string query = StringFormat(
"SELECT `x`, `y`, `z`, `heading`, `number`, `pause` "
"FROM `grid_entries` "
"WHERE `zoneid` = %u and `gridid` = %i "
"ORDER BY `number` ",
zone->GetZoneID(),
target->CastToNPC()->GetGrid()
"SELECT `x`, `y`, `z`, `heading`, `number`, `pause` "
"FROM `grid_entries` "
"WHERE `zoneid` = %u and `gridid` = %i "
"ORDER BY `number` ",
zone->GetZoneID(),
target->CastToNPC()->GetGrid()
);
auto results = database.QueryDatabase(query);
@@ -2046,11 +2300,12 @@ void command_grid(Client *c, const Seperator *sep)
/**
* Depop any node npc's already spawned
*/
auto &mob_list = entity_list.GetMobList();
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
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();
}
}
/**
@@ -2060,21 +2315,22 @@ void command_grid(Client *c, const Seperator *sep)
auto node_position = glm::vec4(atof(row[0]), atof(row[1]), atof(row[2]), atof(row[3]));
NPC *npc = NPC::SpawnGridNodeNPC(
target->GetCleanName(),
node_position,
static_cast<uint32>(target->CastToNPC()->GetGrid()),
static_cast<uint32>(atoi(row[4])),
static_cast<uint32>(atoi(row[5]))
target->GetCleanName(),
node_position,
static_cast<uint32>(target->CastToNPC()->GetGrid()),
static_cast<uint32>(atoi(row[4])),
static_cast<uint32>(atoi(row[5]))
);
npc->SetFlyMode(1);
npc->GMMove(node_position.x, node_position.y, node_position.z, node_position.w);
}
}
else if (strcasecmp("delete", sep->arg[1]) == 0)
database.ModifyGrid(c, true,atoi(sep->arg[2]),0,0,zone->GetZoneID());
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)");
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)");
}
}
@@ -4345,6 +4601,49 @@ void command_depopzone(Client *c, const Seperator *sep)
c->Message(0, "Zone depoped.");
}
void command_devtools(Client *c, const Seperator *sep)
{
std::string menu_commands_search;
std::string window_toggle_command;
/**
* Search entity commands
*/
menu_commands_search += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#list npcs", false, "NPC") + "] ";
menu_commands_search += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#list players", false, "Players") + "] ";
menu_commands_search += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#list corpses", false, "Corpses") + "] ";
menu_commands_search += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#list doors", false, "Doors") + "] ";
menu_commands_search += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#list objects", false, "Objects") + "] ";
std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", c->AccountID());
/**
* Handle window toggle
*/
if (strcasecmp(sep->arg[1], "disable_window") == 0) {
DataBucket::SetData(dev_tools_window_key, "true");
c->SetDevToolsWindowEnabled(false);
}
if (strcasecmp(sep->arg[1], "enable_window") == 0) {
DataBucket::DeleteData(dev_tools_window_key);
c->SetDevToolsWindowEnabled(true);
}
/**
* Show window status
*/
window_toggle_command = "Disabled [" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#devtools enable_window", false, "Enable") + "] ";
if (c->IsDevToolsWindowEnabled()) {
window_toggle_command = "Enabled [" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#devtools disable_window", false, "Disable") + "] ";
}
/**
* Print menu
*/
c->Message(0, "| [Devtools] Window %s", window_toggle_command.c_str());
c->Message(0, "| [Devtools] Search %s", menu_commands_search.c_str());
}
void command_repop(Client *c, const Seperator *sep)
{
int timearg = 1;
@@ -11147,6 +11446,133 @@ void command_reloadtraps(Client *c, const Seperator *sep)
c->Message(CC_Default, "Traps reloaded for %s.", zone->GetShortName());
}
void command_scale(Client *c, const Seperator *sep)
{
if (sep->argnum == 0) {
c->Message(15, "# Usage # ");
c->Message(15, "#scale [static/dynamic] (With targeted NPC)");
c->Message(15, "#scale [npc_name_search] [static/dynamic] (To make zone-wide changes)");
c->Message(15, "#scale all [static/dynamic]");
return;
}
/**
* Targeted changes
*/
if (c->GetTarget() && c->GetTarget()->IsNPC() && sep->argnum < 2) {
NPC * npc = c->GetTarget()->CastToNPC();
bool apply_status = false;
if (strcasecmp(sep->arg[1], "dynamic") == 0) {
c->Message(15, "Applying global base scaling to npc dynamically (All stats set to zeroes)...");
apply_status = npc_scale_manager->ApplyGlobalBaseScalingToNPCDynamically(npc);
}
else if (strcasecmp(sep->arg[1], "static") == 0) {
c->Message(15, "Applying global base scaling to npc statically (Copying base stats onto NPC)...");
apply_status = npc_scale_manager->ApplyGlobalBaseScalingToNPCStatically(npc);
}
else {
return;
}
if (apply_status) {
c->Message(15, "Applied to NPC '%s' successfully!", npc->GetName());
}
else {
c->Message(15, "Failed to load scaling data from the database "
"for this npc / type, see 'NPCScaling' log for more info");
}
}
else if (c->GetTarget() && sep->argnum < 2) {
c->Message(15, "Target must be an npc!");
}
/**
* Zonewide
*/
if (sep->argnum > 1) {
std::string scale_type;
if (strcasecmp(sep->arg[2], "dynamic") == 0) {
scale_type = "dynamic";
}
else if (strcasecmp(sep->arg[2], "static") == 0) {
scale_type = "static";
}
if (scale_type.length() <= 0) {
c->Message(15, "You must first set if you intend on using static versus dynamic for these changes");
c->Message(15, "#scale [npc_name_search] [static/dynamic]");
c->Message(15, "#scale all [static/dynamic]");
return;
}
std::string search_string = sep->arg[1];
auto &entity_list_search = entity_list.GetNPCList();
int found_count = 0;
for (auto &itr : entity_list_search) {
NPC *entity = itr.second;
std::string entity_name = entity->GetName();
/**
* Filter by name
*/
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos && strcasecmp(sep->arg[1], "all") != 0) {
continue;
}
std::string status = "(Searching)";
if (strcasecmp(sep->arg[3], "apply") == 0) {
status = "(Applying)";
if (strcasecmp(sep->arg[2], "dynamic") == 0) {
npc_scale_manager->ApplyGlobalBaseScalingToNPCDynamically(entity);
}
if (strcasecmp(sep->arg[2], "static") == 0) {
npc_scale_manager->ApplyGlobalBaseScalingToNPCStatically(entity);
}
}
c->Message(
15,
"| ID %5d | %s | x %.0f | y %0.f | z %.0f | DBID %u %s",
entity->GetID(),
entity->GetName(),
entity->GetX(),
entity->GetY(),
entity->GetZ(),
entity->GetNPCTypeID(),
status.c_str()
);
found_count++;
}
if (strcasecmp(sep->arg[3], "apply") == 0) {
c->Message(15, "%s scaling applied against (%i) NPC's", sep->arg[2], found_count);
}
else {
std::string saylink = StringFormat(
"#scale %s %s apply",
sep->arg[1],
sep->arg[2]
);
c->Message(15, "Found (%i) NPC's that match this search...", found_count);
c->Message(
15, "To apply these changes, click <%s> or type %s",
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Apply").c_str(),
saylink.c_str()
);
}
}
}
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
#ifdef BOTS
#include "bot_command.h"
+3
View File
@@ -84,6 +84,7 @@ void command_deletegraveyard(Client *c, const Seperator *sep);
void command_delpetition(Client *c, const Seperator *sep);
void command_depop(Client *c, const Seperator *sep);
void command_depopzone(Client *c, const Seperator *sep);
void command_devtools(Client *c, const Seperator *sep);
void command_details(Client *c, const Seperator *sep);
void command_disablerecipe(Client *c, const Seperator *sep);
void command_disarmtrap(Client *c, const Seperator *sep);
@@ -152,6 +153,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);
@@ -241,6 +243,7 @@ void command_resetaa_timer(Client *c, const Seperator *sep);
void command_revoke(Client *c, const Seperator *sep);
void command_rules(Client *c, const Seperator *sep);
void command_save(Client *c, const Seperator *sep);
void command_scale(Client *c, const Seperator *sep);
void command_scribespell(Client *c, const Seperator *sep);
void command_scribespells(Client *c, const Seperator *sep);
void command_sendop(Client *c, const Seperator *sep);
+27 -13
View File
@@ -820,7 +820,7 @@ void Doors::SetDisableTimer(bool flag) {
void Doors::CreateDatabaseEntry()
{
if(database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion()) - 1 >= 255) {
if (database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion()) - 1 >= 255) {
return;
}
@@ -828,18 +828,32 @@ void Doors::CreateDatabaseEntry()
* Persist
*/
database.InsertDoor(
GetDoorDBID(),
GetDoorID(),
GetDoorName(),
m_Position,
GetOpenType(),
static_cast<uint16>(GetGuildID()),
GetLockpick(),
GetKeyItem(),
static_cast<uint8>(GetDoorParam()),
static_cast<uint8>(GetInvertState()),
GetIncline(),
GetSize()
GetDoorDBID(),
GetDoorID(),
GetDoorName(),
m_Position,
GetOpenType(),
static_cast<uint16>(GetGuildID()),
GetLockpick(),
GetKeyItem(),
static_cast<uint8>(GetDoorParam()),
static_cast<uint8>(GetInvertState()),
GetIncline(),
GetSize()
);
}
float Doors::GetX()
{
return m_Position.x;
}
float Doors::GetY()
{
return m_Position.y;
}
float Doors::GetZ()
{
return m_Position.z;
}
+4
View File
@@ -64,6 +64,10 @@ public:
void SetSize(uint16 size);
void ToggleState(Mob *sender);
float GetX();
float GetY();
float GetZ();
private:
uint32 database_id;
+49 -5
View File
@@ -2870,6 +2870,20 @@ XS(XS__GetInstanceID) {
XSRETURN_UV(id);
}
XS(XS__GetInstanceIDByCharID);
XS(XS__GetInstanceIDByCharID) {
dXSARGS;
if (items != 3)
Perl_croak(aTHX_ "Usage: quest::GetInstanceIDByCharID(string zone_name, uint16 version, uint32 char_id)");
char *zone = (char *) SvPV_nolen(ST(0));
uint16 version = (int) SvUV(ST(1));
uint32 char_id = (int) SvUV(ST(2));
uint16 id = quest_manager.GetInstanceIDByCharID(zone, version, char_id);
XSRETURN_UV(id);
}
XS(XS__GetCharactersInInstance);
XS(XS__GetCharactersInInstance) {
dXSARGS;
@@ -2921,6 +2935,19 @@ XS(XS__AssignToInstance) {
XSRETURN_EMPTY;
}
XS(XS__AssignToInstanceByCharID);
XS(XS__AssignToInstanceByCharID) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: quest::AssignToInstanceByCharID(uint16 instance_id, uint32 char_id)");
uint16 instance_id = (int) SvUV(ST(0));
uint32 char_id = (int) SvUV(ST(1));
quest_manager.AssignToInstanceByCharID(instance_id, char_id);
XSRETURN_EMPTY;
}
XS(XS__AssignGroupToInstance);
XS(XS__AssignGroupToInstance) {
dXSARGS;
@@ -2957,6 +2984,19 @@ XS(XS__RemoveFromInstance) {
XSRETURN_EMPTY;
}
XS(XS__RemoveFromInstanceByCharID);
XS(XS__RemoveFromInstanceByCharID) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: quest::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id)");
uint16 instance_id = (int) SvUV(ST(0));
uint32 char_id = (int) SvUV(ST(1));
quest_manager.RemoveFromInstanceByCharID(instance_id, char_id);
XSRETURN_EMPTY;
}
XS(XS__RemoveAllFromInstance);
XS(XS__RemoveAllFromInstance) {
dXSARGS;
@@ -3025,10 +3065,10 @@ XS(XS__saylink) {
Perl_croak(aTHX_ "Usage: quest::saylink(string message, [bool silent = false], [link_name = message])");
dXSTARG;
Const_char *RETVAL;
char message[250];
char link_name[250];
bool silent = false;
std::string RETVAL;
char message[250];
char link_name[250];
bool silent = false;
strcpy(message, (char *) SvPV_nolen(ST(0)));
if (items >= 2) {
silent = ((int) SvIV(ST(1))) == 0 ? false : true;
@@ -3039,7 +3079,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);
@@ -3675,6 +3716,7 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "AssignGroupToInstance"), XS__AssignGroupToInstance, file);
newXS(strcpy(buf, "AssignRaidToInstance"), XS__AssignRaidToInstance, file);
newXS(strcpy(buf, "AssignToInstance"), XS__AssignToInstance, file);
newXS(strcpy(buf, "AssignToInstanceByCharID"), XS__AssignToInstanceByCharID, file);
newXS(strcpy(buf, "ChooseRandom"), XS__ChooseRandom, file);
newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file);
newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file);
@@ -3686,6 +3728,7 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file);
newXS(strcpy(buf, "GetCharactersInInstance"), XS__GetCharactersInInstance, file);
newXS(strcpy(buf, "GetInstanceID"), XS__GetInstanceID, file);
newXS(strcpy(buf, "GetInstanceIDByCharID"), XS__GetInstanceIDByCharID, file);
newXS(strcpy(buf, "GetSpellResistType"), XS__GetSpellResistType, file);
newXS(strcpy(buf, "GetSpellTargetType"), XS__GetSpellTargetType, file);
newXS(strcpy(buf, "GetTimeSeconds"), XS__GetTimeSeconds, file);
@@ -3704,6 +3747,7 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "MovePCInstance"), XS__MovePCInstance, file);
newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file);
newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, file);
newXS(strcpy(buf, "RemoveFromInstanceByCharID"), XS__RemoveFromInstanceByCharID, file);
newXS(strcpy(buf, "SendMail"), XS__SendMail, file);
newXS(strcpy(buf, "SetRunning"), XS__SetRunning, file);
newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file);
+2 -52
View File
@@ -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;
-1
View File
@@ -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();
+23 -9
View File
@@ -684,14 +684,12 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
}
}
if(RuleB(Character, PerCharacterQglobalMaxLevel)){
uint32 MaxLevel = GetCharMaxLevelFromQGlobal();
if(MaxLevel){
if(GetLevel() >= MaxLevel){
uint32 expneeded = GetEXPForLevel(MaxLevel);
if(set_exp > expneeded) {
set_exp = expneeded;
}
if (GetClientMaxLevel() > 0) {
int client_max_level = GetClientMaxLevel();
if (GetLevel() >= client_max_level) {
uint32 expneeded = GetEXPForLevel(client_max_level);
if(set_exp > expneeded) {
set_exp = expneeded;
}
}
}
@@ -1130,7 +1128,23 @@ uint32 Client::GetCharMaxLevelFromQGlobal() {
++gcount;
}
return false;
return 0;
}
uint32 Client::GetCharMaxLevelFromBucket() {
uint32 char_id = this->CharacterID();
std::string query = StringFormat("SELECT value FROM data_buckets WHERE key = '%i-CharMaxLevel'", char_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
Log(Logs::General, Logs::Error, "Data bucket for CharMaxLevel for char ID %i failed.", char_id);
return 0;
}
if (results.RowCount() > 0) {
auto row = results.begin();
return atoi(row[0]);
}
return 0;
}
uint32 Client::GetRequiredAAExperience() {
+32 -21
View File
@@ -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) {
@@ -866,10 +862,18 @@ int lua_get_instance_id(const char *zone, uint32 version) {
return quest_manager.GetInstanceID(zone, version);
}
int lua_get_instance_id_by_char_id(const char *zone, uint32 version, uint32 char_id) {
return quest_manager.GetInstanceIDByCharID(zone, version, char_id);
}
void lua_assign_to_instance(uint32 instance_id) {
quest_manager.AssignToInstance(instance_id);
}
void lua_assign_to_instance_by_char_id(uint32 instance_id, uint32 char_id) {
quest_manager.AssignToInstanceByCharID(instance_id, char_id);
}
void lua_assign_group_to_instance(uint32 instance_id) {
quest_manager.AssignGroupToInstance(instance_id);
}
@@ -882,6 +886,10 @@ void lua_remove_from_instance(uint32 instance_id) {
quest_manager.RemoveFromInstance(instance_id);
}
void lua_remove_from_instance_by_char_id(uint32 instance_id, uint32 char_id) {
quest_manager.RemoveFromInstanceByCharID(instance_id, char_id);
}
void lua_remove_all_from_instance(uint32 instance_id) {
quest_manager.RemoveAllFromInstance(instance_id);
}
@@ -1430,19 +1438,19 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
LuaCreateNPCParse(AC, uint32, 0);
LuaCreateNPCParse(Mana, uint32, 0);
LuaCreateNPCParse(ATK, uint32, 0);
LuaCreateNPCParse(STR, uint32, 75);
LuaCreateNPCParse(STA, uint32, 75);
LuaCreateNPCParse(DEX, uint32, 75);
LuaCreateNPCParse(AGI, uint32, 75);
LuaCreateNPCParse(INT, uint32, 75);
LuaCreateNPCParse(WIS, uint32, 75);
LuaCreateNPCParse(CHA, uint32, 75);
LuaCreateNPCParse(MR, int32, 25);
LuaCreateNPCParse(FR, int32, 25);
LuaCreateNPCParse(CR, int32, 25);
LuaCreateNPCParse(PR, int32, 25);
LuaCreateNPCParse(DR, int32, 25);
LuaCreateNPCParse(Corrup, int32, 25);
LuaCreateNPCParse(STR, uint32, 0);
LuaCreateNPCParse(STA, uint32, 0);
LuaCreateNPCParse(DEX, uint32, 0);
LuaCreateNPCParse(AGI, uint32, 0);
LuaCreateNPCParse(INT, uint32, 0);
LuaCreateNPCParse(WIS, uint32, 0);
LuaCreateNPCParse(CHA, uint32, 0);
LuaCreateNPCParse(MR, int32, 0);
LuaCreateNPCParse(FR, int32, 0);
LuaCreateNPCParse(CR, int32, 0);
LuaCreateNPCParse(PR, int32, 0);
LuaCreateNPCParse(DR, int32, 0);
LuaCreateNPCParse(Corrup, int32, 0);
LuaCreateNPCParse(PhR, int32, 0);
LuaCreateNPCParse(haircolor, uint8, 0);
LuaCreateNPCParse(beardcolor, uint8, 0);
@@ -1689,13 +1697,16 @@ luabind::scope lua_register_general() {
luabind::def("destroy_instance", &lua_destroy_instance),
luabind::def("update_instance_timer", &lua_update_instance_timer),
luabind::def("get_instance_id", &lua_get_instance_id),
luabind::def("get_instance_id_by_char_id", &lua_get_instance_id_by_char_id),
luabind::def("get_instance_timer", &lua_get_instance_timer),
luabind::def("get_instance_timer_by_id", &lua_get_instance_timer_by_id),
luabind::def("get_characters_in_instance", &lua_get_characters_in_instance),
luabind::def("assign_to_instance", &lua_assign_to_instance),
luabind::def("assign_to_instance_by_char_id", &lua_assign_to_instance_by_char_id),
luabind::def("assign_group_to_instance", &lua_assign_group_to_instance),
luabind::def("assign_raid_to_instance", &lua_assign_raid_to_instance),
luabind::def("remove_from_instance", &lua_remove_from_instance),
luabind::def("remove_from_instance_by_char_id", &lua_remove_from_instance_by_char_id),
luabind::def("remove_all_from_instance", &lua_remove_all_from_instance),
luabind::def("flag_instance_by_group_leader", &lua_flag_instance_by_group_leader),
luabind::def("flag_instance_by_raid_leader", &lua_flag_instance_by_raid_leader),
+323 -296
View File
@@ -38,149 +38,153 @@ extern EntityList entity_list;
extern Zone* zone;
extern WorldServer worldserver;
Mob::Mob(const char* in_name,
const char* in_lastname,
int32 in_cur_hp,
int32 in_max_hp,
uint8 in_gender,
uint16 in_race,
uint8 in_class,
bodyType in_bodytype,
uint8 in_deity,
uint8 in_level,
uint32 in_npctype_id,
float in_size,
float in_runspeed,
const glm::vec4& position,
uint8 in_light,
uint8 in_texture,
uint8 in_helmtexture,
uint16 in_ac,
uint16 in_atk,
uint16 in_str,
uint16 in_sta,
uint16 in_dex,
uint16 in_agi,
uint16 in_int,
uint16 in_wis,
uint16 in_cha,
uint8 in_haircolor,
uint8 in_beardcolor,
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
uint8 in_eyecolor2,
uint8 in_hairstyle,
uint8 in_luclinface,
uint8 in_beard,
uint32 in_drakkin_heritage,
uint32 in_drakkin_tattoo,
uint32 in_drakkin_details,
EQEmu::TintProfile in_armor_tint,
uint8 in_aa_title,
uint8 in_see_invis, // see through invis/ivu
uint8 in_see_invis_undead,
uint8 in_see_hide,
uint8 in_see_improved_hide,
int32 in_hp_regen,
int32 in_mana_regen,
uint8 in_qglobal,
uint8 in_maxlevel,
uint32 in_scalerate,
uint8 in_armtexture,
uint8 in_bracertexture,
uint8 in_handtexture,
uint8 in_legtexture,
uint8 in_feettexture
) :
attack_timer(2000),
attack_dw_timer(2000),
ranged_timer(2000),
tic_timer(6000),
mana_timer(2000),
spellend_timer(0),
rewind_timer(30000),
bindwound_timer(10000),
stunned_timer(0),
spun_timer(0),
bardsong_timer(6000),
gravity_timer(1000),
viral_timer(0),
m_FearWalkTarget(-999999.0f, -999999.0f, -999999.0f),
m_TargetLocation(glm::vec3()),
m_TargetV(glm::vec3()),
flee_timer(FLEE_CHECK_TIMER),
m_Position(position),
tmHidden(-1),
mitigation_ac(0),
m_specialattacks(eSpecialAttacks::None),
fix_z_timer(300),
fix_z_timer_engaged(100),
attack_anim_timer(1000),
position_update_melee_push_timer(500),
hate_list_cleanup_timer(6000)
Mob::Mob(
const char *in_name,
const char *in_lastname,
int32 in_cur_hp,
int32 in_max_hp,
uint8 in_gender,
uint16 in_race,
uint8 in_class,
bodyType in_bodytype,
uint8 in_deity,
uint8 in_level,
uint32 in_npctype_id,
float in_size,
float in_runspeed,
const glm::vec4 &position,
uint8 in_light,
uint8 in_texture,
uint8 in_helmtexture,
uint16 in_ac,
uint16 in_atk,
uint16 in_str,
uint16 in_sta,
uint16 in_dex,
uint16 in_agi,
uint16 in_int,
uint16 in_wis,
uint16 in_cha,
uint8 in_haircolor,
uint8 in_beardcolor,
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
uint8 in_eyecolor2,
uint8 in_hairstyle,
uint8 in_luclinface,
uint8 in_beard,
uint32 in_drakkin_heritage,
uint32 in_drakkin_tattoo,
uint32 in_drakkin_details,
EQEmu::TintProfile in_armor_tint,
uint8 in_aa_title,
uint8 in_see_invis, // see through invis/ivu
uint8 in_see_invis_undead,
uint8 in_see_hide,
uint8 in_see_improved_hide,
int32 in_hp_regen,
int32 in_mana_regen,
uint8 in_qglobal,
uint8 in_maxlevel,
uint32 in_scalerate,
uint8 in_armtexture,
uint8 in_bracertexture,
uint8 in_handtexture,
uint8 in_legtexture,
uint8 in_feettexture
) :
attack_timer(2000),
attack_dw_timer(2000),
ranged_timer(2000),
tic_timer(6000),
mana_timer(2000),
spellend_timer(0),
rewind_timer(30000),
bindwound_timer(10000),
stunned_timer(0),
spun_timer(0),
bardsong_timer(6000),
gravity_timer(1000),
viral_timer(0),
m_FearWalkTarget(-999999.0f, -999999.0f, -999999.0f),
m_TargetLocation(glm::vec3()),
m_TargetV(glm::vec3()),
flee_timer(FLEE_CHECK_TIMER),
m_Position(position),
tmHidden(-1),
mitigation_ac(0),
m_specialattacks(eSpecialAttacks::None),
fix_z_timer(300),
fix_z_timer_engaged(100),
attack_anim_timer(1000),
position_update_melee_push_timer(500),
hate_list_cleanup_timer(6000)
{
targeted = 0;
tar_ndx = 0;
tar_vector = 0;
targeted = 0;
tar_ndx = 0;
tar_vector = 0;
currently_fleeing = false;
last_major_update_position = m_Position;
is_distance_roamer = false;
is_distance_roamer = false;
AI_Init();
SetMoving(false);
moved = false;
moved = false;
m_RewindLocation = glm::vec3();
_egnode = nullptr;
name[0] = 0;
orig_name[0] = 0;
name[0] = 0;
orig_name[0] = 0;
clean_name[0] = 0;
lastname[0] = 0;
lastname[0] = 0;
if (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;
gender = in_gender;
race = in_race;
base_gender = in_gender;
base_race = in_race;
class_ = in_class;
bodytype = in_bodytype;
}
cur_hp = in_cur_hp;
max_hp = in_max_hp;
base_hp = in_max_hp;
gender = in_gender;
race = in_race;
base_gender = in_gender;
base_race = in_race;
class_ = in_class;
bodytype = in_bodytype;
orig_bodytype = in_bodytype;
deity = in_deity;
level = in_level;
orig_level = in_level;
npctype_id = in_npctype_id;
size = in_size;
base_size = size;
runspeed = in_runspeed;
deity = in_deity;
level = in_level;
orig_level = in_level;
npctype_id = in_npctype_id;
size = in_size;
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);
}
base_runspeed = (int) ((float) runspeed * 40.0f);
// clients
if (runspeed == 0.7f) {
base_runspeed = 28;
walkspeed = 0.3f;
base_runspeed = 28;
walkspeed = 0.3f;
base_walkspeed = 12;
fearspeed = 0.625f;
fearspeed = 0.625f;
base_fearspeed = 25;
// npcs
}
else {
base_walkspeed = base_runspeed * 100 / 265;
walkspeed = ((float)base_walkspeed) * 0.025f;
walkspeed = ((float) base_walkspeed) * 0.025f;
base_fearspeed = base_runspeed * 100 / 127;
fearspeed = ((float)base_fearspeed) * 0.025f;
fearspeed = ((float) base_fearspeed) * 0.025f;
}
last_hp_percent = 0;
last_hp = 0;
last_hp = 0;
current_speed = base_runspeed;
@@ -188,226 +192,223 @@ 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.Type[EQEmu::lightsource::LightInnate] = in_light;
m_Light.Level[EQEmu::lightsource::LightInnate] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightInnate]);
m_Light.Type[EQEmu::lightsource::LightActive] = m_Light.Type[EQEmu::lightsource::LightInnate];
m_Light.Type[EQEmu::lightsource::LightActive] = m_Light.Type[EQEmu::lightsource::LightInnate];
m_Light.Level[EQEmu::lightsource::LightActive] = m_Light.Level[EQEmu::lightsource::LightInnate];
texture = in_texture;
helmtexture = in_helmtexture;
armtexture = in_armtexture;
texture = in_texture;
helmtexture = in_helmtexture;
armtexture = in_armtexture;
bracertexture = in_bracertexture;
handtexture = in_handtexture;
legtexture = in_legtexture;
feettexture = in_feettexture;
multitexture = (armtexture || bracertexture || handtexture || legtexture || feettexture);
handtexture = in_handtexture;
legtexture = in_legtexture;
feettexture = in_feettexture;
multitexture = (armtexture || bracertexture || handtexture || legtexture || feettexture);
haircolor = in_haircolor;
beardcolor = in_beardcolor;
eyecolor1 = in_eyecolor1;
eyecolor2 = in_eyecolor2;
hairstyle = in_hairstyle;
luclinface = in_luclinface;
beard = in_beard;
drakkin_heritage = in_drakkin_heritage;
drakkin_tattoo = in_drakkin_tattoo;
drakkin_details = in_drakkin_details;
attack_speed = 0;
attack_delay = 0;
slow_mitigation = 0;
findable = false;
trackable = true;
has_shieldequiped = false;
haircolor = in_haircolor;
beardcolor = in_beardcolor;
eyecolor1 = in_eyecolor1;
eyecolor2 = in_eyecolor2;
hairstyle = in_hairstyle;
luclinface = in_luclinface;
beard = in_beard;
drakkin_heritage = in_drakkin_heritage;
drakkin_tattoo = in_drakkin_tattoo;
drakkin_details = in_drakkin_details;
attack_speed = 0;
attack_delay = 0;
slow_mitigation = 0;
findable = false;
trackable = true;
has_shieldequiped = false;
has_twohandbluntequiped = false;
has_twohanderequipped = false;
can_facestab = false;
has_numhits = false;
has_MGB = false;
has_ProjectIllusion = false;
SpellPowerDistanceMod = 0;
last_los_check = false;
has_twohanderequipped = false;
can_facestab = false;
has_numhits = false;
has_MGB = false;
has_ProjectIllusion = false;
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;
STA = in_sta;
DEX = in_dex;
AGI = in_agi;
INT = in_int;
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;
hp_regen = in_hp_regen;
mana_regen = in_mana_regen;
ooc_regen = RuleI(NPC, OOCRegen); //default Out of Combat Regen
maxlevel = in_maxlevel;
scalerate = in_scalerate;
invisible = false;
invisible_undead = false;
AC = in_ac;
ATK = in_atk;
STR = in_str;
STA = in_sta;
DEX = in_dex;
AGI = in_agi;
INT = in_int;
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;
hp_regen = in_hp_regen;
mana_regen = in_mana_regen;
ooc_regen = RuleI(NPC, OOCRegen); //default Out of Combat Regen
maxlevel = in_maxlevel;
scalerate = in_scalerate;
invisible = 0;
invisible_undead = false;
invisible_animals = false;
sneaking = false;
hidden = false;
improved_hidden = false;
invulnerable = false;
IsFullHP = (cur_hp == max_hp);
qglobal = 0;
spawned = false;
rare_spawn = false;
sneaking = false;
hidden = false;
improved_hidden = false;
invulnerable = false;
IsFullHP = (cur_hp == max_hp);
qglobal = 0;
spawned = false;
rare_spawn = false;
InitializeBuffSlots();
// clear the proc arrays
int i;
int j;
for (j = 0; j < MAX_PROCS; j++)
{
PermaProcs[j].spellID = SPELL_UNKNOWN;
PermaProcs[j].chance = 0;
PermaProcs[j].base_spellID = SPELL_UNKNOWN;
PermaProcs[j].level_override = -1;
SpellProcs[j].spellID = SPELL_UNKNOWN;
SpellProcs[j].chance = 0;
SpellProcs[j].base_spellID = SPELL_UNKNOWN;
SpellProcs[j].level_override = -1;
DefensiveProcs[j].spellID = SPELL_UNKNOWN;
DefensiveProcs[j].chance = 0;
DefensiveProcs[j].base_spellID = SPELL_UNKNOWN;
for (int j = 0; j < MAX_PROCS; j++) {
PermaProcs[j].spellID = SPELL_UNKNOWN;
PermaProcs[j].chance = 0;
PermaProcs[j].base_spellID = SPELL_UNKNOWN;
PermaProcs[j].level_override = -1;
SpellProcs[j].spellID = SPELL_UNKNOWN;
SpellProcs[j].chance = 0;
SpellProcs[j].base_spellID = SPELL_UNKNOWN;
SpellProcs[j].level_override = -1;
DefensiveProcs[j].spellID = SPELL_UNKNOWN;
DefensiveProcs[j].chance = 0;
DefensiveProcs[j].base_spellID = SPELL_UNKNOWN;
DefensiveProcs[j].level_override = -1;
RangedProcs[j].spellID = SPELL_UNKNOWN;
RangedProcs[j].chance = 0;
RangedProcs[j].base_spellID = SPELL_UNKNOWN;
RangedProcs[j].level_override = -1;
RangedProcs[j].spellID = SPELL_UNKNOWN;
RangedProcs[j].chance = 0;
RangedProcs[j].base_spellID = SPELL_UNKNOWN;
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;
}
std::fill(std::begin(m_spellHitsLeft), std::end(m_spellHitsLeft), 0);
m_Delta = glm::vec4();
m_Delta = glm::vec4();
animation = 0;
logging_enabled = false;
isgrouped = false;
isgrouped = false;
israidgrouped = false;
IsHorse = false;
entity_id_being_looted = 0;
_appearance = eaStanding;
pRunAnimSpeed = 0;
_appearance = eaStanding;
pRunAnimSpeed = 0;
spellend_timer.Disable();
bardsong_timer.Disable();
bardsong = 0;
bardsong_target_id = 0;
casting_spell_id = 0;
casting_spell_timer = 0;
bardsong = 0;
bardsong_target_id = 0;
casting_spell_id = 0;
casting_spell_timer = 0;
casting_spell_timer_duration = 0;
casting_spell_inventory_slot = 0;
casting_spell_aa_id = 0;
target = 0;
casting_spell_aa_id = 0;
target = 0;
ActiveProjectileATK = false;
for (int i = 0; i < MAX_SPELL_PROJECTILE; i++)
{
ProjectileAtk[i].increment = 0;
for (int i = 0; i < MAX_SPELL_PROJECTILE; i++) {
ProjectileAtk[i].increment = 0;
ProjectileAtk[i].hit_increment = 0;
ProjectileAtk[i].target_id = 0;
ProjectileAtk[i].wpn_dmg = 0;
ProjectileAtk[i].origin_x = 0.0f;
ProjectileAtk[i].origin_y = 0.0f;
ProjectileAtk[i].origin_z = 0.0f;
ProjectileAtk[i].tlast_x = 0.0f;
ProjectileAtk[i].tlast_y = 0.0f;
ProjectileAtk[i].ranged_id = 0;
ProjectileAtk[i].ammo_id = 0;
ProjectileAtk[i].ammo_slot = 0;
ProjectileAtk[i].skill = 0;
ProjectileAtk[i].speed_mod = 0.0f;
ProjectileAtk[i].target_id = 0;
ProjectileAtk[i].wpn_dmg = 0;
ProjectileAtk[i].origin_x = 0.0f;
ProjectileAtk[i].origin_y = 0.0f;
ProjectileAtk[i].origin_z = 0.0f;
ProjectileAtk[i].tlast_x = 0.0f;
ProjectileAtk[i].tlast_y = 0.0f;
ProjectileAtk[i].ranged_id = 0;
ProjectileAtk[i].ammo_id = 0;
ProjectileAtk[i].ammo_slot = 0;
ProjectileAtk[i].skill = 0;
ProjectileAtk[i].speed_mod = 0.0f;
}
memset(&itembonuses, 0, sizeof(StatBonuses));
memset(&spellbonuses, 0, sizeof(StatBonuses));
memset(&aabonuses, 0, sizeof(StatBonuses));
spellbonuses.AggroRange = -1;
spellbonuses.AggroRange = -1;
spellbonuses.AssistRange = -1;
pLastChange = 0;
SetPetID(0);
SetOwnerID(0);
typeofpet = petNone; // default to not a pet
petpower = 0;
held = false;
gheld = false;
nocast = false;
focused = false;
pet_stop = false;
pet_regroup = false;
_IsTempPet = false;
pet_owner_client = false;
typeofpet = petNone; // default to not a pet
petpower = 0;
held = false;
gheld = false;
nocast = false;
focused = false;
pet_stop = false;
pet_regroup = false;
_IsTempPet = false;
pet_owner_client = false;
pet_targetlock_id = 0;
attacked_count = 0;
mezzed = false;
stunned = false;
silenced = false;
amnesiad = false;
inWater = false;
mezzed = false;
stunned = false;
silenced = false;
amnesiad = false;
inWater = false;
int m;
for (m = 0; m < MAX_SHIELDERS; m++)
{
shielder[m].shielder_id = 0;
for (m = 0; m < MAX_SHIELDERS; m++) {
shielder[m].shielder_id = 0;
shielder[m].shielder_bonus = 0;
}
destructibleobject = false;
wandertype = 0;
pausetype = 0;
cur_wp = 0;
m_CurrentWayPoint = glm::vec4();
cur_wp_pause = 0;
patrol = 0;
follow_id = 0;
follow_dist = 100; // Default Distance for Follow
follow_run = true; // We can run if distance great enough
no_target_hotkey = false;
flee_mode = false;
currently_fleeing = false;
wandertype = 0;
pausetype = 0;
cur_wp = 0;
m_CurrentWayPoint = glm::vec4();
cur_wp_pause = 0;
patrol = 0;
follow_id = 0;
follow_dist = 100; // Default Distance for Follow
follow_run = true; // We can run if distance great enough
no_target_hotkey = false;
flee_mode = false;
currently_fleeing = false;
flee_timer.Start();
permarooted = (runspeed > 0) ? false : true;
movetimercompleted = false;
ForcedMovement = 0;
roamer = false;
rooted = false;
charmed = false;
has_virus = false;
for (i = 0; i < MAX_SPELL_TRIGGER * 2; i++) {
ForcedMovement = 0;
roamer = false;
rooted = false;
charmed = false;
has_virus = false;
for (int i = 0; i < MAX_SPELL_TRIGGER * 2; i++) {
viral_spells[i] = 0;
}
pStandingPetOrder = SPO_Follow;
pseudo_rooted = false;
see_invis = GetSeeInvisible(in_see_invis);
see_invis_undead = GetSeeInvisible(in_see_invis_undead);
see_hide = GetSeeInvisible(in_see_hide);
pStandingPetOrder = SPO_Follow;
pseudo_rooted = false;
see_invis = GetSeeInvisible(in_see_invis);
see_invis_undead = GetSeeInvisible(in_see_invis_undead);
see_hide = GetSeeInvisible(in_see_hide);
see_improved_hide = GetSeeInvisible(in_see_improved_hide);
qglobal = in_qglobal != 0;
@@ -416,12 +417,12 @@ Mob::Mob(const char* in_name,
bindwound_timer.Disable();
bindwound_target = 0;
trade = new Trade(this);
trade = new Trade(this);
// hp event
nexthpevent = -1;
nexthpevent = -1;
nextinchpevent = -1;
hasTempPet = false;
hasTempPet = false;
count_TempPet = 0;
m_is_running = false;
@@ -429,25 +430,31 @@ Mob::Mob(const char* in_name,
nimbus_effect1 = 0;
nimbus_effect2 = 0;
nimbus_effect3 = 0;
m_targetable = true;
m_targetable = true;
m_TargetRing = glm::vec3();
flymode = FlyMode3;
flymode = FlyMode3;
DistractedFromGrid = false;
hate_list.SetHateOwner(this);
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; }
m_DisableMelee = false;
emoteid = 0;
endur_upkeep = 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;
}
emoteid = 0;
endur_upkeep = false;
degenerating_effects = false;
PrimaryAggro = false;
AssistAggro = false;
npc_assist_cap = 0;
PrimaryAggro = false;
AssistAggro = false;
npc_assist_cap = 0;
PathRecalcTimer.reset(new Timer(500));
PathingLoopCount = 0;
@@ -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;
}
@@ -3239,8 +3247,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str)
const char *Mob::GetCleanName()
{
if(!strlen(clean_name))
{
if (!strlen(clean_name)) {
CleanMobName(GetName(), clean_name);
}
@@ -3466,24 +3473,33 @@ 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);
if (this->CastToClient()->admin > 200) {
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
@@ -3633,11 +3649,10 @@ void Mob::SetEntityVariable(const char *id, const char *m_var)
m_EntityVariables[id] = n_m_var;
}
const char* Mob::GetEntityVariable(const char *id)
const char *Mob::GetEntityVariable(const char *id)
{
auto iter = m_EntityVariables.find(id);
if(iter != m_EntityVariables.end())
{
if (iter != m_EntityVariables.end()) {
return iter->second.c_str();
}
return nullptr;
@@ -5553,14 +5568,26 @@ bool Mob::HasSpellEffect(int effectid)
return(0);
}
int Mob::GetSpecialAbility(int ability) {
if(ability >= MAX_SPECIAL_ATTACK || ability < 0) {
int Mob::GetSpecialAbility(int ability)
{
if (ability >= MAX_SPECIAL_ATTACK || ability < 0) {
return 0;
}
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;
+22 -1
View File
@@ -166,6 +166,10 @@ public:
bool is_distance_roamer;
void DisplayInfo(Mob *mob);
public:
//Somewhat sorted: needs documenting!
//Attack
@@ -482,6 +486,11 @@ public:
inline virtual int32 GetINT() const { return INT + itembonuses.INT + spellbonuses.INT; }
inline virtual int32 GetWIS() const { return WIS + itembonuses.WIS + spellbonuses.WIS; }
inline virtual int32 GetCHA() const { return CHA + itembonuses.CHA + spellbonuses.CHA; }
inline virtual int32 GetHeroicMR() const { return 0; }
inline virtual int32 GetHeroicFR() const { return 0; }
inline virtual int32 GetHeroicDR() const { return 0; }
inline virtual int32 GetHeroicPR() const { return 0; }
inline virtual int32 GetHeroicCR() const { return 0; }
inline virtual int32 GetMR() const { return MR + itembonuses.MR + spellbonuses.MR; }
inline virtual int32 GetFR() const { return FR + itembonuses.FR + spellbonuses.FR; }
inline virtual int32 GetDR() const { return DR + itembonuses.DR + spellbonuses.DR; }
@@ -495,6 +504,13 @@ public:
inline StatBonuses* GetItemBonusesPtr() { return &itembonuses; }
inline StatBonuses* GetSpellBonusesPtr() { return &spellbonuses; }
inline StatBonuses* GetAABonusesPtr() { return &aabonuses; }
inline virtual int32 GetHeroicSTR() const { return 0; }
inline virtual int32 GetHeroicSTA() const { return 0; }
inline virtual int32 GetHeroicDEX() const { return 0; }
inline virtual int32 GetHeroicAGI() const { return 0; }
inline virtual int32 GetHeroicINT() const { return 0; }
inline virtual int32 GetHeroicWIS() const { return 0; }
inline virtual int32 GetHeroicCHA() const { return 0; }
inline virtual int32 GetMaxSTR() const { return GetSTR(); }
inline virtual int32 GetMaxSTA() const { return GetSTA(); }
inline virtual int32 GetMaxDEX() const { return GetDEX(); }
@@ -514,6 +530,7 @@ public:
inline int32 GetMaxMana() const { return max_mana; }
inline int32 GetMana() const { return current_mana; }
virtual int32 GetEndurance() const { return 0; }
virtual int32 GetMaxEndurance() const { return 0; }
virtual void SetEndurance(int32 newEnd) { return; }
int32 GetItemHPBonuses();
int32 GetSpellHPBonuses();
@@ -1049,6 +1066,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 +1164,10 @@ 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;
int32 GetManaRegen() const;
// Bots HealRotation methods
#ifdef BOTS
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
@@ -1476,7 +1498,6 @@ protected:
bool pAIControlled;
bool roamer;
bool logging_enabled;
int wandertype;
int pausetype;
+831
View File
@@ -0,0 +1,831 @@
/**
* 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"
#include "npc_scale_manager.h"
std::string commify(const std::string &number)
{
std::string temp_string;
auto string_length = static_cast<int>(number.length());
int i = 0;
for (i = string_length - 3; i >= 0; i -= 3) {
if (i > 0) {
temp_string = "," + number.substr(static_cast<unsigned long>(i), 3) + temp_string;
}
else {
temp_string = number.substr(static_cast<unsigned long>(i), 3) + temp_string;
}
}
if (i < 0) {
temp_string = number.substr(0, static_cast<unsigned long>(3 + i)) + temp_string;
}
return temp_string;
}
inline std::string GetMobAttributeByString(Mob *mob, const std::string &attribute)
{
std::string entity_variable = "modify_stat_" + attribute;
std::string scaling_modified;
if (mob->GetEntityVariable(entity_variable.c_str())) {
scaling_modified = " *";
}
if (attribute == "ac") {
if (mob->GetEntityVariable(std::string("modify_stat_max_hp").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string(mob->GetAC())) + scaling_modified;
}
if (attribute == "atk") {
return std::to_string(mob->GetATK()) + scaling_modified;
}
if (attribute == "end") {
int endurance = 0;
if (mob->IsClient()) {
endurance = mob->CastToClient()->GetEndurance();
}
return commify(std::to_string(endurance));
}
if (attribute == "hp") {
return commify(std::to_string(mob->GetHP()));
}
if (attribute == "hp_min_max") {
if (mob->GetEntityVariable(std::string("modify_stat_max_hp").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string(mob->GetHP())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxHP())) + " (" +
std::to_string((int) mob->GetHPRatio()) + "%)";
}
if (attribute == "mana") {
return commify(std::to_string(mob->GetMana()));
}
if (attribute == "mp_min_max") {
return commify(std::to_string(mob->GetMana())) + " / " + commify(std::to_string(mob->GetMaxMana())) + " (" +
std::to_string((int) mob->GetManaPercent()) + "%)";
}
if (attribute == "end_min_max") {
return commify(std::to_string(mob->GetEndurance())) + " / " + commify(std::to_string(mob->GetMaxEndurance())) + " (" +
std::to_string((int)mob->GetEndurancePercent()) + "%)";
}
if (attribute == "str") {
return commify(std::to_string(mob->GetSTR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxSTR())) + " +" +
commify(std::to_string(mob->GetHeroicSTR()));
}
if (attribute == "sta") {
return commify(std::to_string(mob->GetSTA())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxSTA())) + " +" +
commify(std::to_string(mob->GetHeroicSTA()));
}
if (attribute == "dex") {
return commify(std::to_string(mob->GetDEX())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxDEX())) + " +" +
commify(std::to_string(mob->GetHeroicDEX()));
}
if (attribute == "agi") {
return commify(std::to_string(mob->GetAGI())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxAGI())) + " +" +
commify(std::to_string(mob->GetHeroicAGI()));
}
if (attribute == "int") {
return commify(std::to_string(mob->GetINT())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxINT())) + " +" +
commify(std::to_string(mob->GetHeroicINT()));
}
if (attribute == "wis") {
return commify(std::to_string(mob->GetWIS())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxWIS())) + " +" +
commify(std::to_string(mob->GetHeroicWIS()));
}
if (attribute == "cha") {
return commify(std::to_string(mob->GetCHA())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxCHA())) + " +" +
commify(std::to_string(mob->GetHeroicCHA()));
}
if (attribute == "mr") {
return commify(std::to_string(mob->GetMR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxMR())) + " +" +
commify(std::to_string(mob->GetHeroicMR()));
}
if (attribute == "cr") {
return commify(std::to_string(mob->GetCR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxCR())) + " +" +
commify(std::to_string(mob->GetHeroicCR()));
}
if (attribute == "fr") {
return commify(std::to_string(mob->GetFR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxFR())) + " +" +
commify(std::to_string(mob->GetHeroicFR()));
}
if (attribute == "pr") {
return commify(std::to_string(mob->GetPR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxPR())) + " +" +
commify(std::to_string(mob->GetHeroicPR()));
}
if (attribute == "dr") {
return commify(std::to_string(mob->GetDR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxDR())) + " +" +
commify(std::to_string(mob->GetHeroicDR()));
}
if (attribute == "cr") {
return commify(std::to_string(mob->GetCR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxCR())) + " +" +
commify(std::to_string(mob->GetHeroicCR()));
}
if (attribute == "pr") {
return commify(std::to_string(mob->GetPR())) + scaling_modified + " / " +
commify(std::to_string(mob->GetMaxPR())) + " +" +
commify(std::to_string(mob->GetHeroicPR()));
}
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 == "surname") {
std::string last_name = mob->GetLastName();
return (last_name.length() > 0 ? 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 (attribute == "flymode") {
return std::to_string(mob->GetFlyMode());
}
if (attribute == "maxbuffslots") {
return std::to_string(mob->GetMaxBuffSlots());
}
if (attribute == "curbuffslots") {
return std::to_string(mob->GetCurrentBuffSlots());
}
if (attribute == "tohit") {
return std::to_string(mob->compute_tohit(EQEmu::skills::SkillHandtoHand));
}
if (attribute == "total_to_hit") {
return std::to_string(mob->GetTotalToHit(EQEmu::skills::SkillHandtoHand, 0));
}
if (attribute == "defense") {
return std::to_string(mob->compute_defense());
}
if (attribute == "total_defense") {
return std::to_string(mob->GetTotalDefense());
}
if (attribute == "offense") {
return std::to_string(mob->offense(EQEmu::skills::SkillHandtoHand));
}
if (attribute == "mitigation_ac") {
return std::to_string(mob->GetMitigationAC());
}
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((int)npc->GetSize());
}
if (attribute == "runspeed") {
return std::to_string((int)npc->GetRunspeed());
}
if (attribute == "walkspeed") {
return std::to_string((int)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());
}
if (attribute == "see_invis") {
return std::to_string(npc->SeeInvisible());
}
if (attribute == "see_invis_undead") {
return std::to_string(npc->SeeInvisibleUndead());
}
if (attribute == "faction") {
return std::to_string(npc->GetNPCFactionID());
}
if (attribute == "loottable") {
return std::to_string(npc->GetLoottableID());
}
if (attribute == "prim_skill") {
return std::to_string(npc->GetPrimSkill());
}
if (attribute == "sec_skill") {
return std::to_string(npc->GetSecSkill());
}
if (attribute == "melee_texture_1") {
return std::to_string(npc->GetMeleeTexture1());
}
if (attribute == "melee_texture_2") {
return std::to_string(npc->GetMeleeTexture2());
}
if (attribute == "aggrorange") {
return std::to_string((int)npc->GetAggroRange());
}
if (attribute == "assistrange") {
return std::to_string((int)npc->GetAssistRange());
}
if (attribute == "findable") {
return std::to_string(npc->IsFindable());
}
if (attribute == "trackable") {
return std::to_string(npc->IsTrackable());
}
if (attribute == "spells_id") {
return std::to_string(npc->GetNPCSpellsID());
}
if (attribute == "roambox_min_x") {
return std::to_string((int)npc->GetRoamboxMinX());
}
if (attribute == "roambox_max_x") {
return std::to_string((int)npc->GetRoamboxMaxX());
}
if (attribute == "roambox_min_y") {
return std::to_string((int)npc->GetRoamboxMinY());
}
if (attribute == "roambox_max_y") {
return std::to_string((int)npc->GetRoamboxMaxY());
}
if (attribute == "roambox_min_delay") {
return std::to_string((int)npc->GetRoamboxMinDelay());
}
if (attribute == "roambox_delay") {
return std::to_string((int)npc->GetRoamboxDelay());
}
if (attribute == "roambox_distance") {
return std::to_string((int)npc->GetRoamboxDistance());
}
if (attribute == "proximity_min_x") {
return std::to_string((int)npc->GetProximityMinX());
}
if (attribute == "proximity_max_x") {
return std::to_string((int)npc->GetProximityMaxX());
}
if (attribute == "proximity_min_y") {
return std::to_string((int)npc->GetProximityMinY());
}
if (attribute == "proximity_max_y") {
return std::to_string((int)npc->GetProximityMaxY());
}
if (attribute == "proximity_min_z") {
return std::to_string((int)npc->GetProximityMinZ());
}
if (attribute == "proximity_max_z") {
return std::to_string((int)npc->GetProximityMaxZ());
}
if (attribute == "accuracy") {
return std::to_string((int)npc->GetAccuracyRating()) + scaling_modified;
}
if (attribute == "slow_mitigation") {
if (mob->GetEntityVariable(std::string("modify_stat_slow_mitigation").c_str())) {
scaling_modified = " *";
}
return std::to_string((int)npc->GetSlowMitigation()) + scaling_modified;
}
if (attribute == "min_hit") {
if (mob->GetEntityVariable(std::string("modify_stat_min_hit").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string((int)npc->GetMinDMG())) + scaling_modified;
}
if (attribute == "max_hit") {
if (mob->GetEntityVariable(std::string("modify_stat_max_hit").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string((int)npc->GetMaxDMG())) + scaling_modified;
}
if (attribute == "hp_regen") {
if (mob->GetEntityVariable(std::string("modify_stat_hp_regen").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string((int)npc->GetHPRegen())) + scaling_modified;
}
if (attribute == "attack_delay") {
if (mob->GetEntityVariable(std::string("modify_stat_attack_delay").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string(npc->GetAttackDelay())) + scaling_modified;
}
if (attribute == "spell_scale") {
if (mob->GetEntityVariable(std::string("modify_stat_spell_scale").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string((int)npc->GetSpellScale())) + scaling_modified;
}
if (attribute == "heal_scale") {
if (mob->GetEntityVariable(std::string("modify_stat_heal_scale").c_str())) {
scaling_modified = " *";
}
return commify(std::to_string((int)npc->GetHealScale())) + scaling_modified;
}
if (attribute == "avoidance") {
return commify(std::to_string((int)npc->GetAvoidanceRating())) + scaling_modified;
}
npc->GetNPCEmote(npc->GetEmoteID(), 0);
}
if (mob->IsClient()) {
Client *client = mob->CastToClient();
if (attribute == "shielding") {
return commify(std::to_string((int)client->GetShielding())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemShieldingCap)));
}
if (attribute == "spell_shielding") {
return commify(std::to_string((int)client->GetSpellShield())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemSpellShieldingCap)));
}
if (attribute == "dot_shielding") {
return commify(std::to_string((int)client->GetDoTShield())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemDoTShieldingCap)));
}
if (attribute == "stun_resist") {
return commify(std::to_string((int)client->GetStunResist())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemStunResistCap)));
}
if (attribute == "damage_shield") {
return commify(std::to_string((int)client->GetDS())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemDamageShieldCap)));
}
if (attribute == "avoidance") {
return commify(std::to_string((int) client->GetAvoidance())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemAvoidanceCap)));
}
if (attribute == "strikethrough") {
return commify(std::to_string((int) client->GetStrikeThrough())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemStrikethroughCap)));
}
if (attribute == "accuracy") {
return commify(std::to_string((int) client->GetAccuracy())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemAccuracyCap)));
}
if (attribute == "combat_effects") {
return commify(std::to_string((int) client->GetCombatEffects())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemCombatEffectsCap)));
}
if (attribute == "heal_amount") {
return commify(std::to_string((int) client->GetHealAmt())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemHealAmtCap)));
}
if (attribute == "spell_dmg") {
return commify(std::to_string((int) client->GetSpellDmg())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemSpellDmgCap)));
}
if (attribute == "clairvoyance") {
return commify(std::to_string((int) client->GetClair())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemClairvoyanceCap)));
}
if (attribute == "ds_mitigation") {
return commify(std::to_string((int) client->GetDSMit())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemDSMitigationCap)));
}
if (attribute == "hp_regen") {
return commify(std::to_string((int) client->GetHPRegen())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemHealthRegenCap)));
}
if (attribute == "mana_regen") {
return commify(std::to_string((int) client->GetManaRegen())) + " / " +
commify(std::to_string((int) RuleI(Character, ItemManaRegenCap)));
}
if (attribute == "end_regen") {
return commify(std::to_string((int) client->CalcEnduranceRegen())) + " / " +
commify(std::to_string((int) client->CalcEnduranceRegenCap()));
}
}
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 &section_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;
find_replace(attribute_name, "_min_max", std::string(""));
/**
* Translate attribute names with underscores
* "total_to_hit" = "Total To Hit"
*/
if (attribute_name.find('_') != std::string::npos) {
std::vector<std::string> split_string = split(attribute_name, '_');
std::string new_attribute_name;
for (std::string &string_value : split_string) {
new_attribute_name += ucfirst(string_value) + " ";
}
attribute_name = new_attribute_name;
}
/**
* Attribute names less than 4 characters get capitalized
* "hp" = "HP"
*/
if (attribute_name.length() <= 3) {
attribute_name = str_toupper(attribute_name);
}
/**
* Attribute names larger than 3 characters get capitalized first letter
* "avoidance" = "Avoidance"
*/
if (attribute_name.length() > 3) {
attribute_name = ucfirst(attribute_name);
}
find_replace(attribute_name, "Proximity", std::string(""));
find_replace(attribute_name, "Roambox", std::string(""));
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 (npc->GetLoottableID() > 0) {
menu_commands += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#npcloot show", false, "Loot") + "] ";
}
if (menu_commands.length() > 0) {
std::string dev_menu = "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#devtools", false, "DevTools") + "] ";;
client->Message(0, "| %s [Show Commands] %s", dev_menu.c_str(), menu_commands.c_str());
}
}
void Mob::DisplayInfo(Mob *mob)
{
if (!mob) {
return;
}
if (this->IsClient()) {
std::string window_text = "<c \"#FFFF66\">*Drag window open vertically to see all</c><br>";
Client *client = this->CastToClient();
if (!client->IsDevToolsWindowEnabled()) {
return;
}
std::vector<std::string> info_attributes = {
"name",
"race",
"surname",
"class",
};
window_text += WriteDisplayInfoSection(mob, "Info", info_attributes, 1, false);
std::vector<std::string> basic_attributes = {
"type",
"level",
"hp_min_max",
"ac",
"mp_min_max",
"atk",
"end_min_max",
};
window_text += WriteDisplayInfoSection(mob, "Main", basic_attributes, 1, false);
std::vector<std::string> stat_attributes = {
"str",
"sta",
"agi",
"dex",
"wis",
"int",
"cha",
};
window_text += WriteDisplayInfoSection(mob, "Statistics", stat_attributes, 1, false);
std::vector<std::string> resist_attributes = {
"pr",
"mr",
"dr",
"fr",
"cr",
"cor",
"phy",
};
window_text += WriteDisplayInfoSection(mob, "Resists", resist_attributes, 1, false);
std::vector<std::string> calculations = {
"tohit",
"total_to_hit",
"defense",
"total_defense",
"offense",
"mitigation_ac",
};
window_text += WriteDisplayInfoSection(mob, "Calculations", calculations, 1, true);
if (mob->IsClient()) {
std::vector<std::string> mods = {
"hp_regen",
"mana_regen",
"end_regen",
"heal_amount",
"spell_dmg",
"clairvoyance",
};
window_text += WriteDisplayInfoSection(mob, "Mods", mods, 1, true);
std::vector<std::string> mod_defensive = {
"shielding",
"spell_shielding",
"dot_shielding",
"stun_resist",
"damage_shield",
"ds_mitigation",
"avoidance",
};
window_text += WriteDisplayInfoSection(mob, "Mod Defensive", mod_defensive, 1, true);
std::vector<std::string> mod_offensive = {
"strikethrough",
"accuracy",
"combat_effects",
};
window_text += WriteDisplayInfoSection(mob, "Mod Offensive", mod_offensive, 1, true);
}
if (mob->IsNPC()) {
NPC *npc = mob->CastToNPC();
std::vector<std::string> npc_stats = {
"accuracy",
"slow_mitigation",
"min_hit",
"max_hit",
"hp_regen",
"attack_delay",
"spell_scale",
"heal_scale",
"avoidance",
};
window_text += WriteDisplayInfoSection(mob, "NPC Stats", npc_stats, 1, true);
std::vector<std::string> npc_attributes = {
"npcid",
"texture",
"bodytype",
"gender",
"size",
"runspeed",
"walkspeed",
"spawngroup",
"grid",
"emote",
"see_invis",
"see_invis_undead",
"faction",
"loottable",
"prim_skill",
"sec_skill",
"melee_texture_1",
"melee_texture_2",
"aggrorange",
"assistrange",
"findable",
"trackable",
"flymode",
"spells_id",
"curbuffslots",
"maxbuffslots",
};
window_text += WriteDisplayInfoSection(mob, "NPC Attributes", npc_attributes, 1, true);
/**
* Print Roambox
*/
if (npc->GetRoamboxMaxX() != 0 && npc->GetRoamboxMinX() != 0) {
std::vector<std::string> npc_roambox = {
"roambox_min_x",
"roambox_max_x",
"roambox_min_y",
"roambox_max_y",
"roambox_min_delay",
"roambox_delay",
"roambox_distance",
};
window_text += WriteDisplayInfoSection(mob, "Roambox", npc_roambox, 1, true);
}
if (npc->proximity != nullptr) {
std::vector<std::string> npc_proximity = {
"proximity_min_x",
"proximity_max_x",
"proximity_min_y",
"proximity_max_y",
"proximity_min_z",
"proximity_max_z",
};
window_text += WriteDisplayInfoSection(mob, "Proximity", npc_proximity, 1, true);
}
int8 npc_type = npc_scale_manager->GetNPCScalingType(npc);
std::string npc_type_string = npc_scale_manager->GetNPCScalingTypeName(npc);
client->Message(
0,
"| # Target: %s Type: %i (%s)",
npc->GetCleanName(),
npc_type,
npc_type_string.c_str());
NPCCommandsMenu(client, npc);
}
std::cout << "Window Length: " << window_text.length() << std::endl;
if (client->GetDisplayMobInfoWindow()) {
client->SendFullPopup(
"GM: Entity Info",
window_text.c_str(),
EQEmu::popupresponse::MOB_INFO_DISMISS,
0,
100,
0,
"Snooze",
"OK"
);
}
}
}
+8 -2
View File
@@ -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
+593 -574
View File
File diff suppressed because it is too large Load Diff
+41 -11
View File
@@ -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;
@@ -312,6 +320,9 @@ public:
inline bool IsGuarding() const { return(m_GuardPoint.w != 0); }
void SaveGuardSpotCharm();
uint16 GetMeleeTexture1() const;
uint16 GetMeleeTexture2() const;
void RestoreGuardSpotCharm();
void AI_SetRoambox(
@@ -341,6 +352,13 @@ public:
inline const uint32 GetNPCSpellsID() const { return npc_spells_id; }
inline const uint32 GetNPCSpellsEffectsID() const { return npc_spells_effects_id; }
float GetProximityMinX();
float GetProximityMaxX();
float GetProximityMinY();
float GetProximityMaxY();
float GetProximityMinZ();
float GetProximityMaxZ();
ItemList itemlist; //kathgar - why is this public? Doing other things or I would check the code
NPCProximity* proximity;
@@ -357,7 +375,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); }
@@ -435,6 +453,17 @@ public:
bool IgnoreDespawn() { return ignore_despawn; }
float GetRoamboxMaxX() const;
float GetRoamboxMaxY() const;
float GetRoamboxMinX() const;
float GetRoamboxMinY() const;
float GetRoamboxDistance() const;
float GetRoamboxDestinationX() const;
float GetRoamboxDestinationY() const;
float GetRoamboxDestinationZ() const;
uint32 GetRoamboxDelay() const;
uint32 GetRoamboxMinDelay() const;
std::unique_ptr<Timer> AIautocastspell_timer;
protected:
@@ -549,7 +578,8 @@ protected:
uint32 equipment[EQEmu::invslot::EQUIPMENT_COUNT]; //this is an array of item IDs
uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203)
uint16 d_melee_texture1; //this is an item Material value
uint16 d_melee_texture1;
//this is an item Material value
uint16 d_melee_texture2; //this is an item Material value (offhand)
const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile')
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation
+624
View File
@@ -0,0 +1,624 @@
/**
* 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 npc
*/
void NpcScaleManager::ScaleNPC(NPC * npc)
{
int8 npc_type = GetNPCScalingType(npc);
int npc_level = npc->GetLevel();
bool is_auto_scaled = IsAutoScaled(npc);
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
if (!scale_data.level) {
Log(Logs::General, Logs::NPCScaling, "NPC: %s - scaling data not found for type: %i level: %i",
npc->GetCleanName(),
npc_type,
npc_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->GetCorrup() == 0) {
npc->ModifyNPCStat("cr", std::to_string(scale_data.corruption_resist).c_str());
}
if (npc->GetPhR() == 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->GetSpellScale() == 0) {
npc->ModifyNPCStat("spell_scale", std::to_string(scale_data.spell_scale).c_str());
}
if (npc->GetHealScale() == 0) {
npc->ModifyNPCStat("heal_scale", std::to_string(scale_data.heal_scale).c_str());
}
if (!npc->HasSpecialAbilities() && is_auto_scaled) {
npc->ModifyNPCStat("special_abilities", scale_data.special_abilities.c_str());
}
if (LogSys.log_settings[Logs::NPCScaling].is_category_enabled == 1) {
std::string scale_log;
for (const auto &stat : scaling_stats) {
std::string variable = StringFormat("modify_stat_%s", stat.c_str());
if (npc->EntityVariableExists(variable.c_str())) {
scale_log += stat + ": " + npc->GetEntityVariable(variable.c_str()) + " ";
}
}
Log(Logs::General,
Logs::NPCScaling,
"(%s) level: %i type: %i Auto: %s Setting: %s",
npc->GetCleanName(),
npc_level,
npc_type,
(is_auto_scaled ? "true" : "false"),
scale_log.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,"
"spell_scale,"
"heal_scale,"
"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]);
scale_data.spell_scale = atoi(row[25]);
scale_data.heal_scale = atoi(row[26]);
if (row[25]) {
scale_data.special_abilities = row[27];
}
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 npc_type
* @param npc_level
* @return NpcScaleManager::global_npc_scale
*/
NpcScaleManager::global_npc_scale NpcScaleManager::GetGlobalScaleDataForTypeLevel(int8 npc_type, int npc_level)
{
auto iter = npc_global_base_scaling_data.find(std::make_pair(npc_type, npc_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;
}
/**
* @param npc
* @return int8
*/
int8 NpcScaleManager::GetNPCScalingType(NPC *&npc)
{
std::string npc_name = npc->GetName();
if (npc->IsRareSpawn() || npc_name.find('#') != std::string::npos || isupper(npc_name[0])) {
return 1;
}
if (npc->IsRaidTarget()) {
return 2;
}
return 0;
}
/**
* @param npc
* @return std::string
*/
std::string NpcScaleManager::GetNPCScalingTypeName(NPC *&npc)
{
int8 scaling_type = GetNPCScalingType(npc);
if (scaling_type == 1) {
return "Named";
}
if (npc->IsRaidTarget()) {
return "Raid";
}
return "Trash";
}
/**
* Determines based on minimum criteria if NPC is auto scaled for certain things to be scaled like
* special abilities. We use this so we don't blindly assume we want things to be applied
*
* @param npc
* @return
*/
bool NpcScaleManager::IsAutoScaled(NPC *npc)
{
return
(npc->GetHP() == 0 &&
npc->GetMaxDMG() == 0 &&
npc->GetMinDMG() == 0 &&
npc->GetSTR() == 0 &&
npc->GetSTA() == 0 &&
npc->GetDEX() == 0 &&
npc->GetAGI() == 0 &&
npc->GetINT() == 0 &&
npc->GetWIS() == 0 &&
npc->GetCHA() == 0 &&
npc->GetMR() == 0 &&
npc->GetFR() == 0 &&
npc->GetCR() == 0 &&
npc->GetPR() == 0 &&
npc->GetDR() == 0);
}
/**
* Returns false if scaling data not found
* @param npc
* @return
*/
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCStatically(NPC *&npc)
{
int8 npc_type = GetNPCScalingType(npc);
int npc_level = npc->GetLevel();
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
if (!scale_data.level) {
Log(
Logs::General,
Logs::NPCScaling,
"NpcScaleManager::ApplyGlobalBaseScalingToNPCStatically NPC: %s - scaling data not found for type: %i level: %i",
npc->GetCleanName(),
npc_type,
npc_level
);
return false;
}
std::string query = StringFormat(
"UPDATE `npc_types` SET "
"AC = %i, "
"hp = %i, "
"Accuracy = %i, "
"slow_mitigation = %i, "
"ATK = %i, "
"STR = %i, "
"STA = %i, "
"DEX = %i, "
"AGI = %i, "
"_INT = %i, "
"WIS = %i, "
"CHA = %i, "
"MR = %i, "
"CR = %i, "
"FR = %i, "
"PR = %i, "
"DR = %i, "
"Corrup = %i, "
"PhR = %i, "
"mindmg = %i, "
"maxdmg = %i, "
"hp_regen_rate = %i, "
"attack_delay = %i, "
"spellscale = %i, "
"healscale = %i, "
"special_abilities = '%s' "
"WHERE `id` = %i",
scale_data.ac,
scale_data.hp,
scale_data.accuracy,
scale_data.slow_mitigation,
scale_data.attack,
scale_data.strength,
scale_data.stamina,
scale_data.dexterity,
scale_data.agility,
scale_data.intelligence,
scale_data.wisdom,
scale_data.charisma,
scale_data.magic_resist,
scale_data.cold_resist,
scale_data.fire_resist,
scale_data.poison_resist,
scale_data.disease_resist,
scale_data.corruption_resist,
scale_data.physical_resist,
scale_data.min_dmg,
scale_data.max_dmg,
scale_data.hp_regen_rate,
scale_data.attack_delay,
scale_data.spell_scale,
scale_data.heal_scale,
EscapeString(scale_data.special_abilities).c_str(),
npc->GetNPCTypeID()
);
auto results = database.QueryDatabase(query);
return results.Success();
}
/**
* Returns false if scaling data not found
* @param npc
* @return
*/
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically(NPC *&npc)
{
int8 npc_type = GetNPCScalingType(npc);
int npc_level = npc->GetLevel();
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
if (!scale_data.level) {
Log(
Logs::General,
Logs::NPCScaling,
"NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically NPC: %s - scaling data not found for type: %i level: %i",
npc->GetCleanName(),
npc_type,
npc_level
);
return false;
}
std::string query = StringFormat(
"UPDATE `npc_types` SET "
"AC = 0, "
"hp = 0, "
"Accuracy = 0, "
"slow_mitigation = 0, "
"ATK = 0, "
"STR = 0, "
"STA = 0, "
"DEX = 0, "
"AGI = 0, "
"_INT = 0, "
"WIS = 0, "
"CHA = 0, "
"MR = 0, "
"CR = 0, "
"FR = 0, "
"PR = 0, "
"DR = 0, "
"Corrup = 0, "
"PhR = 0, "
"mindmg = 0, "
"maxdmg = 0, "
"hp_regen_rate = 0, "
"attack_delay = 0, "
"spellscale = 0, "
"healscale = 0, "
"special_abilities = '' "
"WHERE `id` = %i",
npc->GetNPCTypeID()
);
auto results = database.QueryDatabase(query);
return results.Success();
}
+107
View File
@@ -0,0 +1,107 @@
/**
* 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;
int spell_scale;
int heal_scale;
std::string special_abilities;
};
std::vector<std::string> scaling_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",
"spell_scale",
"heal_scale",
"special_abilities"
};
void ScaleNPC(NPC * npc);
bool IsAutoScaled(NPC * npc);
bool LoadScaleData();
global_npc_scale GetGlobalScaleDataForTypeLevel(int8 npc_type, int npc_level);
std::map<std::pair<int, int>, global_npc_scale> npc_global_base_scaling_data;
int8 GetNPCScalingType(NPC * &npc);
std::string GetNPCScalingTypeName(NPC * &npc);
bool ApplyGlobalBaseScalingToNPCStatically(NPC * &npc);
bool ApplyGlobalBaseScalingToNPCDynamically(NPC * &npc);
uint32 GetClassLevelDamageMod(uint32 level, uint32 npc_class);
};
extern NpcScaleManager *npc_scale_manager;
#endif //EQEMU_NPC_SCALE_MANAGER_H
+14 -14
View File
@@ -179,20 +179,20 @@ protected:
void ResetState(); // Set state back to original
void RandomSpawn(bool send_packet = false); //spawn this ground spawn at a random place
Object_Struct m_data; // Packet data
EQEmu::ItemInstance* m_inst; // Item representing object
bool m_inuse; // Currently in use by a client?
uint32 m_id; // Database key, different than drop_id
uint32 m_type; // Object Type, ie, forge, oven, dropped item, etc (ref: ContainerUseTypes)
uint32 m_icon; // Icon to use for forge, oven, etc
float m_max_x;
float m_max_y;
float m_min_x;
float m_min_y;
float m_z;
float m_heading;
bool m_ground_spawn;
char m_display_name[64];
Object_Struct m_data; // Packet data
EQEmu::ItemInstance *m_inst; // Item representing object
bool m_inuse; // Currently in use by a client?
uint32 m_id; // Database key, different than drop_id
uint32 m_type; // Object Type, ie, forge, oven, dropped item, etc (ref: ContainerUseTypes)
uint32 m_icon; // Icon to use for forge, oven, etc
float m_max_x;
float m_max_y;
float m_min_x;
float m_min_y;
float m_z;
float m_heading;
bool m_ground_spawn;
char m_display_name[64];
std::map<std::string, std::string> o_EntityVariables;
+64 -68
View File
@@ -976,37 +976,44 @@ void QuestManager::permagender(int gender_id) {
uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
QuestManagerCurrentQuestVars();
uint16 book_slot, count;
uint16 curspell;
uint16 spell_id;
uint32 Char_ID = initiator->CharacterID();
uint32 char_id = initiator->CharacterID();
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
bool SpellGlobalCheckResult = 0;
bool SpellBucketCheckResult = 0;
for(curspell = 0, book_slot = initiator->GetNextAvailableSpellBookSlot(), count = 0; curspell < SPDAT_RECORDS && book_slot < MAX_PP_SPELLBOOK; curspell++, book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot))
for(spell_id = 0, book_slot = initiator->GetNextAvailableSpellBookSlot(), count = 0; spell_id < SPDAT_RECORDS && book_slot < MAX_PP_SPELLBOOK; spell_id++, book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot))
{
if
(
spells[curspell].classes[WARRIOR] != 0 && //check if spell exists
spells[curspell].classes[initiator->GetPP().class_-1] <= max_level && //maximum level
spells[curspell].classes[initiator->GetPP().class_-1] >= min_level && //minimum level
spells[curspell].skill != 52 &&
spells[curspell].effectid[EFFECT_COUNT - 1] != 10
spells[spell_id].classes[WARRIOR] != 0 && //check if spell exists
spells[spell_id].classes[initiator->GetPP().class_-1] <= max_level && //maximum level
spells[spell_id].classes[initiator->GetPP().class_-1] >= min_level && //minimum level
spells[spell_id].skill != 52 &&
spells[spell_id].effectid[EFFECT_COUNT - 1] != 10
)
{
if (book_slot == -1) //no more book slots
break;
if(!IsDiscipline(curspell) && !initiator->HasSpellScribed(curspell)) { //isn't a discipline & we don't already have it scribed
if(!IsDiscipline(spell_id) && !initiator->HasSpellScribed(spell_id)) { //isn't a discipline & we don't already have it scribed
if (SpellGlobalRule) {
// Bool to see if the character has the required QGlobal to scribe it if one exists in the Spell_Globals table
SpellGlobalCheckResult = initiator->SpellGlobalCheck(curspell, Char_ID);
SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id, char_id);
if (SpellGlobalCheckResult) {
initiator->ScribeSpell(curspell, book_slot);
initiator->ScribeSpell(spell_id, book_slot);
count++;
}
}
else {
initiator->ScribeSpell(curspell, book_slot);
} else if (SpellBucketRule) {
SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id, char_id);
if (SpellBucketCheckResult) {
initiator->ScribeSpell(spell_id, book_slot);
count++;
}
} else {
initiator->ScribeSpell(spell_id, book_slot);
count++;
}
}
@@ -1018,46 +1025,59 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
QuestManagerCurrentQuestVars();
uint16 count;
uint16 curspell;
uint16 spell_id;
uint32 Char_ID = initiator->CharacterID();
uint32 char_id = initiator->CharacterID();
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
bool SpellGlobalCheckResult = 0;
bool SpellBucketCheckResult = 0;
for(curspell = 0, count = 0; curspell < SPDAT_RECORDS; curspell++)
for(spell_id = 0, count = 0; spell_id < SPDAT_RECORDS; spell_id++)
{
if
(
spells[curspell].classes[WARRIOR] != 0 && //check if spell exists
spells[curspell].classes[initiator->GetPP().class_-1] <= max_level && //maximum level
spells[curspell].classes[initiator->GetPP().class_-1] >= min_level && //minimum level
spells[curspell].skill != 52 &&
( !RuleB(Spells, UseCHAScribeHack) || spells[curspell].effectid[EFFECT_COUNT - 1] != 10 )
spells[spell_id].classes[WARRIOR] != 0 && //check if spell exists
spells[spell_id].classes[initiator->GetPP().class_-1] <= max_level && //maximum level
spells[spell_id].classes[initiator->GetPP().class_-1] >= min_level && //minimum level
spells[spell_id].skill != 52 &&
( !RuleB(Spells, UseCHAScribeHack) || spells[spell_id].effectid[EFFECT_COUNT - 1] != 10 )
)
{
if(IsDiscipline(curspell)){
if(IsDiscipline(spell_id)){
//we may want to come up with a function like Client::GetNextAvailableSpellBookSlot() to help speed this up a little
for(uint32 r = 0; r < MAX_PP_DISCIPLINES; r++) {
if(initiator->GetPP().disciplines.values[r] == curspell) {
if(initiator->GetPP().disciplines.values[r] == spell_id) {
initiator->Message(13, "You already know this discipline.");
break; //continue the 1st loop
}
else if(initiator->GetPP().disciplines.values[r] == 0) {
if (SpellGlobalRule) {
// Bool to see if the character has the required QGlobal to train it if one exists in the Spell_Globals table
SpellGlobalCheckResult = initiator->SpellGlobalCheck(curspell, Char_ID);
SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id, char_id);
if (SpellGlobalCheckResult) {
initiator->GetPP().disciplines.values[r] = curspell;
database.SaveCharacterDisc(Char_ID, r, curspell);
initiator->GetPP().disciplines.values[r] = spell_id;
database.SaveCharacterDisc(char_id, r, spell_id);
initiator->SendDisciplineUpdate();
initiator->Message(0, "You have learned a new discipline!");
count++; //success counter
}
break; //continue the 1st loop
} else if (SpellBucketRule) {
// Bool to see if the character has the required bucket to train it if one exists in the spell_buckets table
SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id, char_id);
if (SpellBucketCheckResult) {
initiator->GetPP().disciplines.values[r] = spell_id;
database.SaveCharacterDisc(char_id, r, spell_id);
initiator->SendDisciplineUpdate();
initiator->Message(0, "You have learned a new discipline!");
count++;
}
break;
}
else {
initiator->GetPP().disciplines.values[r] = curspell;
database.SaveCharacterDisc(Char_ID, r, curspell);
initiator->GetPP().disciplines.values[r] = spell_id;
database.SaveCharacterDisc(char_id, r, spell_id);
initiator->SendDisciplineUpdate();
initiator->Message(0, "You have learned a new discipline!");
count++; //success counter
@@ -2661,6 +2681,10 @@ uint16 QuestManager::GetInstanceID(const char *zone, int16 version)
return 0;
}
uint16 QuestManager::GetInstanceIDByCharID(const char *zone, int16 version, uint32 char_id) {
return database.GetInstanceID(zone, char_id, version);
}
void QuestManager::AssignToInstance(uint16 instance_id)
{
QuestManagerCurrentQuestVars();
@@ -2670,6 +2694,10 @@ void QuestManager::AssignToInstance(uint16 instance_id)
}
}
void QuestManager::AssignToInstanceByCharID(uint16 instance_id, uint32 char_id) {
database.AddClientToInstance(instance_id, char_id);
}
void QuestManager::AssignGroupToInstance(uint16 instance_id)
{
QuestManagerCurrentQuestVars();
@@ -2710,6 +2738,10 @@ void QuestManager::RemoveFromInstance(uint16 instance_id)
}
}
void QuestManager::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id) {
database.RemoveClientFromInstance(instance_id, char_id);
}
void QuestManager::RemoveAllFromInstance(uint16 instance_id)
{
QuestManagerCurrentQuestVars();
@@ -2761,47 +2793,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) {
+4 -1
View File
@@ -234,10 +234,13 @@ public:
uint32 GetInstanceTimerByID(uint16 instance_id = 0);
void DestroyInstance(uint16 instance_id);
uint16 GetInstanceID(const char *zone, int16 version);
uint16 GetInstanceIDByCharID(const char *zone, int16 version, uint32 char_id);
void AssignToInstance(uint16 instance_id);
void AssignToInstanceByCharID(uint16 instance_id, uint32 char_id);
void AssignGroupToInstance(uint16 instance_id);
void AssignRaidToInstance(uint16 instance_id);
void RemoveFromInstance(uint16 instance_id);
void RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id);
//void RemoveGroupFromInstance(uint16 instance_id); //potentially useful but not implmented at this time.
//void RemoveRaidFromInstance(uint16 instance_id); //potentially useful but not implmented at this time.
void RemoveAllFromInstance(uint16 instance_id);
@@ -245,7 +248,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();
+65 -23
View File
@@ -3021,6 +3021,10 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
if(effect1 != effect2)
continue;
if (IsBardOnlyStackEffect(effect1) && GetSpellLevel(spellid1, BARD) != 255 &&
GetSpellLevel(spellid2, BARD) != 255)
continue;
// big ol' list according to the client, wasn't that nice!
if (IsEffectIgnoredInStacking(effect1))
continue;
@@ -5154,14 +5158,11 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
return -1; //default
}
bool Client::SpellGlobalCheck(uint16 spell_ID, uint32 char_ID) {
std::string spell_Global_Name;
int spell_Global_Value;
int global_Value;
std::string query = StringFormat("SELECT qglobal, value FROM spell_globals "
"WHERE spellid = %i", spell_ID);
bool Client::SpellGlobalCheck(uint16 spell_id, uint32 char_id) {
std::string spell_global_name;
int spell_global_value;
int global_value;
std::string query = StringFormat("SELECT qglobal, value FROM spell_globals WHERE spellid = %i", spell_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
return false; // Query failed, so prevent spell from scribing just in case
@@ -5171,37 +5172,79 @@ bool Client::SpellGlobalCheck(uint16 spell_ID, uint32 char_ID) {
return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing
auto row = results.begin();
spell_Global_Name = row[0];
spell_Global_Value = atoi(row[1]);
spell_global_name = row[0];
spell_global_value = atoi(row[1]);
if (spell_Global_Name.empty())
if (spell_global_name.empty())
return true; // If the entry in the spell_globals table has nothing set for the qglobal name
query = StringFormat("SELECT value FROM quest_globals "
"WHERE charid = %i AND name = '%s'",
char_ID, spell_Global_Name.c_str());
char_id, spell_global_name.c_str());
results = database.QueryDatabase(query);
if (!results.Success()) {
Log(Logs::General, Logs::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_ID, spell_Global_Name.c_str(), spell_Global_Value);
Log(Logs::General, Logs::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_id, spell_global_name.c_str(), spell_global_value);
return false;
}
if (results.RowCount() != 1) {
Log(Logs::General, Logs::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_ID);
Log(Logs::General, Logs::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_id, spell_global_name.c_str(), spell_id);
return false;
}
row = results.begin();
global_value = atoi(row[0]);
if (global_value == spell_global_value)
return true; // If the values match from both tables, allow the spell to be scribed
else if (global_value > spell_global_value)
return true; // Check if the qglobal value is greater than the require spellglobal value
// If no matching result found in qglobals, don't scribe this spell
Log(Logs::General, Logs::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_id, spell_global_name.c_str(), spell_global_value, global_value, spell_id);
return false;
}
bool Client::SpellBucketCheck(uint16 spell_id, uint32 char_id) {
std::string spell_bucket_name;
int spell_bucket_value;
int bucket_value;
std::string query = StringFormat("SELECT key, value FROM spell_buckets WHERE spellid = %i", spell_id);
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
if (results.RowCount() != 1)
return true;
auto row = results.begin();
spell_bucket_name = row[0];
spell_bucket_value = atoi(row[1]);
if (spell_bucket_name.empty())
return true;
query = StringFormat("SELECT value FROM data_buckets WHERE key = '%i-%s'", char_id, spell_bucket_name.c_str());
results = database.QueryDatabase(query);
if (!results.Success()) {
Log(Logs::General, Logs::Error, "Spell bucket %s for spell ID %i for char ID %i failed.", spell_bucket_name.c_str(), spell_id, char_id);
return false;
}
if (results.RowCount() != 1) {
Log(Logs::General, Logs::Error, "Spell bucket %s does not exist for spell ID %i for char ID %i.", spell_bucket_name.c_str(), spell_id, char_id);
return false;
}
row = results.begin();
global_Value = atoi(row[0]);
bucket_value = atoi(row[0]);
if (global_Value == spell_Global_Value)
if (bucket_value == spell_bucket_value)
return true; // If the values match from both tables, allow the spell to be scribed
else if (global_Value > spell_Global_Value)
return true; // Check if the qglobal value is greater than the require spellglobal value
else if (bucket_value > spell_bucket_value)
return true; // Check if the data bucket value is greater than the required spell bucket value
// If no matching result found in qglobals, don't scribe this spell
Log(Logs::General, Logs::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_Global_Value, global_Value, spell_ID);
// If no matching result found in spell buckets, don't scribe this spell
Log(Logs::General, Logs::Error, "Spell bucket %s for spell ID %i for char ID %i did not match value %i.", spell_bucket_name.c_str(), spell_id, char_id, spell_bucket_value);
return false;
}
@@ -5644,9 +5687,8 @@ void NPC::InitializeBuffSlots()
{
int max_slots = GetMaxTotalSlots();
buffs = new Buffs_Struct[max_slots];
for(int x = 0; x < max_slots; ++x)
{
buffs[x].spellid = SPELL_UNKNOWN;
for (int x = 0; x < max_slots; ++x) {
buffs[x].spellid = SPELL_UNKNOWN;
buffs[x].UpdateClient = false;
}
current_buff_count = 0;
+1 -1
View File
@@ -2637,7 +2637,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
temp_npctype_data->spellscale = atoi(row[86]);
temp_npctype_data->healscale = atoi(row[87]);
temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false: true;
temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false : true;
temp_npctype_data->attack_delay = atoi(row[90]) * 100; // TODO: fix DB
temp_npctype_data->light = (atoi(row[91]) & 0x0F);