mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-27 22:05:54 +00:00
Merge pull request #2172 from mod-playerbots/test-staging
Update master from Test staging and Core Update
This commit is contained in:
18
.github/workflows/codestyle_cpp.yml
vendored
18
.github/workflows/codestyle_cpp.yml
vendored
@@ -6,10 +6,6 @@ on:
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
paths:
|
||||
- src/**
|
||||
- "!README.md"
|
||||
- "!docs/**"
|
||||
|
||||
concurrency:
|
||||
group: "codestyle-cppcheck-${{ github.event.pull_request.number }}"
|
||||
@@ -22,13 +18,27 @@ jobs:
|
||||
if: github.event.pull_request.draft == false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
cpp:
|
||||
- 'src/**'
|
||||
- '!README.md'
|
||||
- '!docs/**'
|
||||
|
||||
- name: Setup python
|
||||
if: steps.filter.outputs.cpp == 'true'
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: AzerothCore codestyle
|
||||
if: steps.filter.outputs.cpp == 'true'
|
||||
run: python ./apps/codestyle/codestyle-cpp.py
|
||||
|
||||
- name: C++ Advanced
|
||||
if: steps.filter.outputs.cpp == 'true'
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt install -y cppcheck
|
||||
|
||||
@@ -192,9 +192,12 @@ AiPlayerbot.AutoInitOnly = 0
|
||||
# Default: 1.0 (same with the player)
|
||||
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
|
||||
|
||||
# Bot automatically trains spells when talking to trainer
|
||||
# yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells
|
||||
AiPlayerbot.AutoTrainSpells = yes
|
||||
#
|
||||
# AllowLearnTrainerSpells
|
||||
# Description: Allow the bot to learn trainers' spells as long as it has the money.
|
||||
# Default: 1 - (Enabled)
|
||||
# 0 - (Disabled)
|
||||
AiPlayerbot.AllowLearnTrainerSpells = 1
|
||||
|
||||
#
|
||||
#
|
||||
@@ -563,6 +566,34 @@ AiPlayerbot.AutoGearScoreLimit = 0
|
||||
# Default: food, taxi, and raid are enabled
|
||||
AiPlayerbot.BotCheats = "food,taxi,raid"
|
||||
|
||||
# Attunement quests (comma-separated list of quest IDs)
|
||||
# Default:
|
||||
# Caverns of Time - Part 1
|
||||
# - 10279, To The Master's Lair
|
||||
# - 10277, The Caverns of Time
|
||||
#
|
||||
# Caverns of Time - Part 2 (Escape from Durnholde Keep)
|
||||
# - 10282, Old Hillsbrad
|
||||
# - 10283, Taretha's Diversion
|
||||
# - 10284, Escape from Durnholde
|
||||
# - 10285, Return to Andormu
|
||||
#
|
||||
# Caverns of Time - Part 2 (The Black Morass)
|
||||
# - 10296, The Black Morass
|
||||
# - 10297, The Opening of the Dark Portal
|
||||
# - 10298, Hero of the Brood
|
||||
#
|
||||
# Magister's Terrace Attunement
|
||||
# - 11481, Crisis at the Sunwell
|
||||
# - 11482, Duty Calls
|
||||
# - 11488, Magisters' Terrace
|
||||
# - 11490, The Scryer's Scryer
|
||||
# - 11492, Hard to Kill
|
||||
#
|
||||
# Serpentshrine Cavern
|
||||
# - 10901, The Cudgel of Kar'desh
|
||||
AiPlayerbot.AttunementQuests = 10279,10277,10282,10283,10284,10285,10296,10297,10298,11481,11482,11488,11490,11492,10901
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
@@ -125,6 +125,7 @@ public:
|
||||
creators["runaway"] = &ActionContext::runaway;
|
||||
creators["stay"] = &ActionContext::stay;
|
||||
creators["sit"] = &ActionContext::sit;
|
||||
creators["aggressive target"] = &ActionContext::aggressive_target;
|
||||
creators["attack anything"] = &ActionContext::attack_anything;
|
||||
creators["attack least hp target"] = &ActionContext::attack_least_hp_target;
|
||||
creators["attack enemy player"] = &ActionContext::attack_enemy_player;
|
||||
@@ -315,6 +316,7 @@ private:
|
||||
static Action* suggest_what_to_do(PlayerbotAI* botAI) { return new SuggestWhatToDoAction(botAI); }
|
||||
static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); }
|
||||
static Action* suggest_dungeon(PlayerbotAI* botAI) { return new SuggestDungeonAction(botAI); }
|
||||
static Action* aggressive_target(PlayerbotAI* botAI) { return new AggressiveTargetAction(botAI); }
|
||||
static Action* attack_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); }
|
||||
static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); }
|
||||
static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); }
|
||||
|
||||
@@ -30,6 +30,14 @@ bool AttackEnemyFlagCarrierAction::isUseful()
|
||||
PlayerHasFlag::IsCapturingFlag(bot);
|
||||
}
|
||||
|
||||
bool AggressiveTargetAction::isUseful()
|
||||
{
|
||||
if (bot->IsInCombat())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DropTargetAction::Execute(Event /*event*/)
|
||||
{
|
||||
Unit* target = context->GetValue<Unit*>("current target")->Get();
|
||||
|
||||
@@ -35,6 +35,15 @@ public:
|
||||
std::string const GetTargetName() override { return "tank target"; }
|
||||
};
|
||||
|
||||
class AggressiveTargetAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AggressiveTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "aggressive target") {}
|
||||
|
||||
std::string const GetTargetName() override { return "aggressive target"; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class AttackAnythingAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -7,10 +7,13 @@
|
||||
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
#include "InstancePackets.h"
|
||||
|
||||
bool ResetInstancesAction::Execute(Event /*event*/)
|
||||
{
|
||||
WorldPacket packet(CMSG_RESET_INSTANCES, 0);
|
||||
bot->GetSession()->HandleResetInstancesOpcode(packet);
|
||||
WorldPackets::Instance::ResetInstances resetInstance(std::move(packet));
|
||||
bot->GetSession()->HandleResetInstancesOpcode(resetInstance);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "RpgSubActions.h"
|
||||
|
||||
#include "BudgetValues.h"
|
||||
#include "ChooseRpgTargetAction.h"
|
||||
#include "EmoteAction.h"
|
||||
#include "Formations.h"
|
||||
@@ -51,10 +52,15 @@ GuidPosition RpgHelper::guidP() { return AI_VALUE(GuidPosition, "rpg target"); }
|
||||
|
||||
ObjectGuid RpgHelper::guid() { return (ObjectGuid)guidP(); }
|
||||
|
||||
bool RpgHelper::InRange()
|
||||
{
|
||||
return guidP() ? (guidP().sqDistance2d(bot) < INTERACTION_DISTANCE * INTERACTION_DISTANCE) : false;
|
||||
}
|
||||
bool RpgHelper::InRange()
|
||||
{
|
||||
GuidPosition targetGuid = guidP();
|
||||
if (!targetGuid)
|
||||
return false;
|
||||
|
||||
return bot->GetExactDist2dSq(targetGuid.GetPositionX(), targetGuid.GetPositionY()) <
|
||||
INTERACTION_DISTANCE * INTERACTION_DISTANCE;
|
||||
}
|
||||
|
||||
void RpgHelper::setFacingTo(GuidPosition guidPosition)
|
||||
{
|
||||
@@ -250,6 +256,60 @@ Event RpgSellAction::ActionEvent(Event /*event*/) { return Event("rpg action", "
|
||||
|
||||
std::string const RpgRepairAction::ActionName() { return "repair"; }
|
||||
|
||||
bool RpgTrainAction::isUseful()
|
||||
{
|
||||
if (!rpg->InRange())
|
||||
return false;
|
||||
|
||||
Creature* creature = rpg->guidP().GetCreature();
|
||||
if (!creature)
|
||||
return false;
|
||||
|
||||
if (!creature->IsInWorld() || creature->IsDuringRemoveFromWorld() || !creature->IsAlive())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RpgTrainAction::isPossible()
|
||||
{
|
||||
GuidPosition gp = rpg->guidP();
|
||||
|
||||
CreatureTemplate const* cinfo = gp.GetCreatureTemplate();
|
||||
if (!cinfo)
|
||||
return false;
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cinfo->Entry);
|
||||
if (!trainer)
|
||||
return false;
|
||||
|
||||
if (!trainer->IsTrainerValidForPlayer(bot))
|
||||
return false;
|
||||
|
||||
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cinfo->faction);
|
||||
float reputationDiscount = bot->GetReputationPriceDiscount(factionTemplate);
|
||||
uint32 currentGold = AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells);
|
||||
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
Trainer::Spell const* trainerSpell = trainer->GetSpell(spell.SpellId);
|
||||
if (!trainerSpell)
|
||||
continue;
|
||||
|
||||
if (!trainer->CanTeachSpell(bot, trainerSpell))
|
||||
continue;
|
||||
|
||||
if (currentGold < static_cast<uint32>(floor(trainerSpell->MoneyCost * reputationDiscount)))
|
||||
continue;
|
||||
|
||||
// we only check if at least one spell can be learned from the trainer;
|
||||
// otherwise, the train action should not be allowed
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string const RpgTrainAction::ActionName() { return "trainer"; }
|
||||
|
||||
bool RpgHealAction::Execute(Event /*event*/)
|
||||
|
||||
@@ -165,6 +165,9 @@ class RpgTrainAction : public RpgSubAction
|
||||
public:
|
||||
RpgTrainAction(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgSubAction(botAI, name) {}
|
||||
|
||||
bool isPossible() override;
|
||||
bool isUseful() override;
|
||||
|
||||
private:
|
||||
std::string const ActionName() override;
|
||||
};
|
||||
|
||||
@@ -9,77 +9,120 @@
|
||||
#include "Event.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Trainer.h"
|
||||
|
||||
void TrainerAction::Learn(uint32 cost, const Trainer::Spell tSpell, std::ostringstream& msg)
|
||||
bool TrainerAction::Execute(Event event)
|
||||
{
|
||||
if (sPlayerbotAIConfig.autoTrainSpells != "free" && !botAI->HasCheat(BotCheatMask::gold))
|
||||
{
|
||||
if (AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells) < cost)
|
||||
{
|
||||
msg << " - too expensive";
|
||||
return;
|
||||
}
|
||||
std::string const param = event.getParam();
|
||||
|
||||
bot->ModifyMoney(-int32(cost));
|
||||
}
|
||||
Creature* target = GetCreatureTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell.SpellId);
|
||||
if (!spellInfo)
|
||||
return;
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(target->GetEntry());
|
||||
if (!trainer)
|
||||
return false;
|
||||
|
||||
bool learned = false;
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
{
|
||||
if (spellInfo->Effects[j].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
{
|
||||
uint32 learnedSpell = spellInfo->Effects[j].TriggerSpell;
|
||||
if (!bot->HasSpell(learnedSpell))
|
||||
{
|
||||
bot->learnSpell(learnedSpell);
|
||||
learned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: Original version uses SpellIds here, but occasionally only inserts
|
||||
// a single spell ID value from parameters. If someone wants to impl multiple
|
||||
// spells as parameters, check SkipSpellsListAction::parseIds as an example.
|
||||
uint32 spellId = chat->parseSpell(param);
|
||||
|
||||
if (!learned && !bot->HasSpell(tSpell.SpellId))
|
||||
bot->learnSpell(tSpell.SpellId);
|
||||
bool learnSpells = param.find("learn") != std::string::npos || sRandomPlayerbotMgr.IsRandomBot(bot) ||
|
||||
(sPlayerbotAIConfig.allowLearnTrainerSpells &&
|
||||
// TODO: Rewrite to only exclude start primary profession skills and make config dependent.
|
||||
(trainer->GetTrainerType() != Trainer::Type::Tradeskill || !botAI->HasActivePlayerMaster()));
|
||||
|
||||
msg << " - learned";
|
||||
Iterate(target, learnSpells, spellId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TrainerAction::Iterate(Creature* creature, TrainerSpellAction action, SpellIds& spells)
|
||||
bool TrainerAction::isUseful()
|
||||
{
|
||||
Creature* target = GetCreatureTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (!target->IsInWorld() || target->IsDuringRemoveFromWorld() || !target->IsAlive())
|
||||
return false;
|
||||
|
||||
return target->IsTrainer();
|
||||
}
|
||||
|
||||
bool TrainerAction::isPossible()
|
||||
{
|
||||
Creature* target = GetCreatureTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(target->GetEntry());
|
||||
if (!trainer)
|
||||
return false;
|
||||
|
||||
if (!trainer->IsTrainerValidForPlayer(bot))
|
||||
return false;
|
||||
|
||||
if (trainer->GetSpells().empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* TrainerAction::GetTarget()
|
||||
{
|
||||
// There are just two scenarios: the bot has a master or it doesn't. If the
|
||||
// bot has a master, the master should target a unit; otherwise, the bot
|
||||
// should target the unit itself.
|
||||
if (Player* master = GetMaster())
|
||||
return master->GetSelectedUnit();
|
||||
|
||||
return bot->GetSelectedUnit();
|
||||
}
|
||||
|
||||
Creature* TrainerAction::GetCreatureTarget()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
return target ? target->ToCreature() : nullptr;
|
||||
}
|
||||
|
||||
void TrainerAction::Iterate(Creature* creature, bool learnSpells, uint32 spellId)
|
||||
{
|
||||
TellHeader(creature);
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(creature->GetEntry());
|
||||
|
||||
if (!trainer)
|
||||
return;
|
||||
|
||||
float fDiscountMod = bot->GetReputationPriceDiscount(creature);
|
||||
float reputationDiscount = bot->GetReputationPriceDiscount(creature);
|
||||
uint32 totalCost = 0;
|
||||
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
||||
// simplified version of Trainer::TeachSpell method
|
||||
|
||||
Trainer::Spell const* trainerSpell = trainer->GetSpell(spell.SpellId);
|
||||
if (!trainerSpell)
|
||||
continue;
|
||||
|
||||
if (!spells.empty() && spells.find(spell.SpellId) == spells.end())
|
||||
if (!trainer->CanTeachSpell(bot, trainerSpell))
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell.SpellId);
|
||||
if (spellId && trainerSpell->SpellId != spellId)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(trainerSpell->SpellId);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
uint32 cost = uint32(floor(spell.MoneyCost * fDiscountMod));
|
||||
uint32 cost = static_cast<uint32>(floor(trainerSpell->MoneyCost * reputationDiscount));
|
||||
totalCost += cost;
|
||||
|
||||
std::ostringstream out;
|
||||
out << chat->FormatSpell(spellInfo) << chat->formatMoney(cost);
|
||||
|
||||
if (action)
|
||||
(this->*action)(cost, spell, out);
|
||||
if (learnSpells)
|
||||
Learn(spellInfo, cost, out);
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
@@ -87,55 +130,25 @@ void TrainerAction::Iterate(Creature* creature, TrainerSpellAction action, Spell
|
||||
TellFooter(totalCost);
|
||||
}
|
||||
|
||||
bool TrainerAction::Execute(Event event)
|
||||
void TrainerAction::Learn(SpellInfo const* spellInfo, uint32 cost, std::ostringstream& out)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
|
||||
Player* master = GetMaster();
|
||||
|
||||
Creature* creature = botAI->GetCreature(bot->GetTarget());
|
||||
|
||||
if (master)
|
||||
if (!botAI->HasCheat(BotCheatMask::gold))
|
||||
{
|
||||
creature = master->GetSelectedUnit() ? master->GetSelectedUnit()->ToCreature() : nullptr;
|
||||
}
|
||||
// if (AI_VALUE(GuidPosition, "rpg target") != bot->GetTarget())
|
||||
// if (master)
|
||||
// creature = botAI->GetCreature(master->GetTarget());
|
||||
// else
|
||||
// return false;
|
||||
if (AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells) < cost)
|
||||
{
|
||||
out << " - too expensive";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!creature || !creature->IsTrainer())
|
||||
return false;
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(creature->GetEntry());
|
||||
|
||||
if (!trainer || !trainer->IsTrainerValidForPlayer(bot))
|
||||
return false;
|
||||
|
||||
std::vector<Trainer::Spell> trainer_spells = trainer->GetSpells();
|
||||
|
||||
if (trainer_spells.empty())
|
||||
{
|
||||
botAI->TellError("No spells can be learned from this trainer");
|
||||
return false;
|
||||
bot->ModifyMoney(-static_cast<int32>(cost));
|
||||
}
|
||||
|
||||
uint32 spell = chat->parseSpell(text);
|
||||
SpellIds spells;
|
||||
if (spell)
|
||||
spells.insert(spell);
|
||||
|
||||
if (text.find("learn") != std::string::npos || sRandomPlayerbotMgr.IsRandomBot(bot) ||
|
||||
(sPlayerbotAIConfig.autoTrainSpells != "no" &&
|
||||
(trainer->GetTrainerType() != Trainer::Type::Tradeskill ||
|
||||
!botAI->HasActivePlayerMaster()))) // Todo rewrite to only exclude start primary profession skills and make
|
||||
// config dependent.
|
||||
Iterate(creature, &TrainerAction::Learn, spells);
|
||||
if (spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
|
||||
bot->CastSpell(bot, spellInfo->Id, true);
|
||||
else
|
||||
Iterate(creature, nullptr, spells);
|
||||
bot->learnSpell(spellInfo->Id, false);
|
||||
|
||||
return true;
|
||||
out << " - learned";
|
||||
}
|
||||
|
||||
void TrainerAction::TellHeader(Creature* creature)
|
||||
@@ -245,7 +258,8 @@ bool MaintenanceAction::Execute(Event /*event*/)
|
||||
if (sPlayerbotAIConfig.altMaintenanceKeyring)
|
||||
factory.InitKeyring();
|
||||
|
||||
if (sPlayerbotAIConfig.altMaintenanceGemsEnchants && bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel)
|
||||
if (sPlayerbotAIConfig.altMaintenanceGemsEnchants &&
|
||||
bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel)
|
||||
factory.ApplyEnchantAndGemsNew();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "Action.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Trainer.h"
|
||||
|
||||
class Creature;
|
||||
class PlayerbotAI;
|
||||
@@ -21,11 +20,14 @@ public:
|
||||
TrainerAction(PlayerbotAI* botAI) : Action(botAI, "trainer") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
bool isPossible() override;
|
||||
Unit* GetTarget() override;
|
||||
|
||||
private:
|
||||
typedef void (TrainerAction::*TrainerSpellAction)(uint32, const Trainer::Spell, std::ostringstream& msg);
|
||||
void Iterate(Creature* creature, TrainerSpellAction action, SpellIds& spells);
|
||||
void Learn(uint32 cost, const Trainer::Spell tSpell, std::ostringstream& msg);
|
||||
Creature* GetCreatureTarget();
|
||||
void Iterate(Creature* creature, bool learnSpells, uint32 spellId);
|
||||
void Learn(SpellInfo const* spellInfo, uint32 cost, std::ostringstream& out);
|
||||
void TellHeader(Creature* creature);
|
||||
void TellFooter(uint32 totalCost);
|
||||
};
|
||||
|
||||
20
src/Ai/Base/Strategy/AggressiveStrategy.cpp
Normal file
20
src/Ai/Base/Strategy/AggressiveStrategy.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AggressiveStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void AggressiveStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"no target",
|
||||
{
|
||||
NextAction("aggressive target", 4.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
22
src/Ai/Base/Strategy/AggressiveStrategy.h
Normal file
22
src/Ai/Base/Strategy/AggressiveStrategy.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AGGRESSIVESTRATEGY_H
|
||||
#define _PLAYERBOT_AGGRESSIVESTRATEGY_H
|
||||
|
||||
#include "NonCombatStrategy.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AggressiveStrategy : public NonCombatStrategy
|
||||
{
|
||||
public:
|
||||
AggressiveStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
||||
|
||||
std::string const getName() override { return "aggressive"; }
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifndef _PLAYERBOT_STRATEGYCONTEXT_H
|
||||
#define _PLAYERBOT_STRATEGYCONTEXT_H
|
||||
|
||||
#include "AggressiveStrategy.h"
|
||||
#include "AttackEnemyPlayersStrategy.h"
|
||||
#include "BattlegroundStrategy.h"
|
||||
#include "CastTimeStrategy.h"
|
||||
@@ -61,6 +62,7 @@ public:
|
||||
creators["gather"] = &StrategyContext::gather;
|
||||
creators["emote"] = &StrategyContext::emote;
|
||||
creators["passive"] = &StrategyContext::passive;
|
||||
creators["aggressive"] = &StrategyContext::aggressive;
|
||||
creators["save mana"] = &StrategyContext::auto_save_mana;
|
||||
creators["food"] = &StrategyContext::food;
|
||||
creators["chat"] = &StrategyContext::chat;
|
||||
@@ -144,6 +146,7 @@ private:
|
||||
static Strategy* gather(PlayerbotAI* botAI) { return new GatherStrategy(botAI); }
|
||||
static Strategy* emote(PlayerbotAI* botAI) { return new EmoteStrategy(botAI); }
|
||||
static Strategy* passive(PlayerbotAI* botAI) { return new PassiveStrategy(botAI); }
|
||||
static Strategy* aggressive(PlayerbotAI* botAI) { return new AggressiveStrategy(botAI); }
|
||||
// static Strategy* conserve_mana(PlayerbotAI* botAI) { return new ConserveManaStrategy(botAI); }
|
||||
static Strategy* auto_save_mana(PlayerbotAI* botAI) { return new HealerAutoSaveManaStrategy(botAI); }
|
||||
static Strategy* food(PlayerbotAI* botAI) { return new UseFoodStrategy(botAI); }
|
||||
|
||||
@@ -163,52 +163,19 @@ bool RpgRepairTrigger::IsActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RpgTrainTrigger::IsTrainerOf(CreatureTemplate const* cInfo, Player* pPlayer)
|
||||
{
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cInfo->Entry);
|
||||
|
||||
if (trainer->GetTrainerType() == Trainer::Type::Mount && trainer->GetTrainerRequirement() != pPlayer->getRace())
|
||||
{
|
||||
if (FactionTemplateEntry const* faction_template = sFactionTemplateStore.LookupEntry(cInfo->faction))
|
||||
if (pPlayer->GetReputationRank(faction_template->faction) == REP_EXALTED)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return trainer->IsTrainerValidForPlayer(pPlayer);
|
||||
}
|
||||
|
||||
bool RpgTrainTrigger::IsActive()
|
||||
{
|
||||
GuidPosition guidP(getGuidP());
|
||||
|
||||
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_TRAINER))
|
||||
GuidPosition gp = getGuidP();
|
||||
if (!gp)
|
||||
return false;
|
||||
|
||||
CreatureTemplate const* cInfo = guidP.GetCreatureTemplate();
|
||||
|
||||
if (!IsTrainerOf(cInfo, bot))
|
||||
if (!gp.HasNpcFlag(UNIT_NPC_FLAG_TRAINER))
|
||||
return false;
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cInfo->Entry);
|
||||
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction);
|
||||
float fDiscountMod = bot->GetReputationPriceDiscount(factionTemplate);
|
||||
if (!AI_VALUE(bool, "can train"))
|
||||
return false;
|
||||
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
||||
continue;
|
||||
|
||||
uint32 cost = uint32(floor(spell.MoneyCost * fDiscountMod));
|
||||
|
||||
if (cost > AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells))
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RpgHealTrigger::IsActive()
|
||||
|
||||
@@ -134,8 +134,6 @@ class RpgTrainTrigger : public RpgTrigger
|
||||
public:
|
||||
RpgTrainTrigger(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgTrigger(botAI, name) {}
|
||||
|
||||
static bool IsTrainerOf(CreatureTemplate const* cInfo, Player* pPlayer);
|
||||
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
|
||||
66
src/Ai/Base/Value/AggressiveTargetValue.cpp
Normal file
66
src/Ai/Base/Value/AggressiveTargetValue.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AggressiveTargetValue.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
Unit* AggressiveTargetValue::Calculate()
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
|
||||
if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() ||
|
||||
!GET_PLAYERBOT_AI(master)))
|
||||
master = nullptr;
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
if (targets.empty())
|
||||
return nullptr;
|
||||
|
||||
float aggroRange = sPlayerbotAIConfig.aggroDistance;
|
||||
float distance = 0;
|
||||
Unit* result = nullptr;
|
||||
|
||||
for (ObjectGuid const guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || !unit->IsAlive())
|
||||
continue;
|
||||
|
||||
if (!unit->IsInWorld() || unit->IsDuringRemoveFromWorld())
|
||||
continue;
|
||||
|
||||
if (unit->ToCreature() && !unit->ToCreature()->GetCreatureTemplate()->lootid &&
|
||||
bot->GetReactionTo(unit) >= REP_NEUTRAL)
|
||||
continue;
|
||||
|
||||
if (!bot->IsHostileTo(unit) && unit->GetNpcFlags() != UNIT_NPC_FLAG_NONE)
|
||||
continue;
|
||||
|
||||
if (abs(bot->GetPositionZ() - unit->GetPositionZ()) > INTERACTION_DISTANCE)
|
||||
continue;
|
||||
|
||||
if (!bot->InBattleground() && master && botAI->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) &&
|
||||
ServerFacade::instance().GetDistance2d(master, unit) > aggroRange)
|
||||
continue;
|
||||
|
||||
if (!bot->IsWithinLOSInMap(unit))
|
||||
continue;
|
||||
|
||||
if (bot->GetDistance(unit) > aggroRange)
|
||||
continue;
|
||||
|
||||
float newdistance = bot->GetDistance(unit);
|
||||
if (!result || (newdistance < distance))
|
||||
{
|
||||
distance = newdistance;
|
||||
result = unit;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
22
src/Ai/Base/Value/AggressiveTargetValue.h
Normal file
22
src/Ai/Base/Value/AggressiveTargetValue.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AGGRESSIVETARGETVALUE_H
|
||||
#define _PLAYERBOT_AGGRESSIVETARGETVALUE_H
|
||||
|
||||
#include "TargetValue.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
|
||||
class AggressiveTargetValue : public TargetValue
|
||||
{
|
||||
public:
|
||||
AggressiveTargetValue(PlayerbotAI* botAI, std::string const name = "aggressive target") : TargetValue(botAI, name) {}
|
||||
|
||||
Unit* Calculate() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
uint32 MaxGearRepairCostValue::Calculate()
|
||||
{
|
||||
uint32 TotalCost = 0;
|
||||
uint32 totalCost = 0;
|
||||
|
||||
for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||
{
|
||||
uint16 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
|
||||
@@ -43,15 +44,16 @@ uint32 MaxGearRepairCostValue::Calculate()
|
||||
|
||||
uint32 costs = uint32(maxDurability * dmultiplier * double(dQualitymodEntry->quality_mod));
|
||||
|
||||
TotalCost += costs;
|
||||
totalCost += costs;
|
||||
}
|
||||
|
||||
return TotalCost;
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
uint32 RepairCostValue::Calculate()
|
||||
{
|
||||
uint32 TotalCost = 0;
|
||||
uint32 totalCost = 0;
|
||||
|
||||
for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||
{
|
||||
uint16 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
|
||||
@@ -86,45 +88,49 @@ uint32 RepairCostValue::Calculate()
|
||||
dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class, ditemProto->SubClass)];
|
||||
uint32 costs = uint32(LostDurability * dmultiplier * double(dQualitymodEntry->quality_mod));
|
||||
|
||||
TotalCost += costs;
|
||||
totalCost += costs;
|
||||
}
|
||||
|
||||
return TotalCost;
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
uint32 TrainCostValue::Calculate()
|
||||
{
|
||||
uint32 TotalCost = 0;
|
||||
uint32 totalCost = 0;
|
||||
|
||||
std::set<uint32> spells;
|
||||
std::unordered_set<uint32> spells;
|
||||
|
||||
if (CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates())
|
||||
CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates();
|
||||
for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr)
|
||||
{
|
||||
for (CreatureTemplateContainer::const_iterator itr = creatures->begin(); itr != creatures->end(); ++itr)
|
||||
if (!(itr->second.npcflag & UNIT_NPC_FLAG_TRAINER))
|
||||
continue;
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(itr->first);
|
||||
if (!trainer)
|
||||
continue;
|
||||
|
||||
if (trainer->GetTrainerType() != Trainer::Type::Class || !trainer->IsTrainerValidForPlayer(bot))
|
||||
continue;
|
||||
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(itr->first);
|
||||
|
||||
if (!trainer)
|
||||
Trainer::Spell const* trainerSpell = trainer->GetSpell(spell.SpellId);
|
||||
if (!trainerSpell)
|
||||
continue;
|
||||
|
||||
if (trainer->GetTrainerType() != Trainer::Type::Class || !trainer->IsTrainerValidForPlayer(bot))
|
||||
if (!trainer->CanTeachSpell(bot, trainerSpell))
|
||||
continue;
|
||||
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
||||
continue;
|
||||
if (spells.find(trainerSpell->SpellId) != spells.end())
|
||||
continue;
|
||||
|
||||
if (spells.find(spell.SpellId) != spells.end())
|
||||
continue;
|
||||
|
||||
TotalCost += spell.MoneyCost;
|
||||
spells.insert(spell.SpellId);
|
||||
}
|
||||
totalCost += trainerSpell->MoneyCost;
|
||||
spells.insert(trainerSpell->SpellId);
|
||||
}
|
||||
}
|
||||
|
||||
return TotalCost;
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
uint32 MoneyNeededForValue::Calculate()
|
||||
|
||||
@@ -44,6 +44,11 @@ bool CanSellValue::Calculate()
|
||||
AI_VALUE2(uint32, "item count", "usage " + std::to_string(ITEM_USAGE_AH))) > 1;
|
||||
}
|
||||
|
||||
bool CanTrainValue::Calculate()
|
||||
{
|
||||
return AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells) > 0;
|
||||
}
|
||||
|
||||
bool CanFightEqualValue::Calculate() { return AI_VALUE(uint8, "durability") > 20; }
|
||||
|
||||
bool CanFightEliteValue::Calculate()
|
||||
|
||||
@@ -58,6 +58,14 @@ public:
|
||||
bool Calculate() override;
|
||||
};
|
||||
|
||||
class CanTrainValue : public BoolCalculatedValue
|
||||
{
|
||||
public:
|
||||
CanTrainValue(PlayerbotAI* botAI) : BoolCalculatedValue(botAI, "can train", 2 * 2000) {}
|
||||
|
||||
bool Calculate() override;
|
||||
};
|
||||
|
||||
class CanFightEqualValue : public BoolCalculatedValue
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define _PLAYERBOT_VALUECONTEXT_H
|
||||
|
||||
#include "ActiveSpellValue.h"
|
||||
#include "AggressiveTargetValue.h"
|
||||
#include "AlwaysLootListValue.h"
|
||||
#include "AoeHealValues.h"
|
||||
#include "AoeValues.h"
|
||||
@@ -51,6 +52,7 @@
|
||||
#include "LineTargetValue.h"
|
||||
#include "LogLevelValue.h"
|
||||
#include "LootStrategyValue.h"
|
||||
#include "LootValues.h"
|
||||
#include "MaintenanceValues.h"
|
||||
#include "ManaSaveLevelValue.h"
|
||||
#include "NearestAdsValue.h"
|
||||
@@ -143,6 +145,7 @@ public:
|
||||
creators["pet target"] = &ValueContext::pet_target;
|
||||
creators["old target"] = &ValueContext::old_target;
|
||||
creators["grind target"] = &ValueContext::grind_target;
|
||||
creators["aggressive target"] = &ValueContext::aggressive_target;
|
||||
creators["rti target"] = &ValueContext::rti_target;
|
||||
creators["rti cc target"] = &ValueContext::rti_cc_target;
|
||||
creators["duel target"] = &ValueContext::duel_target;
|
||||
@@ -272,6 +275,7 @@ public:
|
||||
creators["can repair"] = &ValueContext::can_repair;
|
||||
creators["should sell"] = &ValueContext::should_sell;
|
||||
creators["can sell"] = &ValueContext::can_sell;
|
||||
creators["can train"] = &ValueContext::can_train;
|
||||
creators["can fight equal"] = &ValueContext::can_fight_equal;
|
||||
creators["can fight elite"] = &ValueContext::can_fight_elite;
|
||||
creators["can fight boss"] = &ValueContext::can_fight_boss;
|
||||
@@ -457,6 +461,7 @@ private:
|
||||
static UntypedValue* current_cc_target(PlayerbotAI* botAI) { return new CurrentCcTargetValue(botAI); }
|
||||
static UntypedValue* pet_target(PlayerbotAI* botAI) { return new PetTargetValue(botAI); }
|
||||
static UntypedValue* grind_target(PlayerbotAI* botAI) { return new GrindTargetValue(botAI); }
|
||||
static UntypedValue* aggressive_target(PlayerbotAI* botAI) { return new AggressiveTargetValue(botAI); }
|
||||
static UntypedValue* rti_target(PlayerbotAI* botAI) { return new RtiTargetValue(botAI); }
|
||||
static UntypedValue* rti_cc_target(PlayerbotAI* botAI) { return new RtiCcTargetValue(botAI); }
|
||||
static UntypedValue* duel_target(PlayerbotAI* botAI) { return new DuelTargetValue(botAI); }
|
||||
@@ -519,6 +524,7 @@ private:
|
||||
static UntypedValue* can_repair(PlayerbotAI* botAI) { return new CanRepairValue(botAI); }
|
||||
static UntypedValue* should_sell(PlayerbotAI* botAI) { return new ShouldSellValue(botAI); }
|
||||
static UntypedValue* can_sell(PlayerbotAI* botAI) { return new CanSellValue(botAI); }
|
||||
static UntypedValue* can_train(PlayerbotAI* botAI) { return new CanTrainValue(botAI); }
|
||||
static UntypedValue* can_fight_equal(PlayerbotAI* botAI) { return new CanFightEqualValue(botAI); }
|
||||
static UntypedValue* can_fight_elite(PlayerbotAI* botAI) { return new CanFightEliteValue(botAI); }
|
||||
static UntypedValue* can_fight_boss(PlayerbotAI* botAI) { return new CanFightBossValue(botAI); }
|
||||
|
||||
@@ -201,8 +201,7 @@ bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss)
|
||||
continue;
|
||||
|
||||
// Check if position is within maximum allowed distance from boss
|
||||
if (boss && sqrt(pow(potentialPos.GetPositionX() - boss->GetPositionX(), 2) +
|
||||
pow(potentialPos.GetPositionY() - boss->GetPositionY(), 2)) > MAX_BOSS_DISTANCE)
|
||||
if (boss && boss->GetDistance2d(potentialPos.GetPositionX(), potentialPos.GetPositionY()) > MAX_BOSS_DISTANCE)
|
||||
continue;
|
||||
|
||||
// Score this position based on:
|
||||
@@ -215,8 +214,7 @@ bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss)
|
||||
float minOrbDist = std::numeric_limits<float>::max();
|
||||
for (Unit* orb : orbs)
|
||||
{
|
||||
float orbDist = sqrt(pow(potentialPos.GetPositionX() - orb->GetPositionX(), 2) +
|
||||
pow(potentialPos.GetPositionY() - orb->GetPositionY(), 2));
|
||||
float orbDist = orb->GetDistance2d(potentialPos.GetPositionX(), potentialPos.GetPositionY());
|
||||
minOrbDist = std::min(minOrbDist, orbDist);
|
||||
}
|
||||
score += minOrbDist * 2.0f; // Weight orb distance more heavily
|
||||
@@ -232,8 +230,7 @@ bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss)
|
||||
// Factor in proximity to boss (closer is better, as long as we're safe from orbs)
|
||||
if (boss)
|
||||
{
|
||||
float bossDist = sqrt(pow(potentialPos.GetPositionX() - boss->GetPositionX(), 2) +
|
||||
pow(potentialPos.GetPositionY() - boss->GetPositionY(), 2));
|
||||
float bossDist = boss->GetDistance2d(potentialPos.GetPositionX(), potentialPos.GetPositionY());
|
||||
// Add points for being closer to boss (inverse relationship)
|
||||
// but only if we're safely away from orbs
|
||||
if (minOrbDist > SAFE_DISTANCE)
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace GruulsLairHelpers
|
||||
Unit* krosh = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "krosh firehand")->Get();
|
||||
if (krosh && krosh->IsAlive())
|
||||
{
|
||||
float dist = sqrt(pow(pos.GetPositionX() - krosh->GetPositionX(), 2) + pow(pos.GetPositionY() - krosh->GetPositionY(), 2));
|
||||
float dist = krosh->GetDistance2d(pos.GetPositionX(), pos.GetPositionY());
|
||||
if (dist < KROSH_SAFE_DISTANCE)
|
||||
isSafe = false;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace GruulsLairHelpers
|
||||
Unit* maulgar = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "high king maulgar")->Get();
|
||||
if (botAI->IsRanged(bot) && maulgar && maulgar->IsAlive())
|
||||
{
|
||||
float dist = sqrt(pow(pos.GetPositionX() - maulgar->GetPositionX(), 2) + pow(pos.GetPositionY() - maulgar->GetPositionY(), 2));
|
||||
float dist = maulgar->GetDistance2d(pos.GetPositionX(), pos.GetPositionY());
|
||||
if (dist < MAULGAR_SAFE_DISTANCE)
|
||||
isSafe = false;
|
||||
}
|
||||
@@ -182,7 +182,7 @@ namespace GruulsLairHelpers
|
||||
|
||||
if (IsPositionSafe(botAI, bot, candidatePos))
|
||||
{
|
||||
float movementDistance = sqrt(pow(destX - bot->GetPositionX(), 2) + pow(destY - bot->GetPositionY(), 2));
|
||||
float movementDistance = bot->GetDistance2d(destX, destY);
|
||||
if (movementDistance < bestScore)
|
||||
{
|
||||
bestScore = movementDistance;
|
||||
|
||||
@@ -1800,8 +1800,7 @@ bool IccRotfaceTankPositionAction::HandleBigOozePositioning(Unit*)
|
||||
Unit* puddle = botAI->GetUnit(puddleGuid);
|
||||
if (puddle && botAI->GetAura("Ooze Flood", puddle))
|
||||
{
|
||||
float puddleDistance = std::sqrt(std::pow(newX - puddle->GetPositionX(), 2) +
|
||||
std::pow(newY - puddle->GetPositionY(), 2));
|
||||
float puddleDistance = puddle->GetDistance2d(newX, newY);
|
||||
if (puddleDistance < puddleSafeDistance)
|
||||
{
|
||||
isSafeFromPuddles = false;
|
||||
@@ -1921,8 +1920,7 @@ bool IccRotfaceGroupPositionAction::MoveAwayFromPuddle(Unit* boss, Unit* puddle,
|
||||
float moveZ = bot->GetPositionZ();
|
||||
|
||||
// Check distances and line of sight
|
||||
float newPuddleDistance =
|
||||
sqrt(pow(moveX - puddle->GetPositionX(), 2) + pow(moveY - puddle->GetPositionY(), 2));
|
||||
float newPuddleDistance = puddle->GetDistance2d(moveX, moveY);
|
||||
float newCenterDistance = sqrt(pow(moveX - ICC_ROTFACE_CENTER_POSITION.GetPositionX(), 2) +
|
||||
pow(moveY - ICC_ROTFACE_CENTER_POSITION.GetPositionY(), 2));
|
||||
|
||||
@@ -2125,8 +2123,7 @@ bool IccRotfaceGroupPositionAction::FindAndMoveFromClosestMember(Unit* boss, Uni
|
||||
// Ensure the target position is at least 30 yards away from the puddle
|
||||
if (puddle)
|
||||
{
|
||||
float puddleDistance = std::sqrt(std::pow(targetX - puddle->GetPositionX(), 2) +
|
||||
std::pow(targetY - puddle->GetPositionY(), 2));
|
||||
float puddleDistance = puddle->GetDistance2d(targetX, targetY);
|
||||
if (puddleDistance < puddleSafeDistance)
|
||||
{
|
||||
// Adjust the target position to move further away from the puddle
|
||||
@@ -2203,8 +2200,7 @@ bool IccRotfaceMoveAwayFromExplosionAction::MoveToRandomSafeLocation()
|
||||
if (!puddle || !botAI->HasAura("Ooze Flood", puddle))
|
||||
continue;
|
||||
|
||||
float puddleDistance =
|
||||
std::sqrt(std::pow(moveX - puddle->GetPositionX(), 2) + std::pow(moveY - puddle->GetPositionY(), 2));
|
||||
float puddleDistance = puddle->GetDistance2d(moveX, moveY);
|
||||
if (puddleDistance < 30.0f)
|
||||
{
|
||||
// Adjust the position to move further away from the puddle
|
||||
@@ -2407,7 +2403,7 @@ bool IccPutricideGrowingOozePuddleAction::IsPositionTooCloseToOtherPuddles(float
|
||||
if (Aura* grow = unit->GetAura(SPELL_GROW_AURA))
|
||||
safeDistance += (grow->GetStackAmount() * STACK_MULTIPLIER);
|
||||
|
||||
float dist = sqrt(pow(x - unit->GetPositionX(), 2) + pow(y - unit->GetPositionY(), 2));
|
||||
float dist = unit->GetDistance2d(x, y);
|
||||
if (dist < safeDistance)
|
||||
return true;
|
||||
}
|
||||
@@ -2650,7 +2646,7 @@ bool IccPutricideGasCloudAction::HandleGaseousBloatMovement(Unit* gasCloud)
|
||||
float minGasBombDist = FLT_MAX;
|
||||
for (Unit* bomb : gasBombs)
|
||||
{
|
||||
float bombDist = sqrt(pow(testX - bomb->GetPositionX(), 2) + pow(testY - bomb->GetPositionY(), 2));
|
||||
float bombDist = bomb->GetDistance2d(testX, testY);
|
||||
if (bombDist < minGasBombDist)
|
||||
minGasBombDist = bombDist;
|
||||
}
|
||||
@@ -2717,8 +2713,7 @@ bool IccPutricideGasCloudAction::HandleGaseousBloatMovement(Unit* gasCloud)
|
||||
float minEmergencyGasBombDist = FLT_MAX;
|
||||
for (Unit* bomb : gasBombs)
|
||||
{
|
||||
float bombDist = sqrt(pow(emergencyPos.GetPositionX() - bomb->GetPositionX(), 2) +
|
||||
pow(emergencyPos.GetPositionY() - bomb->GetPositionY(), 2));
|
||||
float bombDist = bomb->GetDistance2d(emergencyPos.GetPositionX(), emergencyPos.GetPositionY());
|
||||
if (bombDist < minEmergencyGasBombDist)
|
||||
minEmergencyGasBombDist = bombDist;
|
||||
}
|
||||
@@ -4487,8 +4482,7 @@ bool IccBqlGroupPositionAction::HandleGroupPosition(Unit* boss, Aura* frenzyAura
|
||||
// Maintain minimum distance from center position (if too close to center, move out)
|
||||
float centerX = ICC_BQL_CENTER_POSITION.GetPositionX();
|
||||
float centerY = ICC_BQL_CENTER_POSITION.GetPositionY();
|
||||
float centerDist =
|
||||
std::sqrt(std::pow(bot->GetPositionX() - centerX, 2) + std::pow(bot->GetPositionY() - centerY, 2));
|
||||
float centerDist = bot->GetDistance2d(centerX, centerY);
|
||||
if (centerDist < MIN_CENTER_DISTANCE && !((boss->GetPositionZ() - bot->GetPositionZ()) > 5.0f))
|
||||
{
|
||||
float dx = bot->GetPositionX() - centerX;
|
||||
@@ -6904,7 +6898,7 @@ bool IccLichKingShadowTrapAction::Execute(Event /*event*/)
|
||||
Unit* trap = botAI->GetUnit(trapGuid);
|
||||
if (!trap)
|
||||
continue;
|
||||
float distToTrap = sqrt(pow(testX - trap->GetPositionX(), 2) + pow(testY - trap->GetPositionY(), 2));
|
||||
float distToTrap = trap->GetDistance2d(testX, testY);
|
||||
if (distToTrap < SAFE_DISTANCE)
|
||||
{
|
||||
isSafe = false;
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace MagtheridonHelpers
|
||||
}
|
||||
for (Unit* hazard : debrisHazards)
|
||||
{
|
||||
float dist = std::sqrt(std::pow(x - hazard->GetPositionX(), 2) + std::pow(y - hazard->GetPositionY(), 2));
|
||||
float dist = hazard->GetDistance2d(x, y);
|
||||
if (dist < 9.0f)
|
||||
return false;
|
||||
}
|
||||
@@ -145,7 +145,7 @@ namespace MagtheridonHelpers
|
||||
if (!go || go->GetEntry() != GO_BLAZE)
|
||||
continue;
|
||||
|
||||
float dist = std::sqrt(std::pow(x - go->GetPositionX(), 2) + std::pow(y - go->GetPositionY(), 2));
|
||||
float dist = go->GetDistance2d(x, y);
|
||||
if (dist < 5.0f)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -262,10 +262,10 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
||||
// that removes the distance check and keeps all other checks
|
||||
switch (questGiver->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
case TYPEID_UNIT: // Player::GetNPCIfCanInteractWith
|
||||
{
|
||||
ObjectGuid guid = questGiver->GetGUID();
|
||||
uint32 npcflagmask = UNIT_NPC_FLAG_QUESTGIVER;
|
||||
|
||||
// unit checks
|
||||
if (!guid)
|
||||
return false;
|
||||
@@ -292,7 +292,7 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
||||
return false;
|
||||
|
||||
// appropriate npc type
|
||||
if (npcflagmask && !creature->HasNpcFlag(NPCFlags(npcflagmask)))
|
||||
if (!creature->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER))
|
||||
return false;
|
||||
|
||||
// not allow interaction under control, but allow with own pets
|
||||
@@ -303,35 +303,24 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
||||
if (creature->GetReactionTo(bot) <= REP_UNFRIENDLY)
|
||||
return false;
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(creature->GetEntry());
|
||||
|
||||
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train
|
||||
// dual wield to a shaman :/ too many to change in sql and watch in the future pussywizard: this function is
|
||||
// not used when talking, but when already taking action (buy spell, reset talents, show spell list)
|
||||
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) &&
|
||||
trainer->GetTrainerType() == Trainer::Type::Class &&
|
||||
!trainer->IsTrainerValidForPlayer(bot))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
case TYPEID_GAMEOBJECT:
|
||||
case TYPEID_GAMEOBJECT: // Player::GetGameObjectIfCanInteractWith
|
||||
{
|
||||
ObjectGuid guid = questGiver->GetGUID();
|
||||
GameobjectTypes type = GAMEOBJECT_TYPE_QUESTGIVER;
|
||||
|
||||
if (GameObject* go = bot->GetMap()->GetGameObject(guid))
|
||||
{
|
||||
if (go->GetGoType() == type)
|
||||
if (go->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
|
||||
{
|
||||
// Players cannot interact with gameobjects that use the "Point" icon
|
||||
if (go->GetGOInfo()->IconName == "Point")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// unused for now
|
||||
|
||||
@@ -4739,38 +4739,13 @@ void PlayerbotFactory::InitAttunementQuests()
|
||||
|
||||
uint32 currentXP = bot->GetUInt32Value(PLAYER_XP);
|
||||
|
||||
// List of attunement quest IDs
|
||||
std::list<uint32> attunementQuestsTBC = {
|
||||
// Caverns of Time - Part 1
|
||||
10279, // To The Master's Lair
|
||||
10277, // The Caverns of Time
|
||||
|
||||
// Caverns of Time - Part 2 (Escape from Durnholde Keep)
|
||||
10282, // Old Hillsbrad
|
||||
10283, // Taretha's Diversion
|
||||
10284, // Escape from Durnholde
|
||||
10285, // Return to Andormu
|
||||
|
||||
// Caverns of Time - Part 2 (The Black Morass)
|
||||
10296, // The Black Morass
|
||||
10297, // The Opening of the Dark Portal
|
||||
10298, // Hero of the Brood
|
||||
|
||||
// Magister's Terrace Attunement
|
||||
11481, // Crisis at the Sunwell
|
||||
11482, // Duty Calls
|
||||
11488, // Magisters' Terrace
|
||||
11490, // The Scryer's Scryer
|
||||
11492 // Hard to Kill
|
||||
};
|
||||
|
||||
// Complete all level-appropriate attunement quests for the bot
|
||||
if (level >= 60)
|
||||
{
|
||||
std::list<uint32> questsToComplete;
|
||||
|
||||
// Check each quest status before adding to the completion list
|
||||
for (uint32 questId : attunementQuestsTBC)
|
||||
for (uint32 questId : sPlayerbotAIConfig.attunementQuests)
|
||||
{
|
||||
QuestStatus questStatus = bot->GetQuestStatus(questId);
|
||||
|
||||
|
||||
@@ -45,18 +45,18 @@ void StatsCollector::CollectItemStats(ItemTemplate const* proto)
|
||||
switch (proto->Spells[j].SpellTrigger)
|
||||
{
|
||||
case ITEM_SPELLTRIGGER_ON_USE:
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, proto->Spells[j].SpellCooldown);
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, Milliseconds(proto->Spells[j].SpellCooldown));
|
||||
break;
|
||||
case ITEM_SPELLTRIGGER_ON_EQUIP:
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, 0);
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, Milliseconds(0));
|
||||
break;
|
||||
case ITEM_SPELLTRIGGER_CHANCE_ON_HIT:
|
||||
if (type_ & CollectorType::MELEE)
|
||||
{
|
||||
if (proto->Spells[j].SpellPPMRate > 0.01f)
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, 60000 / proto->Spells[j].SpellPPMRate);
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, Milliseconds(static_cast<int>(60000 / proto->Spells[j].SpellPPMRate)));
|
||||
else
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, 60000 / 1.8f); // Default PPM = 1.8
|
||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, Milliseconds(static_cast<int>(60000 / 1.8f))); // Default PPM = 1.8
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -71,7 +71,7 @@ void StatsCollector::CollectItemStats(ItemTemplate const* proto)
|
||||
}
|
||||
}
|
||||
|
||||
void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 spellCooldown)
|
||||
void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, Milliseconds spellCooldown)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
|
||||
@@ -81,21 +81,21 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
||||
if (SpecialSpellFilter(spellId))
|
||||
return;
|
||||
|
||||
const SpellProcEventEntry* eventEntry = sSpellMgr->GetSpellProcEvent(spellInfo->Id);
|
||||
const SpellProcEntry* eventEntry = sSpellMgr->GetSpellProcEntry(spellInfo->Id);
|
||||
|
||||
uint32 triggerCooldown = eventEntry ? eventEntry->cooldown : 0;
|
||||
Milliseconds triggerCooldown = eventEntry ? eventEntry->Cooldown : 0ms;
|
||||
|
||||
bool canNextTrigger = true;
|
||||
|
||||
uint32 procFlags;
|
||||
uint32 procChance;
|
||||
if (eventEntry && eventEntry->procFlags)
|
||||
procFlags = eventEntry->procFlags;
|
||||
if (eventEntry && eventEntry->ProcFlags)
|
||||
procFlags = eventEntry->ProcFlags;
|
||||
else
|
||||
procFlags = spellInfo->ProcFlags;
|
||||
|
||||
if (eventEntry && eventEntry->customChance)
|
||||
procChance = eventEntry->customChance;
|
||||
if (eventEntry && eventEntry->Chance)
|
||||
procChance = eventEntry->Chance;
|
||||
else
|
||||
procChance = spellInfo->ProcChance;
|
||||
bool lowChance = procChance <= 5;
|
||||
@@ -142,11 +142,11 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
||||
break;
|
||||
|
||||
float coverage;
|
||||
if (spellCooldown <= 2000 || spellInfo->GetDuration() == -1)
|
||||
if (spellCooldown.count() <= 2000 || spellInfo->GetDuration() == -1)
|
||||
coverage = 1.0f;
|
||||
else
|
||||
coverage =
|
||||
std::min(1.0f, (float)spellInfo->GetDuration() / (spellInfo->GetDuration() + spellCooldown));
|
||||
std::min(1.0f, (float)spellInfo->GetDuration() / (spellInfo->GetDuration() + spellCooldown.count()));
|
||||
|
||||
multiplier *= coverage;
|
||||
HandleApplyAura(effectInfo, multiplier, canNextTrigger, triggerCooldown);
|
||||
@@ -155,9 +155,9 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
||||
case SPELL_EFFECT_HEAL:
|
||||
{
|
||||
/// @todo Handle spell without cooldown
|
||||
if (!spellCooldown)
|
||||
if (!spellCooldown.count())
|
||||
break;
|
||||
float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f);
|
||||
float normalizedCd = std::max((float)spellCooldown.count() / 1000, 5.0f);
|
||||
int32 val = AverageValue(effectInfo);
|
||||
float transfer_multiplier = 1;
|
||||
stats[STATS_TYPE_HEAL_POWER] += (float)val / normalizedCd * multiplier * transfer_multiplier;
|
||||
@@ -166,11 +166,11 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
||||
case SPELL_EFFECT_ENERGIZE:
|
||||
{
|
||||
/// @todo Handle spell without cooldown
|
||||
if (!spellCooldown)
|
||||
if (!spellCooldown.count())
|
||||
break;
|
||||
if (effectInfo.MiscValue != POWER_MANA)
|
||||
break;
|
||||
float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f);
|
||||
float normalizedCd = std::max((float)spellCooldown.count() / 1000, 5.0f);
|
||||
int32 val = AverageValue(effectInfo);
|
||||
float transfer_multiplier = 0.2;
|
||||
stats[STATS_TYPE_MANA_REGENERATION] += (float)val / normalizedCd * multiplier * transfer_multiplier;
|
||||
@@ -179,9 +179,9 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
||||
case SPELL_EFFECT_SCHOOL_DAMAGE:
|
||||
{
|
||||
/// @todo Handle spell without cooldown
|
||||
if (!spellCooldown)
|
||||
if (!spellCooldown.count())
|
||||
break;
|
||||
float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f);
|
||||
float normalizedCd = std::max((float)spellCooldown.count() / 1000, 5.0f);
|
||||
int32 val = AverageValue(effectInfo);
|
||||
if (type_ & (CollectorType::MELEE | CollectorType::RANGED))
|
||||
{
|
||||
@@ -352,12 +352,12 @@ bool StatsCollector::SpecialEnchantFilter(uint32 enchantSpellId)
|
||||
|
||||
bool StatsCollector::CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict)
|
||||
{
|
||||
const SpellProcEventEntry* eventEntry = sSpellMgr->GetSpellProcEvent(spellInfo->Id);
|
||||
const SpellProcEntry* eventEntry = sSpellMgr->GetSpellProcEntry(spellInfo->Id);
|
||||
uint32 spellFamilyName = 0;
|
||||
if (eventEntry)
|
||||
{
|
||||
spellFamilyName = eventEntry->spellFamilyName;
|
||||
flag96 spellFamilyMask = eventEntry->spellFamilyMask;
|
||||
spellFamilyName = eventEntry->SpellFamilyName;
|
||||
flag96 spellFamilyMask = eventEntry->SpellFamilyMask;
|
||||
if (spellFamilyName != 0)
|
||||
{
|
||||
if (!CheckSpellValidation(spellFamilyName, spellFamilyMask, strict))
|
||||
@@ -548,7 +548,7 @@ void StatsCollector::CollectByItemStatType(uint32 itemStatType, int32 val)
|
||||
}
|
||||
|
||||
void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float multiplier, bool canNextTrigger,
|
||||
uint32 triggerCooldown)
|
||||
Milliseconds triggerCooldown)
|
||||
{
|
||||
if (effectInfo.Effect != SPELL_EFFECT_APPLY_AURA)
|
||||
return;
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
StatsCollector(StatsCollector& stats) = default;
|
||||
void Reset();
|
||||
void CollectItemStats(ItemTemplate const* proto);
|
||||
void CollectSpellStats(uint32 spellId, float multiplier = 1.0f, int32 spellCooldown = -1);
|
||||
void CollectSpellStats(uint32 spellId, float multiplier = 1.0f, Milliseconds spellCooldown = -1ms);
|
||||
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount = 0);
|
||||
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
||||
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
bool SpecialEnchantFilter(uint32 enchantSpellId);
|
||||
|
||||
void HandleApplyAura(const SpellEffectInfo& effectInfo, float multiplier, bool canNextTrigger,
|
||||
uint32 triggerCooldown);
|
||||
Milliseconds triggerCooldown);
|
||||
float AverageValue(const SpellEffectInfo& effectInfo);
|
||||
|
||||
private:
|
||||
|
||||
@@ -228,13 +228,13 @@ WorldPosition WorldPosition::offset(WorldPosition* center)
|
||||
|
||||
float WorldPosition::size()
|
||||
{
|
||||
return sqrt(pow(GetPositionX(), 2.0) + pow(GetPositionY(), 2.0) + pow(GetPositionZ(), 2.0));
|
||||
return GetExactDist(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
float WorldPosition::distance(WorldPosition* center)
|
||||
{
|
||||
if (GetMapId() == center->GetMapId())
|
||||
return relPoint(center).size();
|
||||
return GetExactDist(center->GetPositionX(), center->GetPositionY(), center->GetPositionZ());
|
||||
|
||||
// this -> mapTransfer | mapTransfer -> center
|
||||
return TravelMgr::instance().mapTransDistance(*this, *center);
|
||||
@@ -243,7 +243,7 @@ float WorldPosition::distance(WorldPosition* center)
|
||||
float WorldPosition::fDist(WorldPosition* center)
|
||||
{
|
||||
if (GetMapId() == center->GetMapId())
|
||||
return sqrt(sqDistance2d(center));
|
||||
return GetExactDist2d(center->GetPositionX(), center->GetPositionY());
|
||||
|
||||
// this -> mapTransfer | mapTransfer -> center
|
||||
return TravelMgr::instance().fastMapTransDistance(*this, *center);
|
||||
|
||||
@@ -179,8 +179,7 @@ public:
|
||||
// Quick square distance in 2d plane.
|
||||
float sqDistance2d(WorldPosition center)
|
||||
{
|
||||
return (GetPositionX() - center.GetPositionX()) * (GetPositionX() - center.GetPositionX()) +
|
||||
(GetPositionY() - center.GetPositionY()) * (GetPositionY() - center.GetPositionY());
|
||||
return GetExactDist2dSq(center.GetPositionX(), center.GetPositionY());
|
||||
}
|
||||
|
||||
// Quick square distance calculation without map check. Used for getting the minimum distant points.
|
||||
@@ -193,8 +192,7 @@ public:
|
||||
|
||||
float sqDistance2d(WorldPosition* center)
|
||||
{
|
||||
return (GetPositionX() - center->GetPositionX()) * (GetPositionX() - center->GetPositionX()) +
|
||||
(GetPositionY() - center->GetPositionY()) * (GetPositionY() - center->GetPositionY());
|
||||
return GetExactDist2dSq(center->GetPositionX(), center->GetPositionY());
|
||||
}
|
||||
|
||||
float sqDistance(WorldPosition* center)
|
||||
|
||||
@@ -179,6 +179,9 @@ bool PlayerbotAIConfig::Initialize()
|
||||
"179490,141596,160836,160845,179516,176224,181085,176112,128308,128403,"
|
||||
"165739,165738,175245,175970,176325,176327,123329,2560"),
|
||||
disallowedGameObjects);
|
||||
LoadSet<std::set<uint32>>(
|
||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.AttunementQuests", "10279,10277,10282,10283,10284,10285,10296,10297,10298,11481,11482,11488,11490,11492,10901"),
|
||||
attunementQuests);
|
||||
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
||||
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 500);
|
||||
@@ -620,7 +623,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
syncQuestWithPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestWithPlayer", true);
|
||||
syncQuestForPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestForPlayer", false);
|
||||
dropObsoleteQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.DropObsoleteQuests", true);
|
||||
autoTrainSpells = sConfigMgr->GetOption<std::string>("AiPlayerbot.AutoTrainSpells", "yes");
|
||||
allowLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowLearnTrainerSpells", true);
|
||||
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
|
||||
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
|
||||
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
|
||||
|
||||
@@ -98,6 +98,7 @@ public:
|
||||
std::set<uint32> aoeAvoidSpellWhitelist;
|
||||
bool tellWhenAvoidAoe;
|
||||
std::set<uint32> disallowedGameObjects;
|
||||
std::set<uint32> attunementQuests;
|
||||
|
||||
uint32 openGoSpell;
|
||||
bool randomBotAutologin;
|
||||
@@ -352,7 +353,7 @@ public:
|
||||
bool syncQuestWithPlayer;
|
||||
bool syncQuestForPlayer;
|
||||
bool dropObsoleteQuests;
|
||||
std::string autoTrainSpells;
|
||||
bool allowLearnTrainerSpells;
|
||||
bool autoPickTalents;
|
||||
bool autoUpgradeEquip;
|
||||
int32 hunterWolfPet;
|
||||
|
||||
Reference in New Issue
Block a user