Merge aeb13b285f786add5cf21f2911e27a52a1293958 into a1adda36fac591fe507ba5016cc51caf205c8ed9

This commit is contained in:
Alex 2014-06-11 03:51:12 +00:00
commit d6e07ef252
40 changed files with 299 additions and 24755 deletions

View File

@ -584,11 +584,7 @@ bool Database::DeleteCharacter(char *name)
#if DEBUG >= 5
printf(" guild_members");
#endif
#ifdef BOTS
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM guild_members WHERE char_id='%d' AND GetMobTypeById(%i) = 'C'", charid), errbuf, nullptr, &affected_rows);
#else
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM guild_members WHERE char_id='%d'", charid), errbuf, nullptr, &affected_rows);
#endif
if(query)
{
safe_delete_array(query);

View File

@ -938,20 +938,12 @@ bool BaseGuildManager::_RunQuery(char *&query, int len, const char *errmsg) {
return(true);
}
//factored out so I dont have to copy this crap.
#ifdef BOTS
#define GuildMemberBaseQuery \
"SELECT c.id,c.name,c.class,c.level,c.timelaston,c.zoneid," \
" g.guild_id,g.rank,g.tribute_enable,g.total_tribute,g.last_tribute," \
" g.banker,g.public_note,g.alt" \
" FROM vwBotCharacterMobs AS c LEFT JOIN vwGuildMembers AS g ON c.id=g.char_id AND c.mobtype = g.mobtype "
#else
#define GuildMemberBaseQuery \
"SELECT c.id,c.name,c.class,c.level,c.timelaston,c.zoneid," \
" g.guild_id,g.rank,g.tribute_enable,g.total_tribute,g.last_tribute," \
" g.banker,g.public_note,g.alt " \
" FROM character_ AS c LEFT JOIN guild_members AS g ON c.id=g.char_id "
#endif
"SELECT c.id,c.name,c.class,c.level,c.timelaston,c.zoneid," \
" g.guild_id,g.rank,g.tribute_enable,g.total_tribute,g.last_tribute," \
" g.banker,g.public_note,g.alt " \
" FROM character_ AS c LEFT JOIN guild_members AS g ON c.id=g.char_id "
static void ProcessGuildMember(MYSQL_ROW &row, CharGuildInfo &into) {
//fields from `characer_`
into.char_id = atoi(row[0]);
@ -1066,13 +1058,7 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
MYSQL_ROW row;
//load up the rank info for each guild.
if (!m_db->RunQuery(query, MakeAnyLenString(&query,
#ifdef BOTS
GuildMemberBaseQuery " WHERE c.id=%d AND c.mobtype = 'C'", char_id
#else
GuildMemberBaseQuery " WHERE c.id=%d", char_id
#endif
), errbuf, &result)) {
if (!m_db->RunQuery(query, MakeAnyLenString(&query, GuildMemberBaseQuery " WHERE c.id=%d", char_id), errbuf, &result)) {
_log(GUILDS__ERROR, "Error loading guild member '%s': %s", query, errbuf);
safe_delete_array(query);
return(false);

View File

@ -443,22 +443,6 @@ RULE_BOOL ( TaskSystem, KeepOneRecordPerCompletedTask, true)
RULE_BOOL ( TaskSystem, EnableTaskProximity, true)
RULE_CATEGORY_END()
#ifdef BOTS
RULE_CATEGORY ( Bots )
RULE_REAL ( Bots, BotManaRegen, 2.0 ) // Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players.
RULE_BOOL ( Bots, BotFinishBuffing, false ) // Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat.
RULE_INT ( Bots, CreateBotCount, 150 ) // Number of bots that each account can create
RULE_INT ( Bots, SpawnBotCount, 71 ) // Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid
RULE_BOOL ( Bots, BotQuest, false ) // Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl
RULE_BOOL ( Bots, BotGroupBuffing, false ) // Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB.
RULE_BOOL ( Bots, BotSpellQuest, false ) // Anita Thrall's (Anita_Thrall.pl) Bot Spell Scriber quests.
RULE_INT ( Bots, BotAAExpansion, 8 ) // Bots get AAs through this expansion
RULE_BOOL ( Bots, BotGroupXP, false ) // Determines whether client gets xp for bots outside their group.
RULE_BOOL ( Bots, BotBardUseOutOfCombatSongs, true) // Determines whether bard bots use additional out of combat songs.
RULE_BOOL ( Bots, BotLevelsWithOwner, false) // Auto-updates spawned bots as owner levels/de-levels (false is original behavior)
RULE_CATEGORY_END()
#endif
RULE_CATEGORY ( Chat )
RULE_BOOL ( Chat, ServerWideOOC, true)
RULE_BOOL ( Chat, ServerWideAuction, true)

View File

@ -6,8 +6,6 @@ SET(zone_sources
attack.cpp
beacon.cpp
bonuses.cpp
bot.cpp
botspellsai.cpp
client.cpp
client_logs.cpp
client_mods.cpp
@ -124,10 +122,7 @@ SET(zone_sources
SET(zone_headers
AA.h
basic_functions.h
beacon.h
bot.h
botStructs.h
client.h
client_logs.h
client_packet.h
@ -169,8 +164,6 @@ SET(zone_headers
lua_spell.h
map.h
masterentity.h
maxskill.h
message.h
merc.h
mob.h
net.h
@ -189,7 +182,6 @@ SET(zone_headers
raid.h
raids.h
RaycastMesh.h
skills.h
spawn2.cpp
spawn2.h
spawngroup.h

View File

@ -491,7 +491,7 @@ void Mob::AI_Start(uint32 iMoveDelay) {
pAggroRange = 70;
if (GetAssistRange() == 0)
pAssistRange = 70;
hate_list.Wipe();
hate_list.clear();
delta_heading = 0;
delta_x = 0;
@ -548,7 +548,7 @@ void Mob::AI_Stop() {
safe_delete(AItarget_check_timer)
safe_delete(AIscanarea_timer);
safe_delete(AIfeignremember_timer);
hate_list.Wipe();
hate_list.clear();
}
void NPC::AI_Stop() {
@ -784,12 +784,12 @@ void Client::AI_Process()
if (engaged)
{
if (IsRooted())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.getClosest(this));
else
{
if(AItarget_check_timer->Check())
{
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.getHighestHate(this));
}
}
@ -1057,18 +1057,18 @@ void Mob::AI_Process() {
if (engaged)
{
if (IsRooted())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.getClosest(this));
else
{
if(AItarget_check_timer->Check())
{
if (IsFocused()) {
if (!target) {
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.getHighestHate(this));
}
} else {
if (!ImprovedTaunt())
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.getHighestHate(this));
}
}
@ -1083,15 +1083,6 @@ void Mob::AI_Process() {
return;
}
#ifdef BOTS
if (IsPet() && GetOwner()->IsBot() && target == GetOwner())
{
// this blocks all pet attacks against owner..bot pet test (copied above check)
RemoveFromHateList(this);
return;
}
#endif //BOTS
if(DivineAura())
return;
@ -1343,7 +1334,7 @@ void Mob::AI_Process() {
//underwater stuff only works with water maps in the zone!
if(IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(target->GetX(), target->GetY(), target->GetZ())) {
Mob *tar = hate_list.GetTop(this);
Mob *tar = hate_list.getHighestHate(this);
if(tar == target) {
WipeHateList();
Heal();

View File

@ -677,14 +677,6 @@ type', in which case, the answer is yes.
}
}
#ifdef BOTS
bool HasRuleDefined = false;
bool IsBotAttackAllowed = false;
IsBotAttackAllowed = Bot::IsBotAttackAllowed(mob1, mob2, HasRuleDefined);
if(HasRuleDefined)
return IsBotAttackAllowed;
#endif //BOTS
// we fell through, now we swap the 2 mobs and run through again once more
tempmob = mob1;
mob1 = mob2;
@ -763,10 +755,6 @@ bool Mob::IsBeneficialAllowed(Mob *target)
{
return false;
}
#ifdef BOTS
else if(mob2->IsBot())
return true;
#endif
}
else if(_NPC(mob1))
{

View File

@ -1553,7 +1553,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
}
entity_list.RemoveFromTargets(this);
hate_list.RemoveEnt(this);
hate_list.clear(this);
RemoveAutoXTargets();
@ -2142,12 +2142,12 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
if (killerMob) {
if(GetClass() != LDON_TREASURE)
hate_list.Add(killerMob, damage);
hate_list.add(killerMob, damage);
}
safe_delete(app);
Mob *give_exp = hate_list.GetDamageTop(this);
Mob *give_exp = hate_list.getHighestDamage(this);
if(give_exp == nullptr)
give_exp = killer;
@ -2161,12 +2161,6 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
ownerInGroup = true;
give_exp = give_exp->GetUltimateOwner();
#ifdef BOTS
if(!RuleB(Bots, BotGroupXP) && !ownerInGroup) {
give_exp = nullptr;
}
#endif //BOTS
}
int PlayerCount = 0; // QueryServ Player Counting
@ -2532,33 +2526,19 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
&& other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID()))
hate = (hate*spellbonuses.ImprovedTaunt[1])/100;
hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic);
hate_list.add(other, hate, damage, bFrenzy, !iBuffTic);
if(other->IsClient())
other->CastToClient()->AddAutoXTarget(this);
#ifdef BOTS
// if other is a bot, add the bots client to the hate list
if(other->IsBot()) {
if(other->CastToBot()->GetBotOwner() && other->CastToBot()->GetBotOwner()->CastToClient()->GetFeigned()) {
AddFeignMemory(other->CastToBot()->GetBotOwner()->CastToClient());
}
else {
if(!hate_list.IsOnHateList(other->CastToBot()->GetBotOwner()))
hate_list.Add(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
}
}
#endif //BOTS
// if other is a merc, add the merc client to the hate list
if(other->IsMerc()) {
if(other->CastToMerc()->GetMercOwner() && other->CastToMerc()->GetMercOwner()->CastToClient()->GetFeigned()) {
AddFeignMemory(other->CastToMerc()->GetMercOwner()->CastToClient());
}
else {
if(!hate_list.IsOnHateList(other->CastToMerc()->GetMercOwner()))
hate_list.Add(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
if(!hate_list.isHated(other->CastToMerc()->GetMercOwner()))
hate_list.add(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
}
} //MERC
@ -2573,7 +2553,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
// owner must get on list, but he's not actually gained any hate yet
if(!owner->GetSpecialAbility(IMMUNE_AGGRO))
{
hate_list.Add(owner, 0, 0, false, !iBuffTic);
hate_list.add(owner, 0, 0, false, !iBuffTic);
if(owner->IsClient())
owner->CastToClient()->AddAutoXTarget(this);
}
@ -2582,10 +2562,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it
if(!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
mypet->hate_list.Add(other, 0, 0, bFrenzy);
mypet->hate_list.add(other, 0, 0, bFrenzy);
} else if (myowner) { // I am a pet, add other to owner if it's NPC/LD
if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO))
myowner->hate_list.Add(other, 0, 0, bFrenzy);
myowner->hate_list.add(other, 0, 0, bFrenzy);
}
if (!wasengaged) {
if(IsNPC() && other->IsClient() && other->CastToClient())
@ -4274,14 +4254,6 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack
return;
}
#ifdef BOTS
if (this->IsPet() && this->GetOwner()->IsBot()) {
this->TryPetCriticalHit(defender,skill,damage);
return;
}
#endif //BOTS
float critChance = 0.0f;
//1: Try Slay Undead

View File

@ -1,178 +0,0 @@
const char *notin = "~.? ,)=!&|<>\"";
const char * charIn = "`~1234567890-=!@#$%^&*()_+qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP|ASDFGHJKL:ZXCVBNM<>?\"{}";
const char * charIn2 = "`~1234567890-=!@#$%^&*()_+qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP|ASDFGHJKL:ZXCVBNM<>?\" ";
char com_list[512];
/*char * gettok(const char * string, int chara, int pos) {
static char * pch;
static char temp[100];
static char ty[100];
memset(temp, 0, sizeof(temp));
memset(ty, 0, sizeof(ty));
ty[0] = chara;
strn0cpy(temp, string, sizeof(temp));
pch = strtok(temp,ty);
for (int i=0; i < pos; i++) {
if (pos == i) break;
pch = strtok(nullptr,ty);
}
return pch;
}*/
int calc(char * stuff) {
int result = 0;
int i = 0;
int a = 0;
static char temp[100];
int op = 0;
memset(temp,0x0,100);
//char heh[100];
while(*stuff)
{
a++;
if (*stuff >= '0' && *stuff <= '9') {
if (op) {
switch ( op ) {
case 0:
break;
case '+':
result += atoi(stuff);
memset(temp,0x0,100);
i = 0;
break;
case '-':
result -= atoi(stuff);
memset(temp,0x0,100);
i = 0;
break;
case '*':
result *= atoi(stuff);
memset(temp,0x0,100);
i = 0;
break;
case '/':
result /= atoi(stuff);
memset(temp,0x0,100);
i = 0;
break;
}
}
temp[i] = *stuff;
}
else if (*stuff == '+' || *stuff == '-' || *stuff == '/' || *stuff == '*') {
op = *stuff;
if (!result) result = atoi(temp);
memset(temp,0x0,100);
i=0;
}
i++;
stuff++;
}
return result;
}
char * postring (char * string, int pos) {
static char temp[1024];
memset(temp, 0, sizeof(temp));
int p=0;
int tmpStringLen = strlen(string);
for (int i=pos; i < tmpStringLen; i++) {
temp[p] = string[i];
p++;
}
return temp;
}
int g_id ( char * string )
{
char temp[100];
int i=0;
while (*string)
{
if (*string >= '0' && *string <= '9') temp[i++] = *string++;
else string++;
}
return atoi(temp);
}
int GetArgs(char * string)
{
#if 1
char temp[255];
char c_name[255];
int params = 0;
//char *buffer = new char[512]; // this is never deleted, causes zone to crash
char *buffer = com_list;
memset(temp,0x0,255);
//memset(buffer,0x0,512);
//#ifdef WIN32
//strcpy(buffer,com_list);
//#else
//strncpy(buffer,com_list,sizeof(buffer)-1);
//#endif
int i=0;
while (*buffer)
{
if (*buffer != '|' && *buffer != ' ') temp[i++] = *buffer++;
else buffer++;
if (*buffer == '|') {
params = atoi(temp);
if (!strcmp(c_name,string)) {
return params;
}
memset(temp,0x0,255);
i=0;
}
if (*buffer == ' ') {
memset(c_name,0x0,255);
strcpy(c_name,temp);
memset(temp,0x0,255);
i=0;
}
}
return 0;
#else
if (strstr(string,"if")) { return 0; }
if (strstr(string,"sfollow")) { return 0; }
if (strstr(string,"save")) { return 0; }
if (strstr(string,"while")) { return 0; }
if (strstr(string,"break")) { return 1; }
if (strstr(string,"follow")) { return 1; }
if (strstr(string,"setallskill")) { return 1; }
if (strstr(string,"me")) { return 1; }
if (strstr(string,"flagcheck")) { return 1; }
if (strstr(string,"echo")) { return 1; }
if (strstr(string,"summonitem")) { return 1; }
if (strstr(string,"say")) { return 1; }
if (strstr(string,"emote")) { return 1; }
if (strstr(string,"shout")) { return 1; }
if (strstr(string,"depop")) { return 1; }
if (strstr(string,"cumflag")) { return 1; }
if (strstr(string,"exp")) { return 1; }
if (strstr(string,"level")) { return 1; }
if (strstr(string,"safemove")) { return 1; }
if (strstr(string,"rain")) { return 1; }
if (strstr(string,"snow")) { return 1; }
if (strstr(string,"pvp")) { return 1; }
if (strstr(string,"doanim")) { return 1; }
if (strstr(string,"dbspawnadd")) { return 2; }
if (strstr(string,"castspell")) { return 2; }
if (strstr(string,"flagcheck")) { return 2; }
if (strstr(string,"addskill")) { return 2; }
if (strstr(string,"write")) { return 2; }
if (strstr(string,"settarget")) { return 2; }
if (strstr(string,"givecash")) { return 4; }
if (strstr(string,"movepc")) { return 4; }
if (strstr(string,"spawn")) { return 6; }
return 0;
#endif // 0
}
Client* gClient = 0;
uint32 Line_Number = 0;

17174
zone/bot.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,690 +0,0 @@
#ifndef BOT_H
#define BOT_H
#ifdef BOTS
#include "botStructs.h"
#include "mob.h"
#include "client.h"
#include "pets.h"
#include "groups.h"
#include "corpse.h"
#include "zonedb.h"
#include "StringIDs.h"
#include "../common/MiscFunctions.h"
#include "../common/debug.h"
#include "guild_mgr.h"
#include "worldserver.h"
#include <sstream>
extern WorldServer worldserver;
const int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
const int MaxSpellTimer = 15;
const int MaxDisciplineTimer = 10;
const int DisciplineReuseStart = MaxSpellTimer + 1;
const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
const int MaxStances = 7;
const int MaxSpellTypes = 16;
const int MaxHealRotationMembers = 6;
const int MaxHealRotationTargets = 3;
enum BotStanceType {
BotStancePassive,
BotStanceBalanced,
BotStanceEfficient,
BotStanceReactive,
BotStanceAggressive,
BotStanceBurn,
BotStanceBurnAE
};
enum SpellTypeIndex {
SpellType_NukeIndex,
SpellType_HealIndex,
SpellType_RootIndex,
SpellType_BuffIndex,
SpellType_EscapeIndex,
SpellType_PetIndex,
SpellType_LifetapIndex,
SpellType_SnareIndex,
SpellType_DOTIndex,
SpellType_DispelIndex,
SpellType_InCombatBuffIndex,
SpellType_MezIndex,
SpellType_CharmIndex,
SpellType_SlowIndex,
SpellType_DebuffIndex,
SpellType_CureIndex
};
class Bot : public NPC {
public:
// Class enums
enum BotfocusType { //focus types
BotfocusSpellHaste = 1,
BotfocusSpellDuration,
BotfocusRange,
BotfocusReagentCost,
BotfocusManaCost,
BotfocusImprovedHeal,
BotfocusImprovedDamage,
BotfocusImprovedDOT, //i dont know about this...
BotfocusFcDamagePctCrit,
BotfocusImprovedUndeadDamage,
BotfocusPetPower,
BotfocusResistRate,
BotfocusSpellHateMod,
BotfocusTriggerOnCast,
BotfocusSpellVulnerability,
BotfocusTwincast,
BotfocusSympatheticProc,
BotfocusFcDamageAmt,
BotfocusFcDamageAmtCrit,
BotfocusSpellDurByTic,
BotfocusSwarmPetDuration,
BotfocusReduceRecastTime,
BotfocusBlockNextSpell,
BotfocusFcHealPctIncoming,
BotfocusFcDamageAmtIncoming,
BotfocusFcHealAmtIncoming,
BotfocusFcBaseEffects,
BotfocusIncreaseNumHits,
BotfocusFcHealPctCritIncoming,
BotfocusFcHealAmt,
BotfocusFcHealAmtCrit,
};
enum BotTradeType { // types of trades a bot can do
BotTradeClientNormal,
BotTradeClientNoDropNoTrade
};
enum BotRoleType {
BotRoleMainAssist,
BotRoleGroupHealer,
BotRoleRaidHealer
};
enum EqExpansions {
ExpansionNone,
ExpansionEQ,
ExpansionRoK,
ExpansionSoV,
ExpansionSoL,
ExpansionPoP,
ExpansionLoY,
ExpansionLDoN,
ExpansionGoD,
ExpansionOoW,
ExpansionDoN,
ExpansionDoDH,
ExpansionPoR,
ExpansionTSS,
ExpansionSoF,
ExpansionSoD,
ExpansionUF,
ExpansionHoT,
ExpansionVoA,
ExpansionRoF
};
// Class Constructors
Bot(NPCType npcTypeData, Client* botOwner);
Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType npcTypeData);
//abstract virtual function implementations requird by base abstract class
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill);
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false);
virtual bool Attack(Mob* other, int Hand = 13, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
ExtraAttackOptions *opts = nullptr);
virtual bool HasRaid() { return (GetRaid() ? true : false); }
virtual bool HasGroup() { return (GetGroup() ? true : false); }
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); }
virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); }
// Common, but informal "interfaces" with Client object
uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id
inline bool IsInAGuild() const { return (_guildId != GUILD_NONE && _guildId != 0); }
inline bool IsInGuild(uint32 in_gid) const { return (in_gid == _guildId && IsInAGuild()); }
inline uint32 GuildID() const { return _guildId; }
inline uint8 GuildRank() const { return _guildRank; }
// Class Methods
bool IsValidRaceClassCombo();
bool IsValidName();
bool IsBotNameAvailable(std::string* errorMessage);
bool DeleteBot(std::string* errorMessage);
void Spawn(Client* botCharacterOwner, std::string* errorMessage);
virtual void SetLevel(uint8 in_level, bool command = false);
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
virtual bool Process();
void FinishTrade(Client* client, BotTradeType tradeType);
virtual bool Save();
virtual void Depop();
void CalcBotStats(bool showtext = true);
uint16 BotGetSpells(int spellslot) { return AIspells[spellslot].spellid; }
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
virtual float GetProcChances(float ProcBonus, uint16 weapon_speed, uint16 hand);
virtual bool AvoidDamage(Mob* other, int32 &damage, bool CanRiposte);
virtual int GetMonkHandToHandDamage(void);
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
virtual void DoRiposte(Mob* defender);
inline virtual int16 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(SkillOffense)) * 9 / 10); }
inline virtual int16 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
uint16 GetTotalATK();
uint16 GetATKRating();
uint16 GetPrimarySkillValue();
uint16 MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const;
inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false);
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10);
virtual void RogueAssassinate(Mob* other);
virtual void DoClassAttacks(Mob *target, bool IsRiposte=false);
virtual bool TryHeadShot(Mob* defender, SkillUseTypes skillInUse);
virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false);
virtual void ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg);
bool CanDoSpecialAttack(Mob *other);
virtual int32 CheckAggroAmount(uint16 spellid);
virtual void CalcBonuses();
void CalcItemBonuses();
virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr);
virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther);
inline virtual bool IsPet() { return false; }
virtual bool IsNPC() const { return false; }
virtual Mob* GetOwner();
virtual Mob* GetOwnerOrSelf();
inline virtual bool HasOwner() { return (GetBotOwner() ? true : false); }
virtual int32 CheckHealAggroAmount(uint16 spellid, uint32 heal_possible = 0);
virtual int32 CalcMaxMana();
virtual void SetAttackTimer();
uint32 GetClassHPFactor();
virtual int32 CalcMaxHP();
bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
void Camp(bool databaseSave = true);
virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
virtual void SetTarget(Mob* mob);
virtual void Zone();
std::vector<AISpells_Struct> GetBotSpells() { return AIspells; }
bool IsArcheryRange(Mob* target);
void ChangeBotArcherWeapons(bool isArcher);
void Sit();
void Stand();
bool IsSitting();
bool IsStanding();
bool IsBotCasterCombatRange(Mob *target);
bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true) ;
bool UseDiscipline(uint32 spell_id, uint32 target);
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
bool GetNeedsCured(Mob *tar);
bool HasOrMayGetAggro();
void SetDefaultBotStance();
void CalcChanceToCast();
void CreateHealRotation( Mob* target, uint32 timer = 10000 );
bool AddHealRotationMember( Bot* healer );
bool RemoveHealRotationMember( Bot* healer );
bool AddHealRotationTarget( Mob* target );
//bool AddHealRotationTarget( const char *targetName, int index);
bool AddHealRotationTarget( Mob* target, int index);
bool RemoveHealRotationTarget( Mob* target );
bool RemoveHealRotationTarget( int index);
void NotifyNextHealRotationMember( bool notifyNow = false );
void ClearHealRotationLeader() { _healRotationLeader = 0; }
void ClearHealRotationMembers();
void ClearHealRotationTargets();
inline virtual int16 GetMaxStat();
inline virtual int16 GetMaxResist();
inline virtual int16 GetMaxSTR();
inline virtual int16 GetMaxSTA();
inline virtual int16 GetMaxDEX();
inline virtual int16 GetMaxAGI();
inline virtual int16 GetMaxINT();
inline virtual int16 GetMaxWIS();
inline virtual int16 GetMaxCHA();
inline virtual int16 GetMaxMR();
inline virtual int16 GetMaxPR();
inline virtual int16 GetMaxDR();
inline virtual int16 GetMaxCR();
inline virtual int16 GetMaxFR();
inline virtual int16 GetMaxCorrup();
int16 CalcATK();
int16 CalcSTR();
int16 CalcSTA();
int16 CalcDEX();
int16 CalcAGI();
int16 CalcINT();
int16 CalcWIS();
int16 CalcCHA();
int16 CalcMR();
int16 CalcFR();
int16 CalcDR();
int16 CalcPR();
int16 CalcCR();
int16 CalcCorrup();
int32 CalcHPRegenCap();
int32 CalcManaRegenCap();
int32 LevelRegen();
int32 CalcHPRegen();
int32 CalcManaRegen();
uint32 CalcCurrentWeight();
int GroupLeadershipAAHealthEnhancement();
int GroupLeadershipAAManaEnhancement();
int GroupLeadershipAAHealthRegeneration();
int GroupLeadershipAAOffenseEnhancement();
void CalcRestState();
int32 CalcMaxEndurance(); //This calculates the maximum endurance we can have
int32 CalcBaseEndurance(); //Calculates Base End
int32 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen()
int32 GetEndurance() const {return cur_end;} //This gets our current endurance
int32 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
int32 CalcEnduranceRegenCap();
inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); }
void SetEndurance(int32 newEnd); //This sets the current endurance to the new value
void DoEnduranceRegen(); //This Regenerates endurance
void DoEnduranceUpkeep(); //does the endurance upkeep
// AI Methods
virtual bool AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes);
virtual bool AI_EngagedCastCheck();
virtual bool AI_PursueCastCheck();
virtual bool AI_IdleCastCheck();
bool AIHealRotation(Mob* tar, bool useFastHeals);
// Mob AI Virtual Override Methods
virtual void AI_Process();
virtual void AI_Stop();
// Mob Spell Virtual Override Methods
virtual void SpellProcess();
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr);
virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr);
virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime);
virtual int32 GetActSpellCost(uint16 spell_id, int32 cost);
virtual float GetActSpellRange(uint16 spell_id, float range);
virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration);
virtual float GetAOERange(uint16 spell_id);
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0);
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr);
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction);
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF);
// Bot Action Command Methods
bool MesmerizeTarget(Mob* target);
bool Bot_Command_Resist(int resisttype, int level);
bool Bot_Command_DireTarget(int diretype, Mob *target);
bool Bot_Command_CharmTarget(int charmtype, Mob *target);
bool Bot_Command_CalmTarget(Mob *target);
bool Bot_Command_RezzTarget(Mob *target);
bool Bot_Command_Cure(int curetype, int level);
// Bot Equipment & Inventory Class Methods
void BotTradeSwapItem(Client* client, int16 lootSlot, const ItemInst* inst, const ItemInst* inst_swap, uint32 equipableSlots, std::string* errorMessage, bool swap = true);
void BotTradeAddItem(uint32 id, const ItemInst* inst, int16 charges, uint32 equipableSlots, uint16 lootSlot, std::string* errorMessage, bool addToDb = true);
void EquipBot(std::string* errorMessage);
bool CheckLoreConflict(const Item_Struct* item);
uint32 GetEquipmentColor(uint8 material_slot) const;
// Static Class Methods
static void SaveBotGroup(Group* botGroup, std::string botGroupName, std::string* errorMessage);
static void DeleteBotGroup(std::string botGroupName, std::string* errorMessage);
static std::list<BotGroup> LoadBotGroup(std::string botGroupName, std::string* errorMessage);
static uint32 CanLoadBotGroup(uint32 botOwnerCharacterId, std::string botGroupName, std::string* errorMessage);
static uint32 GetBotGroupIdByBotGroupName(std::string botGroupName, std::string* errorMessage);
static uint32 GetBotGroupLeaderIdByBotGroupName(std::string botGroupName);
static std::list<BotGroupList> GetBotGroupListByBotOwnerCharacterId(uint32 botOwnerCharacterId, std::string* errorMessage);
static bool DoesBotGroupNameExist(std::string botGroupName);
//static void DestroyBotRaidObjects(Client* client); // Can be removed after bot raids are dumped
static uint32 GetBotIDByBotName(std::string botName);
static Bot* LoadBot(uint32 botID, std::string* errorMessage);
static std::list<BotsAvailableList> GetBotList(uint32 botOwnerCharacterID, std::string* errorMessage);
static void ProcessBotCommands(Client *c, const Seperator *sep);
static std::list<SpawnedBotsList> ListSpawnedBots(uint32 characterID, std::string* errorMessage);
static uint32 SpawnedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage);
static uint32 CreatedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage);
static uint32 AllowedBotSpawns(uint32 botOwnerCharacterID, std::string* errorMessage);
static uint32 GetBotOwnerCharacterID(uint32 botID, std::string* errorMessage);
static void LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp);
//static bool SetBotOwnerCharacterID(uint32 botID, uint32 botOwnerCharacterID, std::string* errorMessage);
static std::string ClassIdToString(uint16 classId);
static std::string RaceIdToString(uint16 raceId);
static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined);
static void BotGroupOrderFollow(Group* group, Client* client);
static void BotGroupOrderGuard(Group* group, Client* client);
static void BotGroupOrderAttack(Group* group, Mob* target, Client* client);
static void BotGroupSummon(Group* group, Client* client);
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName);
static void ProcessBotGroupInvite(Client* c, std::string botName);
static void ProcessBotGroupDisband(Client* c, std::string botName);
static void BotOrderCampAll(Client* c);
static void BotHealRotationsClear( Client* c );
static void ProcessBotInspectionRequest(Bot* inspectedBot, Client* client);
static std::list<uint32> GetGroupedBotsByGroupId(uint32 groupId, std::string* errorMessage);
static void LoadAndSpawnAllZonedBots(Client* botOwner);
static bool GroupHasBot(Group* group);
static Bot* GetFirstBotInGroup(Group* group);
static void ProcessClientZoneChange(Client* botOwner);
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
static void ProcessGuildInvite(Client* guildOfficer, Bot* botToGuild); // Processes a client's request to guild a bot
static bool ProcessGuildRemoval(Client* guildOfficer, std::string botName); // Processes a client's request to deguild a bot
static int32 GetSpellRecastTimer(Bot *caster, int timer_index);
static bool CheckSpellRecastTimers(Bot *caster, int SpellIndex);
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
static std::list<BotSpell> GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect);
static std::list<BotSpell> GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType);
static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint16 spellType);
static BotSpell GetFirstBotSpellBySpellType(Bot* botCaster, uint16 spellType);
static BotSpell GetBestBotSpellForFastHeal(Bot* botCaster);
static BotSpell GetBestBotSpellForHealOverTime(Bot* botCaster);
static BotSpell GetBestBotSpellForPercentageHeal(Bot* botCaster);
static BotSpell GetBestBotSpellForRegularSingleTargetHeal(Bot* botCaster);
static BotSpell GetFirstBotSpellForSingleTargetHeal(Bot* botCaster);
static BotSpell GetBestBotSpellForGroupHealOverTime(Bot* botCaster);
static BotSpell GetBestBotSpellForGroupCompleteHeal(Bot* botCaster);
static BotSpell GetBestBotSpellForGroupHeal(Bot* botCaster);
static BotSpell GetBestBotSpellForMagicBasedSlow(Bot* botCaster);
static BotSpell GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster);
static Mob* GetFirstIncomingMobToMez(Bot* botCaster, BotSpell botSpell);
static BotSpell GetBestBotSpellForMez(Bot* botCaster);
static BotSpell GetBestBotMagicianPetSpell(Bot* botCaster);
static std::string GetBotMagicianPetType(Bot* botCaster);
static BotSpell GetBestBotSpellForNukeByTargetType(Bot* botCaster, SpellTargetType targetType);
static BotSpell GetBestBotSpellForStunByTargetType(Bot* botCaster, SpellTargetType targetType);
static BotSpell GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* target);
static BotSpell GetDebuffBotSpell(Bot* botCaster, Mob* target);
static BotSpell GetBestBotSpellForCure(Bot* botCaster, Mob* target);
static BotSpell GetBestBotSpellForResistDebuff(Bot* botCaster, Mob* target);
static NPCType CreateDefaultNPCTypeStructForBot(std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender);
static std::list<Bot*> GetBotsInHealRotation( Bot* leader );
// Static Bot Group Methods
static bool AddBotToGroup(Bot* bot, Group* group);
static bool RemoveBotFromGroup(Bot* bot, Group* group);
static bool BotGroupCreate(std::string botGroupLeaderName);
static bool BotGroupCreate(Bot* botGroupLeader);
static bool GroupHasClass(Group* group, uint8 classId);
static bool GroupHasClericClass(Group* group) { return GroupHasClass(group, CLERIC); }
static bool GroupHasDruidClass(Group* group) { return GroupHasClass(group, DRUID); }
static bool GroupHasShamanClass(Group* group) { return GroupHasClass(group, SHAMAN); }
static bool GroupHasEnchanterClass(Group* group) { return GroupHasClass(group, ENCHANTER); }
static bool GroupHasPriestClass(Group* group) { return GroupHasClass(group, CLERIC | DRUID | SHAMAN); }
static void BotGroupSay(Mob *speaker, const char *msg, ...);
// "GET" Class Methods
uint32 GetBotID() const { return _botID; }
uint32 GetBotOwnerCharacterID() { return _botOwnerCharacterID; }
uint32 GetBotSpellID() { return npc_spells_id; }
Mob* GetBotOwner() { return this->_botOwner; }
uint32 GetBotArcheryRange();
ItemInst* GetBotItem(uint32 slotID);
virtual bool GetSpawnStatus() { return _spawnStatus; }
uint8 GetPetChooserID() { return _petChooserID; }
bool IsPetChooser() { return _petChooser; }
bool IsBotArcher() { return _botArcher; }
bool IsBotCharmer() { return _botCharmer; }
virtual bool IsBot() const { return true; }
bool GetRangerAutoWeaponSelect() { return _rangerAutoWeaponSelect; }
BotRoleType GetBotRole() { return _botRole; }
BotStanceType GetBotStance() { return _botStance; }
uint8 GetChanceToCastBySpellType(uint16 spellType);
bool IsGroupPrimaryHealer();
bool IsGroupPrimarySlower();
bool IsBotCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == NECROMANCER || GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == ENCHANTER); }
bool IsBotINTCaster() { return (GetClass() == NECROMANCER || GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == ENCHANTER); }
bool IsBotWISCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN); }
bool CanHeal();
int GetRawACNoShield(int &shield_ac);
void LoadAAs();
uint32 GetAA(uint32 aa_id);
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
bool GetHasBeenSummoned() { return _hasBeenSummoned; }
float GetPreSummonX() { return _preSummonX; }
float GetPreSummonY() { return _preSummonY; }
float GetPreSummonZ() { return _preSummonZ; }
bool GetGroupMessagesOn() { return _groupMessagesOn; }
bool GetInHealRotation() { return _isInHealRotation; }
bool GetHealRotationActive() { return (GetInHealRotation() && _isHealRotationActive); }
bool GetHealRotationUseFastHeals() { return _healRotationUseFastHeals; }
bool GetHasHealedThisCycle() { return _hasHealedThisCycle; }
Mob* GetHealRotationTarget();
Mob* GetHealRotationTarget(uint8 index);
Bot* GetHealRotationLeader();
Bot* GetNextHealRotationMember();
Bot* GetPrevHealRotationMember();
uint8 GetNumHealRotationMembers () { return _numHealRotationMembers; }
uint32 GetHealRotationNextHealTime() { return _healRotationNextHeal; }
uint32 GetHealRotationTimer () { return _healRotationTimer; }
bool GetBardUseOutOfCombatSongs() { return _bardUseOutOfCombatSongs;}
inline virtual int16 GetAC() const { return AC; }
inline virtual int16 GetSTR() const { return STR; }
inline virtual int16 GetSTA() const { return STA; }
inline virtual int16 GetDEX() const { return DEX; }
inline virtual int16 GetAGI() const { return AGI; }
inline virtual int16 GetINT() const { return INT; }
inline virtual int16 GetWIS() const { return WIS; }
inline virtual int16 GetCHA() const { return CHA; }
inline virtual int16 GetMR() const { return MR; }
inline virtual int16 GetFR() const { return FR; }
inline virtual int16 GetDR() const { return DR; }
inline virtual int16 GetPR() const { return PR; }
inline virtual int16 GetCR() const { return CR; }
inline virtual int16 GetCorrup() const { return Corrup; }
//Heroic
inline virtual int16 GetHeroicSTR() const { return itembonuses.HeroicSTR; }
inline virtual int16 GetHeroicSTA() const { return itembonuses.HeroicSTA; }
inline virtual int16 GetHeroicDEX() const { return itembonuses.HeroicDEX; }
inline virtual int16 GetHeroicAGI() const { return itembonuses.HeroicAGI; }
inline virtual int16 GetHeroicINT() const { return itembonuses.HeroicINT; }
inline virtual int16 GetHeroicWIS() const { return itembonuses.HeroicWIS; }
inline virtual int16 GetHeroicCHA() const { return itembonuses.HeroicCHA; }
inline virtual int16 GetHeroicMR() const { return itembonuses.HeroicMR; }
inline virtual int16 GetHeroicFR() const { return itembonuses.HeroicFR; }
inline virtual int16 GetHeroicDR() const { return itembonuses.HeroicDR; }
inline virtual int16 GetHeroicPR() const { return itembonuses.HeroicPR; }
inline virtual int16 GetHeroicCR() const { return itembonuses.HeroicCR; }
inline virtual int16 GetHeroicCorrup() const { return itembonuses.HeroicCorrup; }
// Mod2
inline virtual int16 GetShielding() const { return itembonuses.MeleeMitigation; }
inline virtual int16 GetSpellShield() const { return itembonuses.SpellShield; }
inline virtual int16 GetDoTShield() const { return itembonuses.DoTShielding; }
inline virtual int16 GetStunResist() const { return itembonuses.StunResist; }
inline virtual int16 GetStrikeThrough() const { return itembonuses.StrikeThrough; }
inline virtual int16 GetAvoidance() const { return itembonuses.AvoidMeleeChance; }
inline virtual int16 GetAccuracy() const { return itembonuses.HitChance; }
inline virtual int16 GetCombatEffects() const { return itembonuses.ProcChance; }
inline virtual int16 GetDS() const { return itembonuses.DamageShield; }
// Mod3
inline virtual int16 GetHealAmt() const { return itembonuses.HealAmt; }
inline virtual int16 GetSpellDmg() const { return itembonuses.SpellDmg; }
inline virtual int16 GetClair() const { return itembonuses.Clairvoyance; }
inline virtual int16 GetDSMit() const { return itembonuses.DSMitigation; }
inline virtual int16 GetSingMod() const { return itembonuses.singingMod; }
inline virtual int16 GetBrassMod() const { return itembonuses.brassMod; }
inline virtual int16 GetPercMod() const { return itembonuses.percussionMod; }
inline virtual int16 GetStringMod() const { return itembonuses.stringedMod; }
inline virtual int16 GetWindMod() const { return itembonuses.windMod; }
inline virtual int16 GetDelayDeath() const { return aabonuses.DelayDeath + spellbonuses.DelayDeath + itembonuses.DelayDeath; }
inline InspectMessage_Struct& GetInspectMessage() { return _botInspectMessage; }
inline const InspectMessage_Struct& GetInspectMessage() const { return _botInspectMessage; }
// "SET" Class Methods
void SetBotSpellID(uint32 newSpellID);
virtual void SetSpawnStatus(bool spawnStatus) { _spawnStatus = spawnStatus; }
void SetPetChooserID(uint8 id) { _petChooserID = id; }
void SetBotArcher(bool a) { _botArcher = a; }
void SetBotCharmer(bool c) { _botCharmer = c; }
void SetPetChooser(bool p) { _petChooser = p; }
void SetBotOwner(Mob* botOwner) { this->_botOwner = botOwner; }
// void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; }
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
void SetBotRole(BotRoleType botRole) { _botRole = botRole; }
void SetBotStance(BotStanceType botStance) { _botStance = botStance; }
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
void SetHasBeenSummoned(bool s);
void SetPreSummonX(float x) { _preSummonX = x; }
void SetPreSummonY(float y) { _preSummonY = y; }
void SetPreSummonZ(float z) { _preSummonZ = z; }
void SetGroupMessagesOn(bool groupMessagesOn) { _groupMessagesOn = groupMessagesOn; }
void SetInHealRotation( bool inRotation ) { _isInHealRotation = inRotation; }
void SetHealRotationActive( bool isActive ) { _isHealRotationActive = isActive; }
void SetHealRotationUseFastHeals( bool useFastHeals ) { _healRotationUseFastHeals = useFastHeals; }
void SetHasHealedThisCycle( bool hasHealed ) { _hasHealedThisCycle = hasHealed; }
void SetHealRotationLeader( Bot* leader );
void SetNextHealRotationMember( Bot* healer );
void SetPrevHealRotationMember( Bot* healer );
void SetHealRotationNextHealTime( uint32 nextHealTime ) { _healRotationNextHeal = nextHealTime; }
void SetHealRotationTimer( uint32 timer ) { _healRotationTimer = timer; }
void SetNumHealRotationMembers( uint8 numMembers ) { _numHealRotationMembers = numMembers; }
void SetBardUseOutOfCombatSongs(bool useOutOfCombatSongs) { _bardUseOutOfCombatSongs = useOutOfCombatSongs;}
// Class Destructors
virtual ~Bot();
protected:
virtual void PetAIProcess();
static NPCType FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender, float size, uint32 face, uint32 hairStyle, uint32 hairColor, uint32 eyeColor, uint32 eyeColor2, uint32 beardColor, uint32 beard, uint32 drakkinHeritage, uint32 drakkinTattoo, uint32 drakkinDetails, int32 hp, int32 mana, int16 mr, int16 cr, int16 dr, int16 fr, int16 pr, int16 corrup, int16 ac, uint16 str, uint16 sta, uint16 dex, uint16 agi, uint16 _int, uint16 wis, uint16 cha, uint16 attack);
virtual void BotMeditate(bool isSitting);
virtual void BotRangedAttack(Mob* other);
virtual bool CheckBotDoubleAttack(bool Triple = false);
virtual int16 GetBotFocusEffect(BotfocusType bottype, uint16 spell_id);
virtual int16 CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false);
virtual int16 CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id);
virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client);
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
virtual float GetMaxMeleeRangeToTarget(Mob* target);
static void SetBotGuildMembership(uint32 botId, uint32 guildid, uint8 rank);
private:
// Class Members
uint32 _botID;
uint32 _botOwnerCharacterID;
//uint32 _botSpellID;
bool _spawnStatus;
Mob* _botOwner;
bool _botOrderAttack;
bool _botArcher;
bool _botCharmer;
bool _petChooser;
uint8 _petChooserID;
bool berserk;
Inventory m_inv;
double _lastTotalPlayTime;
time_t _startTotalPlayTime;
Mob* _previousTarget;
uint32 _guildId;
uint8 _guildRank;
std::string _guildName;
uint32 _lastZoneId;
bool _rangerAutoWeaponSelect;
BotRoleType _botRole;
BotStanceType _botStance;
BotStanceType _baseBotStance;
unsigned int RestRegenHP;
unsigned int RestRegenMana;
unsigned int RestRegenEndurance;
Timer rest_timer;
int32 base_end;
int32 cur_end;
int32 max_end;
int16 end_regen;
uint32 timers[MaxTimer];
bool _hasBeenSummoned;
float _preSummonX;
float _preSummonY;
float _preSummonZ;
uint8 _spellCastingChances[MaxStances][MaxSpellTypes];
bool _groupMessagesOn;
bool _isInHealRotation;
bool _isHealRotationActive;
bool _healRotationUseFastHeals;
bool _hasHealedThisCycle;
uint32 _healRotationTimer;
uint32 _healRotationNextHeal;
//char _healRotationTargets[MaxHealRotationTargets][64];
uint16 _healRotationTargets[MaxHealRotationTargets];
uint32 _healRotationLeader;
uint32 _healRotationMemberNext;
uint32 _healRotationMemberPrev;
uint8 _numHealRotationMembers;
std::map<uint32, BotAA> botAAs;
InspectMessage_Struct _botInspectMessage;
bool _bardUseOutOfCombatSongs;
// Private "base stats" Members
int16 _baseMR;
int16 _baseCR;
int16 _baseDR;
int16 _baseFR;
int16 _basePR;
int16 _baseCorrup;
int _baseAC;
int16 _baseSTR;
int16 _baseSTA;
int16 _baseDEX;
int16 _baseAGI;
int16 _baseINT;
int16 _baseWIS;
int16 _baseCHA;
int16 _baseATK;
uint16 _baseRace; // Necessary to preserve the race otherwise bots get their race updated in the db when they get an illusion.
uint8 _baseGender; // Bots gender. Necessary to preserve the original value otherwise it can be changed by illusions.
// Class Methods
int16 acmod();
void GenerateBaseStats();
void GenerateAppearance();
void GenerateArmorClass();
int32 GenerateBaseHitPoints();
void GenerateAABonuses(StatBonuses* newbon);
int32 GenerateBaseManaPoints();
void GenerateSpecialAttacks();
void SetBotID(uint32 botID);
// Private "Inventory" Methods
void GetBotItems(std::string* errorMessage, Inventory &inv);
void BotRemoveEquipItem(int slot);
void BotAddEquipItem(int slot, uint32 id);
uint32 GetBotItemBySlot(uint32 slotID);
void RemoveBotItemBySlot(uint32 slotID, std::string* errorMessage);
void SetBotItemInSlot(uint32 slotID, uint32 itemID, const ItemInst* inst, std::string* errorMessage);
uint32 GetBotItemsCount(std::string* errorMessage);
uint32 GetTotalPlayTime();
void SaveBuffs(); // Saves existing buffs to the database to persist zoning and camping
void LoadBuffs(); // Retrieves saved buffs from the database on spawning
void LoadPetBuffs(SpellBuff_Struct* petBuffs, uint32 botPetSaveId);
void SavePetBuffs(SpellBuff_Struct* petBuffs, uint32 botPetSaveId);
void LoadPetItems(uint32* petItems, uint32 botPetSaveId);
void SavePetItems(uint32* petItems, uint32 botPetSaveId);
void LoadPetStats(std::string* petName, uint16* petMana, uint16* petHitPoints, uint32* botPetId, uint32 botPetSaveId);
uint32 SavePetStats(std::string petName, uint16 petMana, uint16 petHitPoints, uint32 botPetId);
void LoadPet(); // Load and spawn bot pet if there is one
void SavePet(); // Save and depop bot pet if there is one
uint32 GetPetSaveId();
void DeletePetBuffs(uint32 botPetSaveId);
void DeletePetItems(uint32 botPetSaveId);
void DeletePetStats(uint32 botPetSaveId);
void LoadGuildMembership(uint32* guildId, uint8* guildRank, std::string* guildName);
void LoadStance();
void SaveStance();
void LoadTimers();
void SaveTimers();
};
#endif // BOTS
#endif // BOT_H

