Merge branch 'master' into eqstream

This commit is contained in:
KimLS
2017-02-28 23:18:35 -08:00
24 changed files with 3466 additions and 220 deletions
+152 -125
View File
@@ -178,6 +178,8 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
m_CastingRoles.GroupHealer = false;
m_CastingRoles.GroupSlower = false;
m_CastingRoles.GroupNuker = false;
m_CastingRoles.GroupDoter = false;
GenerateBaseStats();
@@ -404,8 +406,10 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b
return Result;
}
void Bot::GenerateBaseStats() {
void Bot::GenerateBaseStats()
{
int BotSpellID = 0;
// base stats
uint32 Strength = _baseSTR;
uint32 Stamina = _baseSTA;
@@ -421,24 +425,27 @@ void Bot::GenerateBaseStats() {
int32 PoisonResist = _basePR;
int32 ColdResist = _baseCR;
int32 CorruptionResist = _baseCorrup;
// pulling fixed values from an auto-increment field is dangerous...
switch(this->GetClass()) {
case 1: // Warrior (why not just use 'case WARRIOR:'?)
case WARRIOR:
BotSpellID = 3001;
Strength += 10;
Stamina += 20;
Agility += 10;
Dexterity += 10;
Attack += 12;
break;
case 2: // Cleric
BotSpellID = 701;
case CLERIC:
BotSpellID = 3002;
Strength += 5;
Stamina += 5;
Agility += 10;
Wisdom += 30;
Attack += 8;
break;
case 3: // Paladin
BotSpellID = 708;
case PALADIN:
BotSpellID = 3003;
Strength += 15;
Stamina += 5;
Wisdom += 15;
@@ -446,84 +453,86 @@ void Bot::GenerateBaseStats() {
Dexterity += 5;
Attack += 17;
break;
case 4: // Ranger
BotSpellID = 710;
case RANGER:
BotSpellID = 3004;
Strength += 15;
Stamina += 10;
Agility += 10;
Wisdom += 15;
Attack += 17;
break;
case 5: // Shadowknight
BotSpellID = 709;
case SHADOWKNIGHT:
BotSpellID = 3004;
Strength += 10;
Stamina += 15;
Intelligence += 20;
Charisma += 5;
Attack += 17;
break;
case 6: // Druid
BotSpellID = 707;
case DRUID:
BotSpellID = 3006;
Stamina += 15;
Wisdom += 35;
Attack += 5;
break;
case 7: // Monk
case MONK:
BotSpellID = 3007;
Strength += 5;
Stamina += 15;
Agility += 15;
Dexterity += 15;
Attack += 17;
break;
case 8: // Bard
BotSpellID = 711;
case BARD:
BotSpellID = 3008;
Strength += 15;
Dexterity += 10;
Charisma += 15;
Intelligence += 10;
Attack += 17;
break;
case 9: // Rogue
case ROGUE:
BotSpellID = 3009;
Strength += 10;
Stamina += 20;
Agility += 10;
Dexterity += 10;
Attack += 12;
break;
case 10: // Shaman
BotSpellID = 706;
case SHAMAN:
BotSpellID = 3010;
Stamina += 10;
Wisdom += 30;
Charisma += 10;
Attack += 28;
break;
case 11: // Necromancer
BotSpellID = 703;
case NECROMANCER:
BotSpellID = 3011;
Dexterity += 10;
Agility += 10;
Intelligence += 30;
Attack += 5;
break;
case 12: // Wizard
BotSpellID = 702;
case WIZARD:
BotSpellID = 3012;
Stamina += 20;
Intelligence += 30;
Attack += 5;
break;
case 13: // Magician
BotSpellID = 704;
case MAGICIAN:
BotSpellID = 3013;
Stamina += 20;
Intelligence += 30;
Attack += 5;
break;
case 14: // Enchanter
BotSpellID = 705;
case ENCHANTER:
BotSpellID = 3014;
Intelligence += 25;
Charisma += 25;
Attack += 5;
break;
case 15: // Beastlord
BotSpellID = 712;
case BEASTLORD:
BotSpellID = 3015;
Stamina += 10;
Agility += 10;
Dexterity += 5;
@@ -531,21 +540,24 @@ void Bot::GenerateBaseStats() {
Charisma += 5;
Attack += 31;
break;
case 16: // Berserker
case BERSERKER:
BotSpellID = 3016;
Strength += 10;
Stamina += 15;
Dexterity += 15;
Agility += 10;
Attack += 25;
break;
default:
break;
}
float BotSize = GetSize();
switch(this->GetRace()) {
case 1: // Humans have no race bonus
case HUMAN: // Humans have no race bonus
break;
case 2: // Barbarian
case BARBARIAN:
Strength += 28;
Stamina += 20;
Agility += 7;
@@ -556,7 +568,7 @@ void Bot::GenerateBaseStats() {
BotSize = 7.0;
ColdResist += 10;
break;
case 3: // Erudite
case ERUDITE:
Strength -= 15;
Stamina -= 5;
Agility -= 5;
@@ -567,7 +579,7 @@ void Bot::GenerateBaseStats() {
MagicResist += 5;
DiseaseResist -= 5;
break;
case 4: // Wood Elf
case WOOD_ELF:
Strength -= 10;
Stamina -= 10;
Agility += 20;
@@ -575,7 +587,7 @@ void Bot::GenerateBaseStats() {
Wisdom += 5;
BotSize = 5.0;
break;
case 5: // High Elf
case HIGH_ELF:
Strength -= 20;
Stamina -= 10;
Agility += 10;
@@ -584,7 +596,7 @@ void Bot::GenerateBaseStats() {
Intelligence += 12;
Charisma += 5;
break;
case 6: // Dark Elf
case DARK_ELF:
Strength -= 15;
Stamina -= 10;
Agility += 15;
@@ -593,7 +605,7 @@ void Bot::GenerateBaseStats() {
Charisma -= 15;
BotSize = 5.0;
break;
case 7: // Half Elf
case HALF_ELF:
Strength -= 5;
Stamina -= 5;
Agility += 15;
@@ -601,7 +613,7 @@ void Bot::GenerateBaseStats() {
Wisdom -= 15;
BotSize = 5.5;
break;
case 8: // Dwarf
case DWARF:
Strength += 15;
Stamina += 15;
Agility -= 5;
@@ -613,7 +625,7 @@ void Bot::GenerateBaseStats() {
MagicResist -= 5;
PoisonResist += 5;
break;
case 9: // Troll
case TROLL:
Strength += 33;
Stamina += 34;
Agility += 8;
@@ -623,7 +635,7 @@ void Bot::GenerateBaseStats() {
BotSize = 8.0;
FireResist -= 20;
break;
case 10: // Ogre
case OGRE:
Strength += 55;
Stamina += 77;
Agility -= 5;
@@ -633,7 +645,7 @@ void Bot::GenerateBaseStats() {
Charisma -= 38;
BotSize = 9.0;
break;
case 11: // Halfling
case HALFLING:
Strength -= 5;
Agility += 20;
Dexterity += 15;
@@ -644,7 +656,7 @@ void Bot::GenerateBaseStats() {
PoisonResist += 5;
DiseaseResist += 5;
break;
case 12: // Gnome
case GNOME:
Strength -= 15;
Stamina -= 5;
Agility += 10;
@@ -654,7 +666,7 @@ void Bot::GenerateBaseStats() {
Charisma -= 15;
BotSize = 3.0;
break;
case 128: // Iksar
case IKSAR:
Strength -= 5;
Stamina -= 5;
Agility += 15;
@@ -664,7 +676,7 @@ void Bot::GenerateBaseStats() {
MagicResist -= 5;
FireResist -= 5;
break;
case 130: // Vah Shir
case VAHSHIR:
Strength += 15;
Agility += 15;
Dexterity -= 5;
@@ -675,7 +687,7 @@ void Bot::GenerateBaseStats() {
MagicResist -= 5;
FireResist -= 5;
break;
case 330: // Froglok
case FROGLOK:
Strength -= 5;
Stamina += 5;
Agility += 25;
@@ -685,7 +697,7 @@ void Bot::GenerateBaseStats() {
MagicResist -= 5;
FireResist -= 5;
break;
case 522: // Drakkin
case DRAKKIN:
Strength -= 5;
Stamina += 5;
Agility += 10;
@@ -698,7 +710,10 @@ void Bot::GenerateBaseStats() {
FireResist += 2;
ColdResist += 2;
break;
default:
break;
}
this->STR = Strength;
this->STA = Stamina;
this->DEX = Dexterity;
@@ -2149,7 +2164,7 @@ void Bot::AI_Process() {
} else if(!IsRooted()) {
if(GetTarget() && GetTarget()->GetHateTop() && GetTarget()->GetHateTop() != this) {
Log.Out(Logs::Detail, Logs::AI, "Returning to location prior to being summoned.");
CalculateNewPosition2(m_PreSummonLocation.x, m_PreSummonLocation.y, m_PreSummonLocation.z, GetRunspeed());
CalculateNewPosition2(m_PreSummonLocation.x, m_PreSummonLocation.y, m_PreSummonLocation.z, GetBotRunspeed());
SetHeading(CalculateHeadingToTarget(m_PreSummonLocation.x, m_PreSummonLocation.y));
return;
}
@@ -2224,7 +2239,7 @@ void Bot::AI_Process() {
if(IsMoving()) {
SetHeading(0);
SetRunAnimSpeed(0);
SetCurrentSpeed(GetRunspeed());
SetCurrentSpeed(GetBotRunspeed());
if(moved)
SetCurrentSpeed(0);
}
@@ -2235,17 +2250,17 @@ void Bot::AI_Process() {
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
GetRunspeed(), WaypointChanged, NodeReached);
GetBotRunspeed(), WaypointChanged, NodeReached);
if (WaypointChanged)
tar_ndx = 20;
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotRunspeed());
}
else {
Mob* follow = entity_list.GetMob(GetFollowID());
if (follow)
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), GetRunspeed());
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), GetBotRunspeed());
}
return;
@@ -2335,7 +2350,7 @@ void Bot::AI_Process() {
float newZ = 0;
FaceTarget(GetTarget());
if (PlotPositionAroundTarget(this, newX, newY, newZ)) {
CalculateNewPosition2(newX, newY, newZ, GetRunspeed());
CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed());
return;
}
}
@@ -2347,7 +2362,7 @@ void Bot::AI_Process() {
float newY = 0;
float newZ = 0;
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) {
CalculateNewPosition2(newX, newY, newZ, GetRunspeed());
CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed());
return;
}
}
@@ -2358,7 +2373,7 @@ void Bot::AI_Process() {
float newY = 0;
float newZ = 0;
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) {
CalculateNewPosition2(newX, newY, newZ, GetRunspeed());
CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed());
return;
}
}
@@ -2483,7 +2498,7 @@ void Bot::AI_Process() {
if (AI_movement_timer->Check()) {
if(!IsRooted()) {
Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName());
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetBotRunspeed());
return;
}
@@ -2503,7 +2518,8 @@ void Bot::AI_Process() {
else if(GetArchetype() == ARCHETYPE_CASTER)
BotMeditate(true);
}
} else {
}
else {
SetTarget(nullptr);
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))
SendRemovePlayerState(PlayerState::Aggressive);
@@ -2512,77 +2528,44 @@ void Bot::AI_Process() {
if (!follow)
return;
float cur_dist = DistanceSquared(m_Position, follow->GetPosition());
if (!IsMoving() && cur_dist <= GetFollowDistance()) {
if (AI_think_timer->Check()) {
if (!spellend_timer.Enabled()) {
if (GetBotStance() != BotStancePassive) {
if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD)
BotMeditate(true);
}
else {
if (GetClass() != BARD)
BotMeditate(true);
}
}
if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) {
if (GetBotStance() != BotStancePassive) {
if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD)
BotMeditate(true);
}
else {
if (GetClass() != BARD)
BotMeditate(true);
}
}
else if(AI_movement_timer->Check()) {
// Something is still wrong with bot the follow code...
// Shows up really bad over long distances when movement bonuses are involved
// The flip-side is that too much speed adversely affects node pathing...
if (cur_dist > GetFollowDistance()) {
if (AI_movement_timer->Check()) {
float dist = DistanceSquared(m_Position, follow->GetPosition());
int speed = GetBotRunspeed();
if (dist < GetFollowDistance() + BOT_FOLLOW_DISTANCE_WALK)
speed = GetBotWalkspeed();
SetRunAnimSpeed(0);
if (dist > GetFollowDistance()) {
if (RuleB(Bots, UsePathing) && zone->pathing) {
if (cur_dist <= BOT_FOLLOW_DISTANCE_WALK) {
bool WaypointChanged, NodeReached;
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(follow->GetX(), follow->GetY(), follow->GetZ(),
GetWalkspeed(), WaypointChanged, NodeReached);
glm::vec3 Goal = UpdatePath(follow->GetX(), follow->GetY(), follow->GetZ(),
speed, WaypointChanged, NodeReached);
if (WaypointChanged)
tar_ndx = 20;
if (WaypointChanged)
tar_ndx = 20;
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetWalkspeed());
}
else {
int speed = GetRunspeed();
if (cur_dist > BOT_FOLLOW_DISTANCE_CRITICAL)
speed = ((float)speed * 1.333f); // sprint mod (1/3 boost)
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(follow->GetX(), follow->GetY(), follow->GetZ(),
speed, WaypointChanged, NodeReached);
if (WaypointChanged)
tar_ndx = 20;
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed);
}
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed);
}
else {
if (cur_dist <= BOT_FOLLOW_DISTANCE_WALK) {
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), GetWalkspeed());
}
else {
int speed = GetRunspeed();
if (cur_dist > BOT_FOLLOW_DISTANCE_CRITICAL)
speed = ((float)speed * 1.333f); // sprint mod (1/3 boost)
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
}
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
}
if (rest_timer.Enabled())
rest_timer.Disable();
if (RuleB(Bots, UpdatePositionWithTimer)) { // this helps with rubber-banding effect
if (IsMoving())
SendPosUpdate();
//else
// SendPosition(); // enabled - no discernable difference..disabled - saves on no movement packets
}
}
else {
if (moved) {
@@ -2590,13 +2573,9 @@ void Bot::AI_Process() {
SetCurrentSpeed(0);
}
}
if (GetClass() == BARD && GetBotStance() != BotStancePassive && !spellend_timer.Enabled() && AI_think_timer->Check())
AI_IdleCastCheck();
return;
}
else if (IsMoving()) {
if (IsMoving()) {
if (GetClass() == BARD && GetBotStance() != BotStancePassive && !spellend_timer.Enabled() && AI_think_timer->Check()) {
AI_IdleCastCheck();
}
@@ -6905,6 +6884,8 @@ void Bot::UpdateGroupCastingRoles(const Group* group, bool disband)
if (iter->IsBot()) {
iter->CastToBot()->SetGroupHealer(false);
iter->CastToBot()->SetGroupSlower(false);
iter->CastToBot()->SetGroupNuker(false);
iter->CastToBot()->SetGroupDoter(false);
}
}
@@ -6913,11 +6894,14 @@ void Bot::UpdateGroupCastingRoles(const Group* group, bool disband)
Mob* healer = nullptr;
Mob* slower = nullptr;
Mob* nuker = nullptr;
Mob* doter = nullptr;
for (auto iter : group->members) {
if (!iter)
continue;
// GroupHealer
switch (iter->GetClass()) {
case CLERIC:
if (!healer)
@@ -6966,6 +6950,7 @@ void Bot::UpdateGroupCastingRoles(const Group* group, bool disband)
break;
}
// GroupSlower
switch (iter->GetClass()) {
case SHAMAN:
if (!slower)
@@ -6997,14 +6982,43 @@ void Bot::UpdateGroupCastingRoles(const Group* group, bool disband)
default:
break;
}
// GroupNuker
switch (iter->GetClass()) {
// wizard
// magician
// necromancer
// enchanter
// druid
// cleric
// shaman
// shadowknight
// paladin
// ranger
// beastlord
default:
break;
}
// GroupDoter
switch (iter->GetClass()) {
default:
break;
}
}
if (healer && healer->IsBot())
healer->CastToBot()->SetGroupHealer();
if (slower && slower->IsBot())
slower->CastToBot()->SetGroupSlower();
if (nuker && nuker->IsBot())
nuker->CastToBot()->SetGroupNuker();
if (doter && doter->IsBot())
doter->CastToBot()->SetGroupDoter();
}
//void Bot::UpdateRaidCastingRoles(const Raid* raid, bool disband = false) { }
bool Bot::CanHeal() {
bool result = false;
@@ -7024,10 +7038,6 @@ bool Bot::CanHeal() {
return result;
}
bool Bot::CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ) {
return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ);
}
Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) {
Bot* Result = 0;
if(c) {
@@ -7776,6 +7786,23 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
}
}
if (iSpellTypes == SpellType_PreCombatBuff) {
if (botCasterClass == BARD || caster->IsEngaged())
return false;
if (caster->HasGroup()) {
Group *g = caster->GetGroup();
if (g) {
for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (g->members[i]) {
if (caster->AICastSpell(g->members[i], iChance, SpellType_PreCombatBuff) || caster->AICastSpell(g->members[i]->GetPet(), iChance, SpellType_PreCombatBuff))
return true;
}
}
}
}
}
return false;
}
+56 -5
View File
@@ -40,8 +40,7 @@
#define BOT_FOLLOW_DISTANCE_DEFAULT 184 // as DSq value (~13.565 units)
#define BOT_FOLLOW_DISTANCE_DEFAULT_MAX 2500 // as DSq value (50 units)
#define BOT_FOLLOW_DISTANCE_WALK 400 // as DSq value (20 units)
#define BOT_FOLLOW_DISTANCE_CRITICAL 22500 // as DSq value (150 units)
#define BOT_FOLLOW_DISTANCE_WALK 1000 // as DSq value (~31.623 units)
extern WorldServer worldserver;
@@ -132,11 +131,48 @@ enum SpellTypeIndex {
SpellType_HateReduxIndex,
SpellType_InCombatBuffSongIndex,
SpellType_OutOfCombatBuffSongIndex,
SpellType_PreCombatBuffIndex,
SpellType_PreCombatBuffSongIndex,
MaxSpellTypes
};
// negative Healer/Slower, positive Healer, postive Slower, positive Healer/Slower
enum BotCastingChanceConditional : uint8 { nHS = 0, pH, pS, pHS, cntHS = 4 };
// nHSND negative Healer/Slower/Nuker/Doter
// pH positive Healer
// pS positive Slower
// pHS positive Healer/Slower
// pN positive Nuker
// pHN positive Healer/Nuker
// pSN positive Slower/Nuker
// pHSN positive Healer/Slower/Nuker
// pD positive Doter
// pHD positive Healer/Doter
// pSD positive Slower/Doter
// pHSD positive Healer/Slower/Doter
// pND positive Nuker/Doter
// pHND positive Healer/Nuker/Doter
// pSND positive Slower/Nuker/Doter
// pHSND positive Healer/Slower/Nuker/Doter
// cntHSND count Healer/Slower/Nuker/Doter
enum BotCastingChanceConditional : uint8
{
nHSND = 0,
pH,
pS,
pHS,
pN,
pHN,
pSN,
pHSN,
pD,
pHD,
pSD,
pHSD,
pND,
pHND,
pSND,
pHSND,
cntHSND = 16
};
class Bot : public NPC {
@@ -299,8 +335,9 @@ public:
void Stand();
bool IsSitting();
bool IsStanding();
int GetBotWalkspeed() const { return (int)((float)_GetWalkSpeed() * 1.786f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
int GetBotRunspeed() const { return (int)((float)_GetRunSpeed() * 1.786f); }
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);
@@ -482,8 +519,16 @@ public:
bool IsGroupHealer() { return m_CastingRoles.GroupHealer; }
bool IsGroupSlower() { return m_CastingRoles.GroupSlower; }
bool IsGroupNuker() { return m_CastingRoles.GroupNuker; }
bool IsGroupDoter() { return m_CastingRoles.GroupDoter; }
static void UpdateGroupCastingRoles(const Group* group, bool disband = false);
//bool IsRaidHealer() { return m_CastingRoles.RaidHealer; }
//bool IsRaidSlower() { return m_CastingRoles.RaidSlower; }
//bool IsRaidNuker() { return m_CastingRoles.RaidNuker; }
//bool IsRaidDoter() { return m_CastingRoles.RaidDoter; }
//static void UpdateRaidCastingRoles(const Raid* raid, bool disband = false);
bool IsBotCaster() { return IsCasterClass(GetClass()); }
bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); }
bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); }
@@ -650,6 +695,12 @@ protected:
BotCastingRoles& GetCastingRoles() { return m_CastingRoles; }
void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; }
void SetGroupSlower(bool flag = true) { m_CastingRoles.GroupSlower = flag; }
void SetGroupNuker(bool flag = true) { m_CastingRoles.GroupNuker = flag; }
void SetGroupDoter(bool flag = true) { m_CastingRoles.GroupDoter = flag; }
//void SetRaidHealer(bool flag = true) { m_CastingRoles.RaidHealer = flag; }
//void SetRaidSlower(bool flag = true) { m_CastingRoles.RaidSlower = flag; }
//void SetRaidNuker(bool flag = true) { m_CastingRoles.RaidNuker = flag; }
//void SetRaidDoter(bool flag = true) { m_CastingRoles.RaidDoter = flag; }
private:
// Class Members
+2
View File
@@ -5151,6 +5151,7 @@ void bot_subcommand_bot_summon(Client *c, const Seperator *sep)
bot_iter->WipeHateList();
bot_iter->SetTarget(bot_iter->GetBotOwner());
bot_iter->Warp(glm::vec3(c->GetPosition()));
bot_iter->DoAnim(0);
if (!bot_iter->HasPet())
continue;
@@ -5399,6 +5400,7 @@ void bot_subcommand_bot_update(Client *c, const Seperator *sep)
bot_iter->SetPetChooser(false);
bot_iter->CalcBotStats((sbl.size() == 1));
bot_iter->SendAppearancePacket(AT_WhoLevel, bot_iter->GetLevel(), true, true);
++bot_count;
}
+34 -18
View File
@@ -82,7 +82,7 @@ bool BotDatabase::LoadBotCommandSettings(std::map<std::string, std::pair<uint8,
return true;
}
static uint8 spell_casting_chances[MaxSpellTypes][PLAYER_CLASS_COUNT][MaxStances][cntHS];
static uint8 spell_casting_chances[MaxSpellTypes][PLAYER_CLASS_COUNT][MaxStances][cntHSND];
bool BotDatabase::LoadBotSpellCastingChances()
{
@@ -91,17 +91,29 @@ bool BotDatabase::LoadBotSpellCastingChances()
query =
"SELECT"
" `spell_type_index`,"
" `class_index`,"
" `class_id`,"
" `stance_index`,"
" `conditional_index`,"
" `value` "
" `nHSND_value`,"
" `pH_value`,"
" `pS_value`,"
" `pHS_value`,"
" `pN_value`,"
" `pHN_value`,"
" `pSN_value`,"
" `pHSN_value`,"
" `pD_value`,"
" `pHD_value`,"
" `pSD_value`,"
" `pHSD_value`,"
" `pND_value`,"
" `pHND_value`,"
" `pSND_value`,"
" `pHSND_value`"
"FROM"
" `bot_spell_casting_chances` "
"WHERE"
" `value` != '0'";
" `bot_spell_casting_chances`";
auto results = QueryDatabase(query);
if (!results.Success())
if (!results.Success() || !results.RowCount())
return false;
for (auto row = results.begin(); row != results.end(); ++row) {
@@ -109,18 +121,22 @@ bool BotDatabase::LoadBotSpellCastingChances()
if (spell_type_index >= MaxSpellTypes)
continue;
uint8 class_index = atoi(row[1]);
if (class_index >= PLAYER_CLASS_COUNT)
if (class_index < WARRIOR || class_index > BERSERKER)
continue;
--class_index;
uint8 stance_index = atoi(row[2]);
if (stance_index >= MaxStances)
continue;
uint8 conditional_index = atoi(row[3]);
if (conditional_index >= cntHS)
continue;
uint8 value = atoi(row[4]);
if (value > 100)
value = 100;
spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index] = value;
for (uint8 conditional_index = nHSND; conditional_index < cntHSND; ++conditional_index) {
uint8 value = atoi(row[3 + conditional_index]);
if (!value)
continue;
if (value > 100)
value = 100;
spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index] = value;
}
}
return true;
@@ -2761,7 +2777,7 @@ bool BotDatabase::DeleteAllHealRotations(const uint32 owner_id)
/* Bot miscellaneous functions */
uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_index, uint8 stance_index, uint8 conditional_index)
uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_index, uint8 stance_index, uint8 conditional_index) // class_index is 0-based
{
if (spell_type_index >= MaxSpellTypes)
return 0;
@@ -2769,7 +2785,7 @@ uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_ind
return 0;
if (stance_index >= MaxStances)
return 0;
if (conditional_index >= cntHS)
if (conditional_index >= cntHSND)
return 0;
return spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index];
+6
View File
@@ -63,6 +63,12 @@ struct BotSpell_wPriority : public BotSpell {
struct BotCastingRoles {
bool GroupHealer;
bool GroupSlower;
bool GroupNuker;
bool GroupDoter;
//bool RaidHealer;
//bool RaidSlower;
//bool RaidNuker;
//bool RaidDoter;
};
struct BotAA {
+103 -30
View File
@@ -1046,6 +1046,12 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
break;
}
case SpellType_PreCombatBuff: {
break;
}
case SpellType_PreCombatBuffSong: {
break;
}
default:
break;
}
@@ -1163,16 +1169,28 @@ bool Bot::AI_IdleCastCheck() {
#endif
AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting.
//Ok, IdleCastCheck depends of class.
// Healers WITHOUT pets will check if a heal is needed before buffing.
uint8 botClass = GetClass();
bool pre_combat = false;
Mob* test_against = nullptr;
if(botClass == CLERIC || botClass == PALADIN || botClass == RANGER) {
if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (HasGroup() && GetGroup()->GetLeader() && GetGroup()->GetLeader()->IsClient())
test_against = GetGroup()->GetLeader();
else if (GetOwner() && GetOwner()->IsClient())
test_against = GetOwner();
if (test_against && test_against->GetTarget() && test_against->GetTarget()->IsNPC() && !test_against->GetTarget()->IsPet())
pre_combat = true;
//Ok, IdleCastCheck depends of class.
switch (GetClass()) {
// Healers WITHOUT pets will check if a heal is needed before buffing.
case CLERIC:
case PALADIN:
case RANGER: {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Heal)) {
if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
if (!AICastSpell(this, 100, SpellType_Buff)) {
if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Buff)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Buff)) {
//
}
}
@@ -1181,16 +1199,23 @@ bool Bot::AI_IdleCastCheck() {
}
result = true;
break;
}
// Pets class will first cast their pet, then buffs
else if(botClass == DRUID || botClass == MAGICIAN || botClass == SHADOWKNIGHT || botClass == SHAMAN || botClass == NECROMANCER || botClass == ENCHANTER || botClass == BEASTLORD || botClass == WIZARD) {
if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
case DRUID:
case MAGICIAN:
case SHADOWKNIGHT:
case SHAMAN:
case NECROMANCER:
case ENCHANTER:
case BEASTLORD: {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Heal)) {
if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
if (!AICastSpell(this, 100, SpellType_Buff)) {
if (!AICastSpell(GetPet(), 100, SpellType_Heal)) {
if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Buff)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Buff)) {
//
}
}
@@ -1201,23 +1226,57 @@ bool Bot::AI_IdleCastCheck() {
}
result = true;
break;
}
else if(botClass == BARD) {
// bard bots
bool battle_prep = false;
Mob* prep_against = nullptr;
if (HasGroup() && GetGroup()->GetLeader() && GetGroup()->GetLeader()->IsClient())
prep_against = GetGroup()->GetLeader();
else if (GetOwner() && GetOwner()->IsClient())
prep_against = GetOwner();
if (prep_against && prep_against->GetTarget() && prep_against->GetTarget()->IsNPC() && !prep_against->GetTarget()->IsPet())
battle_prep = true;
if (battle_prep) {
if (!AICastSpell(this, 100, SpellType_InCombatBuffSong)) {
//
case WIZARD: { // This can eventually be move into the BEASTLORD case handler once pre-combat is fully implemented
if (pre_combat) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
if (!AICastSpell(this, 100, SpellType_Buff)) {
if (!AICastSpell(GetPet(), 100, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_PreCombatBuff)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Buff)) {
//
}
}
}
}
}
}
}
}
}
else {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
if (!AICastSpell(this, 100, SpellType_Buff)) {
if (!AICastSpell(GetPet(), 100, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Buff)) {
//
}
}
}
}
}
}
}
}
result = true;
break;
}
case BARD: {
if (pre_combat) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_PreCombatBuffSong)) {
if (!AICastSpell(this, 100, SpellType_InCombatBuffSong)) {
//
}
}
}
}
else {
@@ -1229,6 +1288,10 @@ bool Bot::AI_IdleCastCheck() {
}
result = true;
break;
}
default:
break;
}
if(!AIautocastspell_timer->Enabled())
@@ -2572,6 +2635,12 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
case SpellType_OutOfCombatBuffSong:
spell_type_index = SpellType_OutOfCombatBuffSongIndex;
break;
case SpellType_PreCombatBuff:
spell_type_index = SpellType_PreCombatBuffIndex;
break;
case SpellType_PreCombatBuffSong:
spell_type_index = SpellType_PreCombatBuffSongIndex;
break;
default:
spell_type_index = MaxSpellTypes;
break;
@@ -2588,12 +2657,16 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
if (stance_index >= MaxStances)
return 0;
uint8 type_index = nHS;
uint8 type_index = nHSND;
if (HasGroup()) {
if (IsGroupHealer())
if (IsGroupHealer()/* || IsRaidHealer()*/)
type_index |= pH;
if (IsGroupSlower())
if (IsGroupSlower()/* || IsRaidSlower()*/)
type_index |= pS;
if (IsGroupNuker()/* || IsRaidNuker()*/)
type_index |= pN;
if (IsGroupDoter()/* || IsRaidDoter()*/)
type_index |= pD;
}
return botdb.GetSpellCastingChance(spell_type_index, class_index, stance_index, type_index);
+14 -14
View File
@@ -5912,20 +5912,20 @@ void Client::SendGroupCreatePacket()
char *Buffer = (char *)outapp->pBuffer;
// Header
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // Null Leader name
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // group ID probably
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); // count of members in packet
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // Null Leader name, shouldn't be null besides this case
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // Member 0
VARSTRUCT_ENCODE_STRING(Buffer, GetName());
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, GetLevel());
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // Member 0, index
VARSTRUCT_ENCODE_STRING(Buffer, GetName()); // group member name
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0); // merc flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // owner name (if merc)
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, GetLevel()); // level
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group tank flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group assist flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group puller flag
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // offline flag
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // timestamp
FastQueuePacket(&outapp);
}
@@ -8823,7 +8823,7 @@ void Client::ProcessAggroMeter()
secondary = cur_tar->GetSecondaryHate(this);
has_aggro = true;
} else {
secondary = cur_tar->GetTarget();
secondary = cur_tar->CheckAggro(cur_tar->GetTarget()) ? cur_tar->GetTarget() : nullptr; // make sure they are targeting for aggro reasons
}
}
+2 -1
View File
@@ -255,6 +255,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
item->attuned = 0;
item->min_level = minlevel;
item->max_level = maxlevel;
item->equip_slot = EQEmu::inventory::slotInvalid;
if (equipit) {
uint8 eslot = 0xFF;
@@ -399,8 +400,8 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
}
if (found) {
CalcBonuses(); // This is less than ideal for bulk adding of items
item->equip_slot = foundslot;
}
item->equip_slot = item2->Slots;
}
if(itemlist != nullptr)
+18 -1
View File
@@ -614,7 +614,11 @@ int Mob::_GetWalkSpeed() const {
return(0);
//runspeed cap.
#ifdef BOTS
if (IsClient() || IsBot())
#else
if(IsClient())
#endif
{
if(speed_mod > runspeedcap)
speed_mod = runspeedcap;
@@ -673,7 +677,11 @@ int Mob::_GetRunSpeed() const {
if (!has_horse && movemod != 0)
{
#ifdef BOTS
if (IsClient() || IsBot())
#else
if (IsClient())
#endif
{
speed_mod += (speed_mod * movemod / 100);
} else {
@@ -702,7 +710,11 @@ int Mob::_GetRunSpeed() const {
return(0);
}
//runspeed cap.
#ifdef BOTS
if (IsClient() || IsBot())
#else
if(IsClient())
#endif
{
if(speed_mod > runspeedcap)
speed_mod = runspeedcap;
@@ -1459,10 +1471,15 @@ void Mob::MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu) {
spu->padding0006 =7;
spu->padding0014 =0x7f;
spu->padding0018 =0x5df27;
#ifdef BOTS
if (this->IsClient() || this->IsBot())
#else
if(this->IsClient())
#endif
spu->animation = animation;
else
spu->animation = pRunAnimSpeed;//animation;
spu->animation = pRunAnimSpeed;//animation;
spu->delta_heading = NewFloatToEQ13(m_Delta.w);
}
+2 -1
View File
@@ -2606,11 +2606,12 @@ DBnpcspells_Struct* ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) {
uint32 tmpidle_no_sp_recast_max = atoi(row[18]);
uint8 tmpidle_b_chance = atoi(row[19]);
// pulling fixed values from an auto-increment field is dangerous...
query = StringFormat("SELECT spellid, type, minlevel, maxlevel, "
"manacost, recast_delay, priority, resist_adjust "
#ifdef BOTS
"FROM %s "
"WHERE npc_spells_id=%d ORDER BY minlevel", (iDBSpellsID >= 701 && iDBSpellsID <= 712 ? "bot_spells_entries" : "npc_spells_entries"), iDBSpellsID);
"WHERE npc_spells_id=%d ORDER BY minlevel", (iDBSpellsID >= 3001 && iDBSpellsID <= 3016 ? "bot_spells_entries" : "npc_spells_entries"), iDBSpellsID);
#else
"FROM npc_spells_entries "
"WHERE npc_spells_id=%d ORDER BY minlevel", iDBSpellsID);
+4
View File
@@ -567,7 +567,11 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_TargetV.z = z - nz;
SetCurrentSpeed((int8)speed);
pRunAnimSpeed = speed;
#ifdef BOTS
if(IsClient() || IsBot())
#else
if(IsClient())
#endif
{
animation = speed / 2;
}