View File

@ -1,48 +0,0 @@
#ifndef BOT_STRUCTS
#define BOT_STRUCTS
#ifdef BOTS
#include "../common/types.h"
#include <sstream>
struct BotsAvailableList {
uint32 BotID;
char BotName[64];
uint16 BotClass;
uint8 BotLevel;
uint16 BotRace;
};
struct BotGroup {
uint32 BotGroupID;
uint32 BotID;
};
struct BotGroupList {
std::string BotGroupName;
std::string BotGroupLeaderName;
};
struct SpawnedBotsList {
char BotName[64];
char ZoneName[64];
uint32 BotLeaderCharID;
};
struct BotSpell {
uint16 SpellId;
int SpellIndex;
int16 ManaCost;
};
struct BotAA {
uint32 aa_id;
uint8 req_level;
uint8 total_levels;
};
#endif // BOTS
#endif // BOT_STRUCTS

File diff suppressed because it is too large Load Diff

View File

@ -327,9 +327,6 @@ Client::Client(EQStreamInterface* ieqs)
}
Client::~Client() {
#ifdef BOTS
Bot::ProcessBotOwnerRefDelete(this);
#endif
if(IsInAGuild())
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));

View File

@ -3308,11 +3308,6 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
}
void Client::Handle_OP_Camp(const EQApplicationPacket *app) {
#ifdef BOTS
// This block is necessary to clean up any bot objects owned by a Client
Bot::BotHealRotationsClear(this);
Bot::BotOrderCampAll(this);
#endif
if(IsLFP())
worldserver.StopLFP(CharacterID());
@ -3555,7 +3550,7 @@ void Client::Handle_OP_DeleteSpawn(const EQApplicationPacket *app)
entity_list.QueueClients(this, outapp, false);
safe_delete(outapp);
hate_list.RemoveEnt(this->CastToMob());
hate_list.clear(this->CastToMob());
Disconnect();
return;
@ -4286,13 +4281,6 @@ void Client::Handle_OP_GuildInvite(const EQApplicationPacket *app)
return;
}
}
#ifdef BOTS
else if (invitee->IsBot()) {
// The guild system is too tightly coupled with the character_ table so we have to avoid using much of the system
Bot::ProcessGuildInvite(this, invitee->CastToBot());
return;
}
#endif
}
}
@ -4315,10 +4303,6 @@ void Client::Handle_OP_GuildRemove(const EQApplicationPacket *app)
else if (!worldserver.Connected())
Message(0, "Error: World server disconnected");
else {
#ifdef BOTS
if(Bot::ProcessGuildRemoval(this, gc->othername))
return;
#endif
uint32 char_id;
Client* client = entity_list.GetClientByName(gc->othername);
@ -4941,10 +4925,6 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
FinishTrade(with->CastToNPC());
}
}
#ifdef BOTS
else if(with->IsBot())
with->CastToBot()->FinishTrade(this, Bot::BotTradeClientNormal);
#endif
trade->Reset();
}
@ -6305,11 +6285,6 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app)
}
}
}
#ifdef BOTS
else if(Invitee->IsBot()) {
Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName()));
}
#endif
}
else
{
@ -6600,22 +6575,6 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
if(!group)
return;
#ifdef BOTS
// this block is necessary to allow more control over controlling how bots are zoned or camped.
if(Bot::GroupHasBot(group)) {
if(group->IsLeader(this)) {
if((GetTarget() == 0 || GetTarget() == this) || (group->GroupCount() < 3)) {
Bot::ProcessBotGroupDisband(this, std::string());
} else {
Mob* tempMember = entity_list.GetMob(gd->name2);
if(tempMember) {
if(tempMember->IsBot())
Bot::ProcessBotGroupDisband(this, std::string(tempMember->GetCleanName()));
}
}
}
}
#endif
if((group->IsLeader(this) && (GetTarget() == 0 || GetTarget() == this)) || (group->GroupCount()<3)) {
group->DisbandGroup();
if(GetMerc() != nullptr)
@ -6759,12 +6718,6 @@ void Client::Handle_OP_InspectRequest(const EQApplicationPacket *app) {
// Inspecting an SoF or later client will make the server handle the request
else { ProcessInspectRequest(tmp->CastToClient(), this); }
}
#ifdef BOTS
if(tmp != 0 && tmp->IsBot()) { Bot::ProcessBotInspectionRequest(tmp->CastToBot(), this); }
#endif
return;
}
void Client::Handle_OP_InspectAnswer(const EQApplicationPacket *app) {
@ -9069,10 +9022,6 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
LFG = false;
}
#ifdef BOTS
Bot::LoadAndSpawnAllZonedBots(this);
#endif
CalcBonuses();
if (m_pp.cur_hp <= 0)
m_pp.cur_hp = GetMaxHP();

View File

@ -407,11 +407,6 @@ int command_init(void) {
command_add("guildlist","[guildapproveid] - Lists character names who have approved the guild specified by the approve id",0,command_guildlist) ||
command_add("altactivate", "[argument] - activates alternate advancement abilities, use altactivate help for more information", 0, command_altactivate) ||
command_add("refundaa", "- Refunds your target's AA points, will disconnect them in the process as well.", 100, command_refundaa) ||
#ifdef BOTS
command_add("bot","- Type \"#bot help\" to the see the list of available commands for bots.", 0, command_bot) ||
#endif
command_add("traindisc","[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)",150,command_traindisc) ||
command_add("setgraveyard","[zone name] - Creates a graveyard for the specified zone based on your target's LOC.", 200, command_setgraveyard) ||
command_add("deletegraveyard","[zone name] - Deletes the graveyard for the specified zone.", 200, command_deletegraveyard) ||
@ -1326,12 +1321,6 @@ void command_zone(Client *c, const Seperator *sep)
}
}
#ifdef BOTS
// This block is necessary to clean up any bot objects owned by a Client
if(zoneid != c->GetZoneID())
Bot::ProcessClientZoneChange(c);
#endif
if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4)){
//zone to specific coords
c->MovePC(zoneid, (float)atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), 0.0f, 0);
@ -2647,10 +2636,6 @@ void command_level(Client *c, const Seperator *sep)
}
else if (c->Admin() < 100) {
c->SetLevel(level, true);
#ifdef BOTS
if(RuleB(Bots, BotLevelsWithOwner))
Bot::LevelBotWithClient(c, level, true);
#endif
}
else if (!c->GetTarget()) {
c->Message(0, "Error: #Level: No target");
@ -2663,10 +2648,6 @@ void command_level(Client *c, const Seperator *sep)
c->GetTarget()->SetLevel(level, true);
if(c->GetTarget()->IsClient()) {
c->GetTarget()->CastToClient()->SendLevelAppearance();
#ifdef BOTS
if(RuleB(Bots, BotLevelsWithOwner))
Bot::LevelBotWithClient(c->GetTarget()->CastToClient(), level, true);
#endif
}
}
}
@ -10781,12 +10762,6 @@ void command_showspellslist(Client *c, const Seperator *sep)
}
// All new code added to command.cpp ought to be BEFORE this comment line. Do no append code to this file below the BOTS code block.
#ifdef BOTS
// Function delegate to support the command interface for Bots with the client.
void command_bot(Client *c, const Seperator *sep) {
Bot::ProcessBotCommands(c, sep);
}
#endif
void command_raidloot(Client *c, const Seperator *sep)
{

View File

@ -335,10 +335,5 @@ void command_profilereset(Client *c, const Seperator *sep);
void command_packetprofile(Client *c, const Seperator *sep);
#endif
#ifdef BOTS
#include "bot.h"
void command_bot(Client*c, const Seperator *sep);
#endif
#endif

View File

@ -2067,74 +2067,6 @@ XS(XS__npcfeature)
XSRETURN_EMPTY;
}
#ifdef BOTS
XS(XS__createbotcount);
XS(XS__createbotcount)
{
dXSARGS;
int RETVAL;
dXSTARG;
RETVAL = quest_manager.createbotcount();
XSprePUSH; PUSHi((IV)RETVAL);
XSRETURN(1);
}
XS(XS__spawnbotcount);
XS(XS__spawnbotcount)
{
dXSARGS;
int RETVAL;
dXSTARG;
RETVAL = quest_manager.spawnbotcount();
XSprePUSH; PUSHi((IV)RETVAL);
XSRETURN(1);
}
XS(XS__botquest);
XS(XS__botquest)
{
dXSARGS;
bool RETVAL;
dXSTARG;
RETVAL = quest_manager.botquest();
XSprePUSH; PUSHu((IV)RETVAL);
XSRETURN(1);
}
XS(XS__createBot);
XS(XS__createBot)
{
dXSARGS;
bool RETVAL;
dXSTARG;
if(items != 6)
{
Perl_croak(aTHX_ "Usage: createBot(firstname, lastname, level, race, class, gender)");
}
char *firstname = (char *)SvPV_nolen(ST(0));
char *lastname = (char *)SvPV_nolen(ST(1));
int level = (int) SvIV(ST(2));
int race = (int) SvIV(ST(3));
int botclass = (int) SvIV(ST(4));
int gender = (int) SvIV(ST(5));
RETVAL = quest_manager.createBot(firstname, lastname, level, race, botclass, gender);
XSprePUSH; PUSHu((IV)RETVAL);
XSRETURN(1);
}
#endif //BOTS
XS(XS__taskselector);
XS(XS__taskselector)
{
@ -3510,14 +3442,6 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "playertexture"), XS__playertexture, file);
newXS(strcpy(buf, "playerfeature"), XS__playerfeature, file);
newXS(strcpy(buf, "npcfeature"), XS__npcfeature, file);
#ifdef BOTS
newXS(strcpy(buf, "botquest"), XS__botquest, file);
newXS(strcpy(buf, "spawnbotcount"), XS__spawnbotcount, file);
newXS(strcpy(buf, "createbotcount"), XS__createbotcount, file);
newXS(strcpy(buf, "createBot"), XS__createBot, file);
#endif //BOTS
newXS(strcpy(buf, "taskselector"), XS__taskselector, file);
newXS(strcpy(buf, "tasksetselector"), XS__tasksetselector, file);
newXS(strcpy(buf, "enabletask"), XS__enabletask, file);

View File

@ -281,20 +281,6 @@ const Beacon* Entity::CastToBeacon() const
return static_cast<const Beacon *>(this);
}
#ifdef BOTS
Bot *Entity::CastToBot()
{
#ifdef _EQDEBUG
if (!IsBot()) {
std::cout << "CastToBot error" << std::endl;
DebugBreak();
return 0;
}
#endif
return static_cast<Bot *>(this);
}
#endif
EntityList::EntityList()
{
// set up ids between 1 and 1500
@ -505,10 +491,6 @@ void EntityList::MobProcess()
entity_list.RemoveNPC(mob->CastToNPC()->GetID());
} else if (mob->IsMerc()) {
entity_list.RemoveMerc(mob->CastToMerc()->GetID());
#ifdef BOTS
} else if (mob->IsBot()) {
entity_list.RemoveBot(mob->CastToBot()->GetID());
#endif
} else {
#ifdef _WINDOWS
struct in_addr in;
@ -2323,13 +2305,6 @@ void EntityList::RemoveEntity(uint16 id)
return;
else if (entity_list.RemoveMerc(id))
return;
#ifdef BOTS
// This block of code is necessary to clean up bot objects
else if (entity_list.RemoveBot(id))
return;
#endif //BOTS
else
entity_list.RemoveObject(id);
}

View File

@ -48,11 +48,6 @@ class Trap;
class Entity;
class EntityList;
#ifdef BOTS
class Bot;
class BotRaids;
#endif
extern EntityList entity_list;
class Entity
@ -103,11 +98,6 @@ public:
virtual void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { pDBAsyncWorkID = 0; }
bool CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk=1);
#ifdef BOTS
virtual bool IsBot() const { return false; }
Bot* CastToBot();
#endif
protected:
friend class EntityList;
inline virtual void SetID(uint16 set_id) { id = set_id; }
@ -446,21 +436,6 @@ private:
std::queue<uint16> free_ids;
// Please Do Not Declare Any EntityList Class Members After This Comment
#ifdef BOTS
public:
void AddBot(Bot* newBot, bool SendSpawnPacket = true, bool dontqueue = false);
void BotPickLock(Bot* rogue);
bool RemoveBot(uint16 entityID);
Mob* GetMobByBotID(uint32 botID);
Bot* GetBotByBotID(uint32 botID);
Bot* GetBotByBotName(std::string botName);
std::list<Bot*> GetBotsByBotOwnerCharacterID(uint32 botOwnerCharacterID);
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint16 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff
private:
std::list<Bot*> bot_list;
#endif
};
class BulkZoneSpawnPacket {

View File

@ -327,17 +327,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
else
Message(15, "Welcome to level %i!", check_level);
#ifdef BOTS
uint8 myoldlevel = GetLevel();
#endif
SetLevel(check_level);
#ifdef BOTS
if(RuleB(Bots, BotLevelsWithOwner))
// hack way of doing this..but, least invasive... (same criteria as gain level for sendlvlapp)
Bot::LevelBotWithClient(this, GetLevel(), (myoldlevel==check_level-1));
#endif
}
//If were at max level then stop gaining experience if we make it to the cap

View File

@ -327,13 +327,6 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
database.SetGroupID(newmember->GetName(), GetID(), owner->CharacterID(), true);
}
}
#ifdef BOTS
for (i = 0;i < MAX_GROUP_MEMBERS; i++) {
if (members[i] != nullptr && members[i]->IsBot()) {
members[i]->CastToBot()->CalcChanceToCast();
}
}
#endif //BOTS
}
else
database.SetGroupID(NewMemberName, GetID(), CharacterID, ismerc);
@ -487,11 +480,6 @@ void Group::MemberZoned(Mob* removemob) {
//should NOT clear the name, it is used for world communication.
break;
}
#ifdef BOTS
if (members[i] != nullptr && members[i]->IsBot()) {
members[i]->CastToBot()->CalcChanceToCast();
}
#endif //BOTS
}
if(removemob->IsClient() && HasRole(removemob, RoleAssist))
SetGroupAssistTarget(0);
@ -589,11 +577,6 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender)
if(members[i]->IsClient())
members[i]->CastToClient()->QueuePacket(outapp);
}
#ifdef BOTS
if (members[i] != nullptr && members[i]->IsBot()) {
members[i]->CastToBot()->CalcChanceToCast();
}
#endif //BOTS
}
if (!ignoresender) {

View File

@ -31,134 +31,112 @@
extern Zone *zone;
HateList::HateList()
{
owner = nullptr;
}
HateList::HateList() : mOwner(nullptr) { }
HateList::~HateList() { }
HateList::~HateList()
{
}
// neotokyo: added for frenzy support
// checks if target still is in frenzy mode
void HateList::CheckFrenzyHate()
void HateList::clear()
{
auto iterator = list.begin();
while(iterator != list.end())
auto i = mEntries.begin();
while(i != mEntries.end())
{
if ((*iterator)->ent->GetHPRatio() >= 20)
(*iterator)->bFrenzy = false;
++iterator;
}
}
void HateList::Wipe()
{
auto iterator = list.begin();
while(iterator != list.end())
{
Mob* m = (*iterator)->ent;
Mob* m = (*i)->mMOB;
if(m)
{
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), m, "0", 0);
parse->EventNPC(EVENT_HATE_LIST, mOwner->CastToNPC(), m, "0", 0);
if(m->IsClient())
m->CastToClient()->DecrementAggroCount();
}
delete (*iterator);
iterator = list.erase(iterator);
delete (*i);
i = mEntries.erase(i);
}
}
bool HateList::IsOnHateList(Mob *mob)
bool HateList::isHated(Mob* pMOB)
{
if(Find(mob))
return true;
return false;
return find(pMOB) != nullptr;
}
tHateEntry *HateList::Find(Mob *ent)
HateEntry* HateList::find(Mob* pMOB)
{
auto iterator = list.begin();
while(iterator != list.end())
{
if((*iterator)->ent == ent)
return (*iterator);
++iterator;
}
for (auto i = mEntries.begin(); i != mEntries.end(); i++)
if ((*i)->mMOB == pMOB) return *i;
return nullptr;
}
void HateList::Set(Mob* other, uint32 in_hate, uint32 in_dam)
void HateList::set(Mob* pMob, uint32 pHate, uint32 pDamage)
{
tHateEntry *p = Find(other);
if(p)
HateEntry *entry = find(pMob);
if (entry)
{
if(in_dam > 0)
p->damage = in_dam;
if(in_hate > 0)
p->hate = in_hate;
if(pDamage > 0)
entry->mDamage = pDamage;
if(pHate > 0)
entry->mHate = pHate;
}
}
Mob* HateList::GetDamageTop(Mob* hater)
Mob* HateList::getHighestDamage(Mob* hater)
{
/*
This is called in NPC::Death
It calls this on it's own HateList, passing itself as the hater parameter.
-- Under the circumstances where there were 40 people in a raid it would calculate the total raid damage 80 times.
*/
Mob* current = nullptr;
Group* grp = nullptr;
Raid* r = nullptr;
uint32 dmg_amt = 0;
auto iterator = list.begin();
while(iterator != list.end())
auto iterator = mEntries.begin();
while(iterator != mEntries.end())
{
grp = nullptr;
r = nullptr;
if((*iterator)->ent && (*iterator)->ent->IsClient()){
r = entity_list.GetRaidByClient((*iterator)->ent->CastToClient());
if((*iterator)->mMOB && (*iterator)->mMOB->IsClient()){
r = entity_list.GetRaidByClient((*iterator)->mMOB->CastToClient());
}
grp = entity_list.GetGroupByMob((*iterator)->ent);
grp = entity_list.GetGroupByMob((*iterator)->mMOB);
if((*iterator)->ent && r){
if((*iterator)->mMOB && r){
if(r->GetTotalRaidDamage(hater) >= dmg_amt)
{
current = (*iterator)->ent;
current = (*iterator)->mMOB;
dmg_amt = r->GetTotalRaidDamage(hater);
}
}
else if ((*iterator)->ent != nullptr && grp != nullptr)
else if ((*iterator)->mMOB != nullptr && grp != nullptr)
{
if (grp->GetTotalGroupDamage(hater) >= dmg_amt)
{
current = (*iterator)->ent;
current = (*iterator)->mMOB;
dmg_amt = grp->GetTotalGroupDamage(hater);
}
}
else if ((*iterator)->ent != nullptr && (uint32)(*iterator)->damage >= dmg_amt)
else if ((*iterator)->mMOB != nullptr && (uint32)(*iterator)->mDamage >= dmg_amt)
{
current = (*iterator)->ent;
dmg_amt = (*iterator)->damage;
current = (*iterator)->mMOB;
dmg_amt = (*iterator)->mDamage;
}
++iterator;
}
return current;
}
Mob* HateList::GetClosest(Mob *hater) {
Mob* HateList::getClosest(Mob *hater) {
Mob* close = nullptr;
float closedist = 99999.9f;
float thisdist;
auto iterator = list.begin();
while(iterator != list.end()) {
thisdist = (*iterator)->ent->DistNoRootNoZ(*hater);
if((*iterator)->ent != nullptr && thisdist <= closedist) {
auto iterator = mEntries.begin();
while(iterator != mEntries.end()) {
thisdist = (*iterator)->mMOB->DistNoRootNoZ(*hater);
if((*iterator)->mMOB != nullptr && thisdist <= closedist) {
closedist = thisdist;
close = (*iterator)->ent;
close = (*iterator)->mMOB;
}
++iterator;
}
@ -169,80 +147,65 @@ Mob* HateList::GetClosest(Mob *hater) {
return close;
}
// neotokyo: a few comments added, rearranged code for readability
void HateList::Add(Mob *ent, int32 in_hate, int32 in_dam, bool bFrenzy, bool iAddIfNotExist)
void HateList::add(Mob* pMOB, int32 pHate, int32 pDamage, bool pFrenzy, bool iAddIfNotExist)
{
if(!ent)
return;
if (!pMOB) return;
if(ent->IsCorpse())
return;
// Do not add corpses to HateList.
if (pMOB->IsCorpse()) return;
if(ent->IsClient() && ent->CastToClient()->IsDead())
return;
// Do not add dead dead players to HateList.
if (pMOB->IsClient() && pMOB->CastToClient()->IsDead()) return;
tHateEntry *p = Find(ent);
if (p)
// Where pMOB is already on the HateList, increase Hate/Damage values.
HateEntry *entry = find(pMOB);
if (entry)
{
p->damage+=(in_dam>=0)?in_dam:0;
p->hate+=in_hate;
p->bFrenzy = bFrenzy;
entry->mDamage += (pDamage >= 0) ? pDamage : 0;
entry->mHate += pHate;
entry->mFrenzy = pFrenzy;
}
// Where pMOB is not on the HateList, add it.
else if (iAddIfNotExist) {
p = new tHateEntry;
p->ent = ent;
p->damage = (in_dam>=0)?in_dam:0;
p->hate = in_hate;
p->bFrenzy = bFrenzy;
list.push_back(p);
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "1", 0);
entry = new HateEntry(pMOB, (pDamage >= 0) ? pDamage : 0, pHate, pFrenzy);
mEntries.push_back(entry);
parse->EventNPC(EVENT_HATE_LIST, mOwner->CastToNPC(), pMOB, "1", 0);
if(ent->IsClient())
ent->CastToClient()->IncrementAggroCount();
// Where pMOB is client, update 'Aggro Count'.
if (pMOB->IsClient())
pMOB->CastToClient()->IncrementAggroCount();
}
}
bool HateList::RemoveEnt(Mob *ent)
bool HateList::clear(Mob* pMOB)
{
if (!ent)
return false;
if (!pMOB) return false;
bool found = false;
auto iterator = list.begin();
while(iterator != list.end())
{
if((*iterator)->ent == ent)
{
if(ent)
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "0", 0);
found = true;
if(ent && ent->IsClient())
ent->CastToClient()->DecrementAggroCount();
delete (*iterator);
iterator = list.erase(iterator);
for (auto i = mEntries.begin(); i != mEntries.end(); i++) {
if ((*i)->mMOB == pMOB) {
parse->EventNPC(EVENT_HATE_LIST, mOwner->CastToNPC(), pMOB, "0", 0);
pMOB->CastToClient()->DecrementAggroCount();
// Clean up.
delete *i;
mEntries.erase(i);
return true;
}
else
++iterator;
}
return found;
return false;
}
void HateList::DoFactionHits(int32 nfl_id) {
if (nfl_id <= 0)
return;
auto iterator = list.begin();
while(iterator != list.end())
auto iterator = mEntries.begin();
while(iterator != mEntries.end())
{
Client *p;
if ((*iterator)->ent && (*iterator)->ent->IsClient())
p = (*iterator)->ent->CastToClient();
if ((*iterator)->mMOB && (*iterator)->mMOB->IsClient())
p = (*iterator)->mMOB->CastToClient();
else
p = nullptr;
@ -252,26 +215,18 @@ void HateList::DoFactionHits(int32 nfl_id) {
}
}
int HateList::SummonedPetCount(Mob *hater) {
//Function to get number of 'Summoned' pets on a targets hate list to allow calculations for certian spell effects.
//Unclear from description that pets are required to be 'summoned body type'. Will not require at this time.
int petcount = 0;
auto iterator = list.begin();
while(iterator != list.end()) {
if((*iterator)->ent != nullptr && (*iterator)->ent->IsNPC() && ((*iterator)->ent->CastToNPC()->IsPet() || ((*iterator)->ent->CastToNPC()->GetSwarmOwner() > 0)))
{
++petcount;
}
++iterator;
int HateList::getSummonedPetCount() {
int count = 0;
for (auto i = mEntries.begin(); i != mEntries.end(); i++) {
Mob* entryMOB = (*i)->mMOB;
if (entryMOB && entryMOB->IsNPC() && (entryMOB->CastToNPC()->IsPet() || (entryMOB->CastToNPC()->GetSwarmOwner() > 0)))
count++;
}
return petcount;
return count;
}
Mob *HateList::GetTop(Mob *center)
Mob *HateList::getHighestHate(Mob *center)
{
Mob* top = nullptr;
int32 hate = -1;
@ -284,10 +239,10 @@ Mob *HateList::GetTop(Mob *center)
int32 hateClientTypeInRange = -1;
int skipped_count = 0;
auto iterator = list.begin();
while(iterator != list.end())
auto iterator = mEntries.begin();
while(iterator != mEntries.end())
{
tHateEntry *cur = (*iterator);
HateEntry *cur = (*iterator);
int16 aggroMod = 0;
if(!cur){
@ -295,48 +250,48 @@ Mob *HateList::GetTop(Mob *center)
continue;
}
if(!cur->ent){
if(!cur->mMOB){
++iterator;
continue;
}
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
if(!zone->watermap->InLiquid(cur->mMOB->GetX(), cur->mMOB->GetY(), cur->mMOB->GetZ())) {
skipped_count++;
++iterator;
continue;
}
}
if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){
if(cur->mMOB->DivineAura() || cur->mMOB->IsMezzed() || cur->mMOB->IsFeared()){
if(hate == -1)
{
top = cur->ent;
top = cur->mMOB;
hate = 0;
}
++iterator;
continue;
}
int32 currentHate = cur->hate;
int32 currentHate = cur->mHate;
if(cur->ent->IsClient()){
if(cur->mMOB->IsClient()){
if(cur->ent->CastToClient()->IsSitting()){
if(cur->mMOB->CastToClient()->IsSitting()){
aggroMod += RuleI(Aggro, SittingAggroMod);
}
if(center){
if(center->GetTarget() == cur->ent)
if(center->GetTarget() == cur->mMOB)
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if(center->CombatRange(cur->ent)){
if(center->CombatRange(cur->mMOB)){
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
if(currentHate > hateClientTypeInRange || cur->bFrenzy){
if(currentHate > hateClientTypeInRange || cur->mFrenzy){
hateClientTypeInRange = currentHate;
topClientTypeInRange = cur->ent;
topClientTypeInRange = cur->mMOB;
}
}
}
@ -345,18 +300,18 @@ Mob *HateList::GetTop(Mob *center)
}
else{
if(center){
if(center->GetTarget() == cur->ent)
if(center->GetTarget() == cur->mMOB)
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if(center->CombatRange(cur->ent)){
if(center->CombatRange(cur->mMOB)){
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
}
}
}
}
if(cur->ent->GetMaxHP() != 0 && ((cur->ent->GetHP()*100/cur->ent->GetMaxHP()) < 20)){
if(cur->mMOB->GetMaxHP() != 0 && ((cur->mMOB->GetHP()*100/cur->mMOB->GetMaxHP()) < 20)){
aggroMod += RuleI(Aggro, CriticallyWoundedAggroMod);
}
@ -364,9 +319,9 @@ Mob *HateList::GetTop(Mob *center)
currentHate += (currentHate * aggroMod / 100);
}
if(currentHate > hate || cur->bFrenzy){
if(currentHate > hate || cur->mFrenzy){
hate = currentHate;
top = cur->ent;
top = cur->mMOB;
}
++iterator;
@ -374,14 +329,6 @@ Mob *HateList::GetTop(Mob *center)
if(topClientTypeInRange != nullptr && top != nullptr) {
bool isTopClientType = top->IsClient();
#ifdef BOTS
if(!isTopClientType) {
if(top->IsBot()) {
isTopClientType = true;
topClientTypeInRange = top;
}
}
#endif //BOTS
if(!isTopClientType) {
if(top->IsMerc()) {
@ -403,23 +350,23 @@ Mob *HateList::GetTop(Mob *center)
}
}
else{
auto iterator = list.begin();
auto iterator = mEntries.begin();
int skipped_count = 0;
while(iterator != list.end())
while(iterator != mEntries.end())
{
tHateEntry *cur = (*iterator);
HateEntry *cur = (*iterator);
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
if(!zone->watermap->InLiquid(cur->mMOB->GetX(), cur->mMOB->GetY(), cur->mMOB->GetZ())) {
skipped_count++;
++iterator;
continue;
}
}
if(cur->ent != nullptr && ((cur->hate > hate) || cur->bFrenzy ))
if(cur->mMOB != nullptr && ((cur->mHate > hate) || cur->mFrenzy ))
{
top = cur->ent;
hate = cur->hate;
top = cur->mMOB;
hate = cur->mHate;
}
++iterator;
}
@ -431,18 +378,18 @@ Mob *HateList::GetTop(Mob *center)
return nullptr;
}
Mob *HateList::GetMostHate(){
Mob *HateList::getMostHate(){
Mob* top = nullptr;
int32 hate = -1;
auto iterator = list.begin();
while(iterator != list.end())
auto iterator = mEntries.begin();
while(iterator != mEntries.end())
{
tHateEntry *cur = (*iterator);
if(cur->ent != nullptr && (cur->hate > hate))
HateEntry *cur = (*iterator);
if(cur->mMOB != nullptr && (cur->mHate > hate))
{
top = cur->ent;
hate = cur->hate;
top = cur->mMOB;
hate = cur->mHate;
}
++iterator;
}
@ -450,57 +397,62 @@ Mob *HateList::GetMostHate(){
}
Mob *HateList::GetRandom()
Mob *HateList::getRandom()
{
int count = list.size();
int count = mEntries.size();
if(count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
return NULL;
if(count == 1) //No need to do all that extra work if we only have one hate entry
{
if(*list.begin()) // Just in case tHateEntry is invalidated somehow...
return (*list.begin())->ent;
if(*mEntries.begin()) // Just in case tHateEntry is invalidated somehow...
return (*mEntries.begin())->mMOB;
return NULL;
}
auto iterator = list.begin();
auto iterator = mEntries.begin();
int random = MakeRandomInt(0, count - 1);
for (int i = 0; i < random; i++)
++iterator;
return (*iterator)->ent;
return (*iterator)->mMOB;
}
int32 HateList::GetEntHate(Mob *ent, bool damage)
int32 HateList::getHate(Mob* pMOB, bool pDamage)
{
tHateEntry *p;
HateEntry* entry = find(pMOB);
if (entry) {
if (pDamage) return entry->mDamage;
return entry->mHate;
}
p = Find(ent);
if ( p && damage)
return p->damage;
else if (p)
return p->hate;
else
return 0;
return 0;
}
//looking for any mob with hate > -1
bool HateList::IsEmpty() {
return(list.size() == 0);
int32 HateList::getDamage(Mob* pMOB)
{
HateEntry* entry = find(pMOB);
if (entry) return entry->mDamage;
return 0;
}
bool HateList::isEmpty() {
return mEntries.size() == 0;
}
// Prints hate list to a client
void HateList::PrintToClient(Client *c)
{
auto iterator = list.begin();
while (iterator != list.end())
auto iterator = mEntries.begin();
while (iterator != mEntries.end())
{
tHateEntry *e = (*iterator);
HateEntry *e = (*iterator);
c->Message(0, "- name: %s, damage: %d, hate: %d",
(e->ent && e->ent->GetName()) ? e->ent->GetName() : "(null)",
e->damage, e->hate);
(e->mMOB && e->mMOB->GetName()) ? e->mMOB->GetName() : "(null)",
e->mDamage, e->mHate);
++iterator;
}
@ -513,16 +465,16 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
int ret = 0;
std::list<uint32> id_list;
auto iterator = list.begin();
while (iterator != list.end())
auto iterator = mEntries.begin();
while (iterator != mEntries.end())
{
tHateEntry *h = (*iterator);
HateEntry *h = (*iterator);
++iterator;
if(h && h->ent && h->ent != caster)
if(h && h->mMOB && h->mMOB != caster)
{
if(caster->CombatRange(h->ent))
if(caster->CombatRange(h->mMOB))
{
id_list.push_back(h->ent->GetID());
id_list.push_back(h->mMOB->GetID());
++ret;
}
}
@ -557,20 +509,20 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range)
//So keep a list of entity ids and look up after
std::list<uint32> id_list;
range = range * range;
auto iterator = list.begin();
while (iterator != list.end())
auto iterator = mEntries.begin();
while (iterator != mEntries.end())
{
tHateEntry *h = (*iterator);
HateEntry *h = (*iterator);
if(range > 0)
{
if(caster->DistNoRoot(*h->ent) <= range)
if(caster->DistNoRoot(*h->mMOB) <= range)
{
id_list.push_back(h->ent->GetID());
id_list.push_back(h->mMOB->GetID());
}
}
else
{
id_list.push_back(h->ent->GetID());
id_list.push_back(h->mMOB->GetID());
}
++iterator;
}

View File

@ -19,11 +19,16 @@
#ifndef HATELIST_H
#define HATELIST_H
struct tHateEntry
class Mob;
// TODO: Later fix pre-declarations. There is some crazy shit going on with include order in other files obviously.
struct HateEntry
{
Mob *ent;
int32 damage, hate;
bool bFrenzy;
HateEntry(Mob* pMOB, int32 pDamage, int32 pHate, bool pFrenzy) : mMOB(pMOB), mDamage(pDamage), mHate(pHate), mFrenzy(pFrenzy) {}
Mob *mMOB;
int32 mDamage;
int32 mHate;
bool mFrenzy;
};
class HateList
@ -32,53 +37,68 @@ public:
HateList();
~HateList();
// adds a mob to the hatelist
void Add(Mob *ent, int32 in_hate=0, int32 in_dam=0, bool bFrenzy = false, bool iAddIfNotExist = true);
// sets existing hate
void Set(Mob *other, uint32 in_hate, uint32 in_dam);
// removes mobs from hatelist
bool RemoveEnt(Mob *ent);
// Remove all
void Wipe();
// ???
void DoFactionHits(int32 nfl_id);
// Gets Hate amount for mob
int32 GetEntHate(Mob *ent, bool damage = false);
// gets top hated mob
Mob *GetTop(Mob *center);
// gets any on the list
Mob *GetRandom();
// get closest mob or nullptr if list empty
Mob *GetClosest(Mob *hater);
// gets top mob or nullptr if hate list empty
Mob *GetDamageTop(Mob *hater);
// used to check if mob is on hatelist
bool IsOnHateList(Mob *);
// used to remove or add frenzy hate
void CheckFrenzyHate();
// Set the owner of the HateList.
void setOwner(Mob* pOwner) { mOwner = pOwner; }
// Returns whether the HateList is empty.
bool isEmpty();
// Returns the number of pets on the HateList.
int getSummonedPetCount();
// Removes a specific MOB from the HateList.
bool clear(Mob* pMOB);
// Removes all MOBs from the HateList.
void clear();
// Adds a MOB to the HateList.
// TODO: Look more into parameter 'iAddIfNotExist' .. I can't think of circumstances where this would be needed.
void add(Mob* pMOB, int32 pHate = 0, int32 pDamage = 0, bool pFrenzy = false, bool iAddIfNotExist = true);
// Sets a MOBs hate.
void set(Mob* pMOB, uint32 pHate, uint32 pDamage);
// Returns the hate value of a specific MOB. (Or Damage for fun under some circumstances...)
// TODO: Remove the 'damage' parameter and use getDamage where appropriate.
int32 getHate(Mob * pMOB, bool damage = false);
// Returns the damage value of a specific MOB.
int32 getDamage(Mob* pMOB);
// Returns the MOB with the highest hate value or null if none.
Mob *getHighestHate(Mob* pCenter);
// Returns the MOB with the highest damage value or null if none.
Mob *getHighestDamage(Mob* pHater);
// Returns a random MOB on the HateList.
Mob* getRandom();
// Returns the closest MOB.
Mob* getClosest(Mob* pHater);
// Returns whether the specific MOB is on the HateList.
bool isHated(Mob * pMOB);
//Gets the target with the most hate regardless of things like frenzy etc.
Mob* GetMostHate();
// Count 'Summoned' pets on hatelist
int SummonedPetCount(Mob *hater);
int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts);
void SpellCast(Mob *caster, uint32 spell_id, float range);
bool IsEmpty();
void PrintToClient(Client *c);
Mob* getMostHate();
//For accessing the hate list via perl; don't use for anything else
std::list<tHateEntry*>& GetHateList() { return list; }
std::list<HateEntry*>& GetHateList() { return mEntries; }
//setting owner
void SetOwner(Mob *newOwner) { owner = newOwner; }
protected:
tHateEntry* Find(Mob *ent);
// TODO: Remove, this functionality does not belong here.
void DoFactionHits(int32 nfl_id);
// TODO: Remove, this functionality does not belong here.
int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts);
// TODO: Remove, this functionality does not belong here.
void SpellCast(Mob *caster, uint32 spell_id, float range);
// TODO: Remove, this functionality does not belong here.
void PrintToClient(Client *c);
private:
std::list<tHateEntry*> list;
Mob *owner;
HateEntry* find(Mob* pMOB);
std::list<HateEntry*> mEntries;
Mob* mOwner;
};
#endif

View File

@ -12,42 +12,42 @@
Lua_Mob Lua_HateEntry::GetEnt() {
Lua_Safe_Call_Class(Lua_Mob);
return Lua_Mob(self->ent);
return Lua_Mob(self->mMOB);
}
void Lua_HateEntry::SetEnt(Lua_Mob e) {
Lua_Safe_Call_Void();
self->ent = e;
self->mMOB = e;
}
int Lua_HateEntry::GetDamage() {
Lua_Safe_Call_Int();
return self->damage;
return self->mDamage;
}
void Lua_HateEntry::SetDamage(int value) {
Lua_Safe_Call_Void();
self->damage = value;
self->mDamage = value;
}
int Lua_HateEntry::GetHate() {
Lua_Safe_Call_Int();
return self->hate;
return self->mHate;
}
void Lua_HateEntry::SetHate(int value) {
Lua_Safe_Call_Void();
self->hate = value;
self->mHate = value;
}
int Lua_HateEntry::GetFrenzy() {
Lua_Safe_Call_Int();
return self->bFrenzy;
return self->mFrenzy;
}
void Lua_HateEntry::SetFrenzy(bool value) {
Lua_Safe_Call_Void();
self->bFrenzy = value;
self->mFrenzy = value;
}
luabind::scope lua_register_hate_entry() {

View File

@ -5,17 +5,17 @@
#include "lua_ptr.h"
class Lua_Mob;
struct tHateEntry;
struct HateEntry;
luabind::scope lua_register_hate_entry();
luabind::scope lua_register_hate_list();
class Lua_HateEntry : public Lua_Ptr<tHateEntry>
class Lua_HateEntry : public Lua_Ptr<HateEntry>
{
typedef tHateEntry NativeType;
typedef HateEntry NativeType;
public:
Lua_HateEntry() : Lua_Ptr(nullptr) { }
Lua_HateEntry(tHateEntry *d) : Lua_Ptr(d) { }
Lua_HateEntry(HateEntry *d) : Lua_Ptr(d) { }
virtual ~Lua_HateEntry() { }
Lua_Mob GetEnt();

View File

@ -11,9 +11,4 @@
#include "mob.h"
#include "trap.h"
#include "beacon.h"
#include "horse.h"
#ifdef BOTS
#include "bot.h"
#endif
#include "horse.h"

File diff suppressed because it is too large Load Diff

View File

@ -1498,7 +1498,7 @@ void Merc::AI_Process() {
rest_timer.Disable();
if(IsRooted())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.getClosest(this));
else
FindTarget();
@ -2552,11 +2552,11 @@ void Merc::CheckHateList() {
Mob* groupMember = g->members[counter];
if(groupMember) {
if(npc->IsOnHatelist(groupMember)) {
if(!hate_list.IsOnHateList(npc)) {
if(!hate_list.isHated(npc)) {
float range = g->HasRole(groupMember, RolePuller) ? RuleI(Mercs, AggroRadiusPuller) : RuleI(Mercs, AggroRadius);
range *= range;
if(npc->DistNoRootNoZ(*this) < range) {
hate_list.Add(npc, 1);
hate_list.add(npc, 1);
}
}
}
@ -4751,7 +4751,7 @@ bool Merc::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attac
Save();
Mob *give_exp = hate_list.GetDamageTop(this);
Mob *give_exp = hate_list.getHighestDamage(this);
Client *give_exp_client = nullptr;
if(give_exp && give_exp->IsClient())

View File

@ -1,7 +0,0 @@
struct Msg {
int id;
char* Sender;
char* Subject;
char* Body;
char* Date;
};

View File

@ -375,7 +375,7 @@ Mob::Mob(const char* in_name,
PathingRouteUpdateTimerLong = new Timer(RuleI(Pathing, RouteUpdateFrequencyLong));
DistractedFromGrid = false;
PathingTraversedNodes = 0;
hate_list.SetOwner(this);
hate_list.setOwner(this);
m_AllowBeneficial = false;
m_DisableMelee = false;
@ -2396,16 +2396,6 @@ bool Mob::HateSummon() {
target->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), x_pos, y_pos, z_pos, target->GetHeading(), 0, SummonPC);
}
else {
#ifdef BOTS
if(target && target->IsBot()) {
// set pre summoning info to return to (to get out of melee range for caster)
target->CastToBot()->SetHasBeenSummoned(true);
target->CastToBot()->SetPreSummonX(target->GetX());
target->CastToBot()->SetPreSummonY(target->GetY());
target->CastToBot()->SetPreSummonZ(target->GetZ());
}
#endif //BOTS
target->GMMove(x_pos, y_pos, z_pos, target->GetHeading());
}
@ -2453,8 +2443,8 @@ bool Mob::RemoveFromHateList(Mob* mob)
bool bFound = false;
if(IsEngaged())
{
bFound = hate_list.RemoveEnt(mob);
if(hate_list.IsEmpty())
bFound = hate_list.clear(mob);
if(hate_list.isEmpty())
{
AI_Event_NoLongerEngaged();
zone->DelAggroMob();
@ -2462,7 +2452,7 @@ bool Mob::RemoveFromHateList(Mob* mob)
}
if(GetTarget() == mob)
{
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.getHighestHate(this));
}
return bFound;
@ -2472,12 +2462,12 @@ void Mob::WipeHateList()
{
if(IsEngaged())
{
hate_list.Wipe();
hate_list.clear();
AI_Event_NoLongerEngaged();
}
else
{
hate_list.Wipe();
hate_list.clear();
}
}
@ -3293,7 +3283,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
}
else if (IsPet){
int count = hate_list.SummonedPetCount(this);
int count = hate_list.getSummonedPetCount();
if ((base2 >= 220 && base2 <= 250) && count >= (base2 - 220)){
use_spell = true;
}

View File

@ -427,16 +427,16 @@ public:
virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true,
bool bFrenzy = false, bool iBuffTic = false);
bool RemoveFromHateList(Mob* mob);
void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.Set(other,hate,damage);}
void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.set(other,hate,damage);}
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate > 1 ? in_hate / 2 : 1)); }
void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate ? in_hate * 2 : 1)); }
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHate(tmob,is_dam);}
uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHate(tmob, true);}
Mob* GetHateTop() { return hate_list.GetTop(this);}
Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTop(other);}
Mob* GetHateRandom() { return hate_list.GetRandom();}
Mob* GetHateMost() { return hate_list.GetMostHate();}
bool IsEngaged() { return(!hate_list.IsEmpty()); }
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.getHate(tmob,is_dam);}
uint32 GetDamageAmount(Mob* tmob) { return hate_list.getHate(tmob, true);}
Mob* GetHateTop() { return hate_list.getHighestHate(this);}
Mob* GetHateDamageTop(Mob* other) { return hate_list.getHighestDamage(other);}
Mob* GetHateRandom() { return hate_list.getRandom();}
Mob* GetHateMost() { return hate_list.getMostHate();}
bool IsEngaged() { return(!hate_list.isEmpty()); }
bool HateSummon();
void FaceTarget(Mob* MobToFace = 0);
void SetHeading(float iHeading) { if(heading != iHeading) { pLastChange = Timer::GetCurrentTime();
@ -446,7 +446,7 @@ public:
void RemoveFromFeignMemory(Client* attacker);
void ClearFeignMemory();
void PrintHateListToClient(Client *who) { hate_list.PrintToClient(who); }
std::list<tHateEntry*>& GetHateList() { return hate_list.GetHateList(); }
std::list<HateEntry*>& GetHateList() { return hate_list.GetHateList(); }
bool CheckLosFN(Mob* other);
bool CheckLosFN(float posX, float posY, float posZ, float mobSize);
inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); }
@ -748,7 +748,7 @@ public:
void ProcessFlee();
void CheckFlee();
inline bool CheckAggro(Mob* other) {return hate_list.IsOnHateList(other);}
inline bool CheckAggro(Mob* other) {return hate_list.isHated(other);}
float CalculateHeadingToTarget(float in_x, float in_y);
bool CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false);
virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true);

View File

@ -234,8 +234,8 @@ public:
inline int32 GetNPCFactionID() const { return npc_faction_id; }
inline int32 GetPrimaryFaction() const { return primary_faction; }
int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHate(in_ent);}
bool IsOnHatelist(Mob*p) { return hate_list.IsOnHateList(p);}
int32 GetNPCHate(Mob* in_ent) {return hate_list.getHate(in_ent);}
bool IsOnHatelist(Mob*p) { return hate_list.isHated(p);}
void SetNPCFactionID(int32 in) { npc_faction_id = in; database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction); }

View File

@ -40,19 +40,19 @@ XS(XS_HateEntry_GetEnt)
if (items != 1)
Perl_croak(aTHX_ "Usage: HateEntry::GetData(THIS)");
{
tHateEntry * THIS;
HateEntry * THIS;
Mob * RETVAL;
if (sv_derived_from(ST(0), "HateEntry")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(tHateEntry *,tmp);
THIS = INT2PTR(HateEntry *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->ent;
RETVAL = THIS->mMOB;
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "Mob", (void*)RETVAL);
}
@ -66,20 +66,20 @@ XS(XS_HateEntry_GetHate)
if (items != 1)
Perl_croak(aTHX_ "Usage: HateEntry::GetHate(THIS)");
{
tHateEntry * THIS;
HateEntry * THIS;
int32 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "HateEntry")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(tHateEntry *,tmp);
THIS = INT2PTR(HateEntry *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->hate;
RETVAL = THIS->mHate;
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
@ -92,20 +92,20 @@ XS(XS_HateEntry_GetDamage)
if (items != 1)
Perl_croak(aTHX_ "Usage: HateEntry::GetDamage(THIS)");
{
tHateEntry * THIS;
HateEntry * THIS;
int32 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "HateEntry")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(tHateEntry *,tmp);
THIS = INT2PTR(HateEntry *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->damage;
RETVAL = THIS->mDamage;
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);

View File

@ -6581,7 +6581,7 @@ XS(XS_Mob_GetHateList)
while(iter != hate_list.end())
{
tHateEntry *entry = (*iter);
HateEntry *entry = (*iter);
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "HateEntry", (void*)entry);
XPUSHs(ST(0));

View File

@ -76,11 +76,6 @@ And then at then end of embparser.cpp, add:
#include "QGlobals.h"
#include "QuestParserCollection.h"
#ifdef BOTS
#include "bot.h"
#endif
extern Zone* zone;
extern WorldServer worldserver;
extern EntityList entity_list;
@ -2021,83 +2016,6 @@ void QuestManager::popup(const char *title, const char *text, uint32 popupid, ui
initiator->SendPopupToClient(title, text, popupid, buttons, Duration);
}
#ifdef BOTS
int QuestManager::createbotcount() {
return RuleI(Bots, CreateBotCount);
}
int QuestManager::spawnbotcount() {
return RuleI(Bots, SpawnBotCount);
}
bool QuestManager::botquest()
{
return RuleB(Bots, BotQuest);
}
bool QuestManager::createBot(const char *name, const char *lastname, uint8 level, uint16 race, uint8 botclass, uint8 gender)
{
QuestManagerCurrentQuestVars();
std::string TempErrorMessage;
uint32 MaxBotCreate = RuleI(Bots, CreateBotCount);
if (initiator && initiator->IsClient())
{
if(Bot::SpawnedBotCount(initiator->CharacterID(), &TempErrorMessage) >= MaxBotCreate)
{
initiator->Message(15,"You have the maximum number of bots allowed.");
return false;
}
if(!TempErrorMessage.empty())
{
initiator->Message(13, "Database Error: %s", TempErrorMessage.c_str());
return false;
}
NPCType DefaultNPCTypeStruct = Bot::CreateDefaultNPCTypeStructForBot(name, lastname, level, race, botclass, gender);
Bot* NewBot = new Bot(DefaultNPCTypeStruct, initiator);
if(NewBot)
{
if(!NewBot->IsValidRaceClassCombo()) {
initiator->Message(0, "That Race/Class combination cannot be created.");
return false;
}
if(!NewBot->IsValidName()) {
initiator->Message(0, "%s has invalid characters. You can use only the A-Z, a-z and _ characters in a bot name.", NewBot->GetCleanName());
return false;
}
if(!NewBot->IsBotNameAvailable(&TempErrorMessage)) {
initiator->Message(0, "The name %s is already being used. Please choose a different name.", NewBot->GetCleanName());
return false;
}
if(!TempErrorMessage.empty()) {
initiator->Message(13, "Database Error: %s", TempErrorMessage.c_str());
return false;
}
// Now that all validation is complete, we can save our newly created bot
if(!NewBot->Save())
{
initiator->Message(0, "Unable to save %s as a bot.", NewBot->GetCleanName());
}
else
{
initiator->Message(0, "%s saved as bot %u.", NewBot->GetCleanName(), NewBot->GetBotID());
return true;
}
}
}
return false;
}
#endif //BOTS
void QuestManager::taskselector(int taskcount, int *tasks) {
QuestManagerCurrentQuestVars();
if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner && taskmanager)

View File

@ -251,14 +251,6 @@ public:
Mob *GetOwner() const;
ItemInst *GetQuestItem() const;
inline bool ProximitySayInUse() { return HaveProximitySays; }
#ifdef BOTS
int createbotcount();
int spawnbotcount();
bool botquest();
bool createBot(const char *name, const char *lastname, uint8 level, uint16 race, uint8 botclass, uint8 gender);
#endif
inline uint16 GetMana(uint32 spell_id) { return( spells[spell_id].mana); }
private:

View File

@ -1,101 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
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 SKILLS_H
#define SKILLS_H
#define HIGHEST_SKILL_UNUSED 74
// Correct Skill Numbers as of 4-14-2002
#define _1H_BLUNT_UNUSED 0
#define _1H_SLASHING_UNUSED 1
#define _2H_BLUNT_UNUSED 2
#define _2H_SLASHING_UNUSED 3
#define ABJURE_UNUSED 4
#define ALTERATION_UNUSED 5
#define APPLY_POISON_UNUSED 6
#define ARCHERY_UNUSED 7
#define BACKSTAB_UNUSED 8
#define BIND_WOUND_UNUSED 9
#define BASH_UNUSED 10
#define BLOCKSKILL_UNUSED 11
#define BRASS_INSTRUMENTS_UNUSED 12
#define CHANNELING_UNUSED 13
#define CONJURATION_UNUSED 14
#define DEFENSE_UNUSED 15
#define DISARM_UNUSED 16
#define DISARM_TRAPS_UNUSED 17
#define DIVINATION_UNUSED 18
#define DODGE_UNUSED 19
#define DOUBLE_ATTACK_UNUSED 20
#define DRAGON_PUNCH_UNUSED 21
#define DUAL_WIELD_UNUSED 22
#define EAGLE_STRIKE_UNUSED 23
#define EVOCATION_UNUSED 24
#define FEIGN_DEATH_UNUSED 25
#define FLYING_KICK_UNUSED 26
#define FORAGE_UNUSED 27
#define HAND_TO_HAND_UNUSED 28
#define HIDE_UNUSED 29
#define KICK_UNUSED 30
#define MEDITATE_UNUSED 31
#define MEND_UNUSED 32
#define OFFENSE_UNUSED 33
#define PARRY_UNUSED 34
#define PICK_LOCK_UNUSED 35
#define PIERCING_UNUSED 36
#define RIPOSTE_UNUSED 37
#define ROUND_KICK_UNUSED 38
#define SAFE_FALL_UNUSED 39
#define SENSE_HEADING_UNUSED 40
#define SINGING_UNUSED 41
#define SNEAK_UNUSED 42
#define SPECIALIZE_ABJURE_UNUSED 43
#define SPECIALIZE_ALTERATION_UNUSED 44
#define SPECIALIZE_CONJURATION_UNUSED 45
#define SPECIALIZE_DIVINATION_UNUSED 46
#define SPECIALIZE_EVOCATION_UNUSED 47
#define PICK_POCKETS_UNUSED 48
#define STRINGED_INSTRUMENTS_UNUSED 49
#define SWIMMING_UNUSED 50
#define THROWING_UNUSED 51
#define TIGER_CLAW_UNUSED 52
#define TRACKING_UNUSED 53
#define WIND_INSTRUMENTS_UNUSED 54
#define FISHING_UNUSED 55
#define MAKE_POISON_UNUSED 56
#define TINKERING_UNUSED 57
#define RESEARCH_UNUSED 58
#define ALCHEMY_UNUSED 59
#define BAKING_UNUSED 60
#define TAILORING_UNUSED 61
#define SENSE_TRAPS_UNUSED 62
#define BLACKSMITHING_UNUSED 63
#define FLETCHING_UNUSED 64
#define BREWING_UNUSED 65
#define ALCOHOL_TOLERANCE_UNUSED 66
#define BEGGING_UNUSED 67
#define JEWELRY_MAKING_UNUSED 68
#define POTTERY_UNUSED 69
#define PERCUSSION_INSTRUMENTS_UNUSED 70
#define INTIMIDATION_UNUSED 71
#define BERSERKING_UNUSED 72
#define TAUNT_UNUSED 73
#define FRENZY_UNUSED 74
#endif

View File

@ -6006,7 +6006,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama
//Limit to amount of pets
if (value >= 221 && value <= 249){
int count = hate_list.SummonedPetCount(this);
int count = hate_list.getSummonedPetCount();
for (int base2_value = 221; base2_value <= 249; ++base2_value){
if (value == base2_value){

View File

@ -987,21 +987,6 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
channelchance -= attacked_count * 2;
channelchance += channelchance * channelbonuses / 100.0f;
}
#ifdef BOTS
else if(IsBot()) {
float channelbonuses = 0.0f;
if (IsFromItem)
channelbonuses += spellbonuses.ChannelChanceItems + itembonuses.ChannelChanceItems + aabonuses.ChannelChanceItems;
else
channelbonuses += spellbonuses.ChannelChanceSpells + itembonuses.ChannelChanceSpells + aabonuses.ChannelChanceSpells;
// max 93% chance at 252 skill
channelchance = 30 + GetSkill(SkillChanneling) / 400.0f * 100;
channelchance -= attacked_count * 2;
channelchance += channelchance * channelbonuses / 100.0f;
}
#endif //BOTS
else {
// NPCs are just hard to interrupt, otherwise they get pwned
channelchance = 85;
@ -1634,21 +1619,6 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
group_id_caster = (owner->GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (owner->GetRaid()->GetGroup(CastToClient()) + 1);
}
}
#ifdef BOTS
else if(IsBot())
{
if(IsGrouped())
{
group_id_caster = GetGroup()->GetID();
}
else if(IsRaidGrouped())
{
if(GetOwner())
group_id_caster = (GetRaid()->GetGroup(GetOwner()->CastToClient()) == 0xFFFF) ? 0 : (GetRaid()->GetGroup(GetOwner()->CastToClient()) + 1);
}
}
#endif //BOTS
if(spell_target->IsClient())
{
if(spell_target->IsGrouped())
@ -1672,21 +1642,6 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
group_id_target = (owner->GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (owner->GetRaid()->GetGroup(CastToClient()) + 1);
}
}
#ifdef BOTS
else if(spell_target->IsBot())
{
if(spell_target->IsGrouped())
{
group_id_target = spell_target->GetGroup()->GetID();
}
else if(spell_target->IsRaidGrouped())
{
if(spell_target->GetOwner())
group_id_target = (spell_target->GetRaid()->GetGroup(spell_target->GetOwner()->CastToClient()) == 0xFFFF) ? 0 : (spell_target->GetRaid()->GetGroup(spell_target->GetOwner()->CastToClient()) + 1);
}
}
#endif //BOTS
if(group_id_caster == 0 || group_id_target == 0)
{
mlog(SPELLS__CASTING_ERR, "Spell %d canceled: Attempted to cast a Single Target Group spell on a ungrouped member.", spell_id);
@ -1877,17 +1832,6 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
case CastActUnknown:
case SingleTarget:
{
#ifdef BOTS
if(IsBot()) {
bool StopLogic = false;
if(!this->CastToBot()->DoFinishedSpellSingleTarget(spell_id, spell_target, slot, StopLogic))
return false;
if(StopLogic)
break;
}
#endif //BOTS
if(spell_target == nullptr) {
mlog(SPELLS__CASTING, "Spell %d: Targeted spell, but we have no target", spell_id);
return(false);
@ -1925,16 +1869,6 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
case AECaster:
case AETarget:
{
#ifdef BOTS
if(IsBot()) {
bool StopLogic = false;
if(!this->CastToBot()->DoFinishedSpellAETarget(spell_id, spell_target, slot, StopLogic))
return false;
if(StopLogic)
break;
}
#endif //BOTS
// we can't cast an AE spell without something to center it on
assert(ae_center != nullptr);
@ -1959,16 +1893,6 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
case GroupSpell:
{
#ifdef BOTS
if(IsBot()) {
bool StopLogic = false;
if(!this->CastToBot()->DoFinishedSpellGroupTarget(spell_id, spell_target, slot, StopLogic))
return false;
if(StopLogic)
break;
}
#endif //BOTS
if(spells[spell_id].can_mgb && IsClient() && CastToClient()->CheckAAEffect(aaEffectMassGroupBuff))
{
SpellOnTarget(spell_id, this);

View File

@ -31,11 +31,6 @@ extern Zone* zone;
void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
#ifdef BOTS
// This block is necessary to clean up any bot objects owned by a Client
Bot::ProcessClientZoneChange(this);
#endif
zoning = true;
if (app->size != sizeof(ZoneChange_Struct)) {
LogFile->write(EQEMuLog::Debug, "Wrong size: OP_ZoneChange, size=%d, expected %d", app->size, sizeof(ZoneChange_Struct));