mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Merge pull request #2172 from mod-playerbots/test-staging
Update master from Test staging and Core Update
This commit is contained in:
commit
d8c668cf96
18
.github/workflows/codestyle_cpp.yml
vendored
18
.github/workflows/codestyle_cpp.yml
vendored
@ -6,10 +6,6 @@ on:
|
|||||||
- reopened
|
- reopened
|
||||||
- synchronize
|
- synchronize
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
paths:
|
|
||||||
- src/**
|
|
||||||
- "!README.md"
|
|
||||||
- "!docs/**"
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: "codestyle-cppcheck-${{ github.event.pull_request.number }}"
|
group: "codestyle-cppcheck-${{ github.event.pull_request.number }}"
|
||||||
@ -22,13 +18,27 @@ jobs:
|
|||||||
if: github.event.pull_request.draft == false
|
if: github.event.pull_request.draft == false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: filter
|
||||||
|
with:
|
||||||
|
filters: |
|
||||||
|
cpp:
|
||||||
|
- 'src/**'
|
||||||
|
- '!README.md'
|
||||||
|
- '!docs/**'
|
||||||
|
|
||||||
- name: Setup python
|
- name: Setup python
|
||||||
|
if: steps.filter.outputs.cpp == 'true'
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
- name: AzerothCore codestyle
|
- name: AzerothCore codestyle
|
||||||
|
if: steps.filter.outputs.cpp == 'true'
|
||||||
run: python ./apps/codestyle/codestyle-cpp.py
|
run: python ./apps/codestyle/codestyle-cpp.py
|
||||||
|
|
||||||
- name: C++ Advanced
|
- name: C++ Advanced
|
||||||
|
if: steps.filter.outputs.cpp == 'true'
|
||||||
run: |
|
run: |
|
||||||
sudo apt update -y
|
sudo apt update -y
|
||||||
sudo apt install -y cppcheck
|
sudo apt install -y cppcheck
|
||||||
|
|||||||
@ -192,9 +192,12 @@ AiPlayerbot.AutoInitOnly = 0
|
|||||||
# Default: 1.0 (same with the player)
|
# Default: 1.0 (same with the player)
|
||||||
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
|
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
|
# AllowLearnTrainerSpells
|
||||||
AiPlayerbot.AutoTrainSpells = yes
|
# 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
|
# Default: food, taxi, and raid are enabled
|
||||||
AiPlayerbot.BotCheats = "food,taxi,raid"
|
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["runaway"] = &ActionContext::runaway;
|
||||||
creators["stay"] = &ActionContext::stay;
|
creators["stay"] = &ActionContext::stay;
|
||||||
creators["sit"] = &ActionContext::sit;
|
creators["sit"] = &ActionContext::sit;
|
||||||
|
creators["aggressive target"] = &ActionContext::aggressive_target;
|
||||||
creators["attack anything"] = &ActionContext::attack_anything;
|
creators["attack anything"] = &ActionContext::attack_anything;
|
||||||
creators["attack least hp target"] = &ActionContext::attack_least_hp_target;
|
creators["attack least hp target"] = &ActionContext::attack_least_hp_target;
|
||||||
creators["attack enemy player"] = &ActionContext::attack_enemy_player;
|
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_what_to_do(PlayerbotAI* botAI) { return new SuggestWhatToDoAction(botAI); }
|
||||||
static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); }
|
static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); }
|
||||||
static Action* suggest_dungeon(PlayerbotAI* botAI) { return new SuggestDungeonAction(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_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); }
|
||||||
static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); }
|
static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); }
|
||||||
static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); }
|
static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); }
|
||||||
|
|||||||
@ -30,6 +30,14 @@ bool AttackEnemyFlagCarrierAction::isUseful()
|
|||||||
PlayerHasFlag::IsCapturingFlag(bot);
|
PlayerHasFlag::IsCapturingFlag(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AggressiveTargetAction::isUseful()
|
||||||
|
{
|
||||||
|
if (bot->IsInCombat())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DropTargetAction::Execute(Event /*event*/)
|
bool DropTargetAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
Unit* target = context->GetValue<Unit*>("current target")->Get();
|
Unit* target = context->GetValue<Unit*>("current target")->Get();
|
||||||
|
|||||||
@ -35,6 +35,15 @@ public:
|
|||||||
std::string const GetTargetName() override { return "tank target"; }
|
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
|
class AttackAnythingAction : public AttackAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
|
||||||
|
#include "InstancePackets.h"
|
||||||
|
|
||||||
bool ResetInstancesAction::Execute(Event /*event*/)
|
bool ResetInstancesAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
WorldPacket packet(CMSG_RESET_INSTANCES, 0);
|
WorldPacket packet(CMSG_RESET_INSTANCES, 0);
|
||||||
bot->GetSession()->HandleResetInstancesOpcode(packet);
|
WorldPackets::Instance::ResetInstances resetInstance(std::move(packet));
|
||||||
|
bot->GetSession()->HandleResetInstancesOpcode(resetInstance);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "RpgSubActions.h"
|
#include "RpgSubActions.h"
|
||||||
|
|
||||||
|
#include "BudgetValues.h"
|
||||||
#include "ChooseRpgTargetAction.h"
|
#include "ChooseRpgTargetAction.h"
|
||||||
#include "EmoteAction.h"
|
#include "EmoteAction.h"
|
||||||
#include "Formations.h"
|
#include "Formations.h"
|
||||||
@ -51,10 +52,15 @@ GuidPosition RpgHelper::guidP() { return AI_VALUE(GuidPosition, "rpg target"); }
|
|||||||
|
|
||||||
ObjectGuid RpgHelper::guid() { return (ObjectGuid)guidP(); }
|
ObjectGuid RpgHelper::guid() { return (ObjectGuid)guidP(); }
|
||||||
|
|
||||||
bool RpgHelper::InRange()
|
bool RpgHelper::InRange()
|
||||||
{
|
{
|
||||||
return guidP() ? (guidP().sqDistance2d(bot) < INTERACTION_DISTANCE * INTERACTION_DISTANCE) : false;
|
GuidPosition targetGuid = guidP();
|
||||||
}
|
if (!targetGuid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bot->GetExactDist2dSq(targetGuid.GetPositionX(), targetGuid.GetPositionY()) <
|
||||||
|
INTERACTION_DISTANCE * INTERACTION_DISTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
void RpgHelper::setFacingTo(GuidPosition guidPosition)
|
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"; }
|
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"; }
|
std::string const RpgTrainAction::ActionName() { return "trainer"; }
|
||||||
|
|
||||||
bool RpgHealAction::Execute(Event /*event*/)
|
bool RpgHealAction::Execute(Event /*event*/)
|
||||||
|
|||||||
@ -165,6 +165,9 @@ class RpgTrainAction : public RpgSubAction
|
|||||||
public:
|
public:
|
||||||
RpgTrainAction(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgSubAction(botAI, name) {}
|
RpgTrainAction(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgSubAction(botAI, name) {}
|
||||||
|
|
||||||
|
bool isPossible() override;
|
||||||
|
bool isUseful() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string const ActionName() override;
|
std::string const ActionName() override;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,77 +9,120 @@
|
|||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "Playerbots.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))
|
std::string const param = event.getParam();
|
||||||
{
|
|
||||||
if (AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells) < cost)
|
|
||||||
{
|
|
||||||
msg << " - too expensive";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bot->ModifyMoney(-int32(cost));
|
Creature* target = GetCreatureTarget();
|
||||||
}
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell.SpellId);
|
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(target->GetEntry());
|
||||||
if (!spellInfo)
|
if (!trainer)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
bool learned = false;
|
// NOTE: Original version uses SpellIds here, but occasionally only inserts
|
||||||
for (uint8 j = 0; j < 3; ++j)
|
// a single spell ID value from parameters. If someone wants to impl multiple
|
||||||
{
|
// spells as parameters, check SkipSpellsListAction::parseIds as an example.
|
||||||
if (spellInfo->Effects[j].Effect == SPELL_EFFECT_LEARN_SPELL)
|
uint32 spellId = chat->parseSpell(param);
|
||||||
{
|
|
||||||
uint32 learnedSpell = spellInfo->Effects[j].TriggerSpell;
|
|
||||||
if (!bot->HasSpell(learnedSpell))
|
|
||||||
{
|
|
||||||
bot->learnSpell(learnedSpell);
|
|
||||||
learned = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!learned && !bot->HasSpell(tSpell.SpellId))
|
bool learnSpells = param.find("learn") != std::string::npos || sRandomPlayerbotMgr.IsRandomBot(bot) ||
|
||||||
bot->learnSpell(tSpell.SpellId);
|
(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);
|
TellHeader(creature);
|
||||||
|
|
||||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(creature->GetEntry());
|
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(creature->GetEntry());
|
||||||
|
|
||||||
if (!trainer)
|
if (!trainer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float fDiscountMod = bot->GetReputationPriceDiscount(creature);
|
float reputationDiscount = bot->GetReputationPriceDiscount(creature);
|
||||||
uint32 totalCost = 0;
|
uint32 totalCost = 0;
|
||||||
|
|
||||||
for (auto& spell : trainer->GetSpells())
|
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;
|
continue;
|
||||||
|
|
||||||
if (!spells.empty() && spells.find(spell.SpellId) == spells.end())
|
if (!trainer->CanTeachSpell(bot, trainerSpell))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell.SpellId);
|
if (spellId && trainerSpell->SpellId != spellId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(trainerSpell->SpellId);
|
||||||
if (!spellInfo)
|
if (!spellInfo)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32 cost = uint32(floor(spell.MoneyCost * fDiscountMod));
|
uint32 cost = static_cast<uint32>(floor(trainerSpell->MoneyCost * reputationDiscount));
|
||||||
totalCost += cost;
|
totalCost += cost;
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << chat->FormatSpell(spellInfo) << chat->formatMoney(cost);
|
out << chat->FormatSpell(spellInfo) << chat->formatMoney(cost);
|
||||||
|
|
||||||
if (action)
|
if (learnSpells)
|
||||||
(this->*action)(cost, spell, out);
|
Learn(spellInfo, cost, out);
|
||||||
|
|
||||||
botAI->TellMaster(out);
|
botAI->TellMaster(out);
|
||||||
}
|
}
|
||||||
@ -87,55 +130,25 @@ void TrainerAction::Iterate(Creature* creature, TrainerSpellAction action, Spell
|
|||||||
TellFooter(totalCost);
|
TellFooter(totalCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrainerAction::Execute(Event event)
|
void TrainerAction::Learn(SpellInfo const* spellInfo, uint32 cost, std::ostringstream& out)
|
||||||
{
|
{
|
||||||
std::string const text = event.getParam();
|
if (!botAI->HasCheat(BotCheatMask::gold))
|
||||||
|
|
||||||
Player* master = GetMaster();
|
|
||||||
|
|
||||||
Creature* creature = botAI->GetCreature(bot->GetTarget());
|
|
||||||
|
|
||||||
if (master)
|
|
||||||
{
|
{
|
||||||
creature = master->GetSelectedUnit() ? master->GetSelectedUnit()->ToCreature() : nullptr;
|
if (AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells) < cost)
|
||||||
}
|
{
|
||||||
// if (AI_VALUE(GuidPosition, "rpg target") != bot->GetTarget())
|
out << " - too expensive";
|
||||||
// if (master)
|
return;
|
||||||
// creature = botAI->GetCreature(master->GetTarget());
|
}
|
||||||
// else
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
if (!creature || !creature->IsTrainer())
|
bot->ModifyMoney(-static_cast<int32>(cost));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 spell = chat->parseSpell(text);
|
if (spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
|
||||||
SpellIds spells;
|
bot->CastSpell(bot, spellInfo->Id, true);
|
||||||
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);
|
|
||||||
else
|
else
|
||||||
Iterate(creature, nullptr, spells);
|
bot->learnSpell(spellInfo->Id, false);
|
||||||
|
|
||||||
return true;
|
out << " - learned";
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainerAction::TellHeader(Creature* creature)
|
void TrainerAction::TellHeader(Creature* creature)
|
||||||
@ -245,7 +258,8 @@ bool MaintenanceAction::Execute(Event /*event*/)
|
|||||||
if (sPlayerbotAIConfig.altMaintenanceKeyring)
|
if (sPlayerbotAIConfig.altMaintenanceKeyring)
|
||||||
factory.InitKeyring();
|
factory.InitKeyring();
|
||||||
|
|
||||||
if (sPlayerbotAIConfig.altMaintenanceGemsEnchants && bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel)
|
if (sPlayerbotAIConfig.altMaintenanceGemsEnchants &&
|
||||||
|
bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel)
|
||||||
factory.ApplyEnchantAndGemsNew();
|
factory.ApplyEnchantAndGemsNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "ChatHelper.h"
|
#include "ChatHelper.h"
|
||||||
#include "Trainer.h"
|
|
||||||
|
|
||||||
class Creature;
|
class Creature;
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
@ -21,11 +20,14 @@ public:
|
|||||||
TrainerAction(PlayerbotAI* botAI) : Action(botAI, "trainer") {}
|
TrainerAction(PlayerbotAI* botAI) : Action(botAI, "trainer") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
|
bool isUseful() override;
|
||||||
|
bool isPossible() override;
|
||||||
|
Unit* GetTarget() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef void (TrainerAction::*TrainerSpellAction)(uint32, const Trainer::Spell, std::ostringstream& msg);
|
Creature* GetCreatureTarget();
|
||||||
void Iterate(Creature* creature, TrainerSpellAction action, SpellIds& spells);
|
void Iterate(Creature* creature, bool learnSpells, uint32 spellId);
|
||||||
void Learn(uint32 cost, const Trainer::Spell tSpell, std::ostringstream& msg);
|
void Learn(SpellInfo const* spellInfo, uint32 cost, std::ostringstream& out);
|
||||||
void TellHeader(Creature* creature);
|
void TellHeader(Creature* creature);
|
||||||
void TellFooter(uint32 totalCost);
|
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
|
#ifndef _PLAYERBOT_STRATEGYCONTEXT_H
|
||||||
#define _PLAYERBOT_STRATEGYCONTEXT_H
|
#define _PLAYERBOT_STRATEGYCONTEXT_H
|
||||||
|
|
||||||
|
#include "AggressiveStrategy.h"
|
||||||
#include "AttackEnemyPlayersStrategy.h"
|
#include "AttackEnemyPlayersStrategy.h"
|
||||||
#include "BattlegroundStrategy.h"
|
#include "BattlegroundStrategy.h"
|
||||||
#include "CastTimeStrategy.h"
|
#include "CastTimeStrategy.h"
|
||||||
@ -61,6 +62,7 @@ public:
|
|||||||
creators["gather"] = &StrategyContext::gather;
|
creators["gather"] = &StrategyContext::gather;
|
||||||
creators["emote"] = &StrategyContext::emote;
|
creators["emote"] = &StrategyContext::emote;
|
||||||
creators["passive"] = &StrategyContext::passive;
|
creators["passive"] = &StrategyContext::passive;
|
||||||
|
creators["aggressive"] = &StrategyContext::aggressive;
|
||||||
creators["save mana"] = &StrategyContext::auto_save_mana;
|
creators["save mana"] = &StrategyContext::auto_save_mana;
|
||||||
creators["food"] = &StrategyContext::food;
|
creators["food"] = &StrategyContext::food;
|
||||||
creators["chat"] = &StrategyContext::chat;
|
creators["chat"] = &StrategyContext::chat;
|
||||||
@ -144,6 +146,7 @@ private:
|
|||||||
static Strategy* gather(PlayerbotAI* botAI) { return new GatherStrategy(botAI); }
|
static Strategy* gather(PlayerbotAI* botAI) { return new GatherStrategy(botAI); }
|
||||||
static Strategy* emote(PlayerbotAI* botAI) { return new EmoteStrategy(botAI); }
|
static Strategy* emote(PlayerbotAI* botAI) { return new EmoteStrategy(botAI); }
|
||||||
static Strategy* passive(PlayerbotAI* botAI) { return new PassiveStrategy(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* conserve_mana(PlayerbotAI* botAI) { return new ConserveManaStrategy(botAI); }
|
||||||
static Strategy* auto_save_mana(PlayerbotAI* botAI) { return new HealerAutoSaveManaStrategy(botAI); }
|
static Strategy* auto_save_mana(PlayerbotAI* botAI) { return new HealerAutoSaveManaStrategy(botAI); }
|
||||||
static Strategy* food(PlayerbotAI* botAI) { return new UseFoodStrategy(botAI); }
|
static Strategy* food(PlayerbotAI* botAI) { return new UseFoodStrategy(botAI); }
|
||||||
|
|||||||
@ -163,52 +163,19 @@ bool RpgRepairTrigger::IsActive()
|
|||||||
return false;
|
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()
|
bool RpgTrainTrigger::IsActive()
|
||||||
{
|
{
|
||||||
GuidPosition guidP(getGuidP());
|
GuidPosition gp = getGuidP();
|
||||||
|
if (!gp)
|
||||||
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_TRAINER))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CreatureTemplate const* cInfo = guidP.GetCreatureTemplate();
|
if (!gp.HasNpcFlag(UNIT_NPC_FLAG_TRAINER))
|
||||||
|
|
||||||
if (!IsTrainerOf(cInfo, bot))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cInfo->Entry);
|
if (!AI_VALUE(bool, "can train"))
|
||||||
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction);
|
return false;
|
||||||
float fDiscountMod = bot->GetReputationPriceDiscount(factionTemplate);
|
|
||||||
|
|
||||||
for (auto& spell : trainer->GetSpells())
|
return true;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RpgHealTrigger::IsActive()
|
bool RpgHealTrigger::IsActive()
|
||||||
|
|||||||
@ -134,8 +134,6 @@ class RpgTrainTrigger : public RpgTrigger
|
|||||||
public:
|
public:
|
||||||
RpgTrainTrigger(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgTrigger(botAI, name) {}
|
RpgTrainTrigger(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgTrigger(botAI, name) {}
|
||||||
|
|
||||||
static bool IsTrainerOf(CreatureTemplate const* cInfo, Player* pPlayer);
|
|
||||||
|
|
||||||
bool IsActive() override;
|
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 MaxGearRepairCostValue::Calculate()
|
||||||
{
|
{
|
||||||
uint32 TotalCost = 0;
|
uint32 totalCost = 0;
|
||||||
|
|
||||||
for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||||
{
|
{
|
||||||
uint16 pos = ((INVENTORY_SLOT_BAG_0 << 8) | 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));
|
uint32 costs = uint32(maxDurability * dmultiplier * double(dQualitymodEntry->quality_mod));
|
||||||
|
|
||||||
TotalCost += costs;
|
totalCost += costs;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TotalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 RepairCostValue::Calculate()
|
uint32 RepairCostValue::Calculate()
|
||||||
{
|
{
|
||||||
uint32 TotalCost = 0;
|
uint32 totalCost = 0;
|
||||||
|
|
||||||
for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||||
{
|
{
|
||||||
uint16 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
|
uint16 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
|
||||||
@ -86,45 +88,49 @@ uint32 RepairCostValue::Calculate()
|
|||||||
dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class, ditemProto->SubClass)];
|
dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class, ditemProto->SubClass)];
|
||||||
uint32 costs = uint32(LostDurability * dmultiplier * double(dQualitymodEntry->quality_mod));
|
uint32 costs = uint32(LostDurability * dmultiplier * double(dQualitymodEntry->quality_mod));
|
||||||
|
|
||||||
TotalCost += costs;
|
totalCost += costs;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TotalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 TrainCostValue::Calculate()
|
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);
|
Trainer::Spell const* trainerSpell = trainer->GetSpell(spell.SpellId);
|
||||||
|
if (!trainerSpell)
|
||||||
if (!trainer)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (trainer->GetTrainerType() != Trainer::Type::Class || !trainer->IsTrainerValidForPlayer(bot))
|
if (!trainer->CanTeachSpell(bot, trainerSpell))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (auto& spell : trainer->GetSpells())
|
if (spells.find(trainerSpell->SpellId) != spells.end())
|
||||||
{
|
continue;
|
||||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (spells.find(spell.SpellId) != spells.end())
|
totalCost += trainerSpell->MoneyCost;
|
||||||
continue;
|
spells.insert(trainerSpell->SpellId);
|
||||||
|
|
||||||
TotalCost += spell.MoneyCost;
|
|
||||||
spells.insert(spell.SpellId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TotalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 MoneyNeededForValue::Calculate()
|
uint32 MoneyNeededForValue::Calculate()
|
||||||
|
|||||||
@ -44,6 +44,11 @@ bool CanSellValue::Calculate()
|
|||||||
AI_VALUE2(uint32, "item count", "usage " + std::to_string(ITEM_USAGE_AH))) > 1;
|
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 CanFightEqualValue::Calculate() { return AI_VALUE(uint8, "durability") > 20; }
|
||||||
|
|
||||||
bool CanFightEliteValue::Calculate()
|
bool CanFightEliteValue::Calculate()
|
||||||
|
|||||||
@ -58,6 +58,14 @@ public:
|
|||||||
bool Calculate() override;
|
bool Calculate() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CanTrainValue : public BoolCalculatedValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CanTrainValue(PlayerbotAI* botAI) : BoolCalculatedValue(botAI, "can train", 2 * 2000) {}
|
||||||
|
|
||||||
|
bool Calculate() override;
|
||||||
|
};
|
||||||
|
|
||||||
class CanFightEqualValue : public BoolCalculatedValue
|
class CanFightEqualValue : public BoolCalculatedValue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#define _PLAYERBOT_VALUECONTEXT_H
|
#define _PLAYERBOT_VALUECONTEXT_H
|
||||||
|
|
||||||
#include "ActiveSpellValue.h"
|
#include "ActiveSpellValue.h"
|
||||||
|
#include "AggressiveTargetValue.h"
|
||||||
#include "AlwaysLootListValue.h"
|
#include "AlwaysLootListValue.h"
|
||||||
#include "AoeHealValues.h"
|
#include "AoeHealValues.h"
|
||||||
#include "AoeValues.h"
|
#include "AoeValues.h"
|
||||||
@ -51,6 +52,7 @@
|
|||||||
#include "LineTargetValue.h"
|
#include "LineTargetValue.h"
|
||||||
#include "LogLevelValue.h"
|
#include "LogLevelValue.h"
|
||||||
#include "LootStrategyValue.h"
|
#include "LootStrategyValue.h"
|
||||||
|
#include "LootValues.h"
|
||||||
#include "MaintenanceValues.h"
|
#include "MaintenanceValues.h"
|
||||||
#include "ManaSaveLevelValue.h"
|
#include "ManaSaveLevelValue.h"
|
||||||
#include "NearestAdsValue.h"
|
#include "NearestAdsValue.h"
|
||||||
@ -143,6 +145,7 @@ public:
|
|||||||
creators["pet target"] = &ValueContext::pet_target;
|
creators["pet target"] = &ValueContext::pet_target;
|
||||||
creators["old target"] = &ValueContext::old_target;
|
creators["old target"] = &ValueContext::old_target;
|
||||||
creators["grind target"] = &ValueContext::grind_target;
|
creators["grind target"] = &ValueContext::grind_target;
|
||||||
|
creators["aggressive target"] = &ValueContext::aggressive_target;
|
||||||
creators["rti target"] = &ValueContext::rti_target;
|
creators["rti target"] = &ValueContext::rti_target;
|
||||||
creators["rti cc target"] = &ValueContext::rti_cc_target;
|
creators["rti cc target"] = &ValueContext::rti_cc_target;
|
||||||
creators["duel target"] = &ValueContext::duel_target;
|
creators["duel target"] = &ValueContext::duel_target;
|
||||||
@ -272,6 +275,7 @@ public:
|
|||||||
creators["can repair"] = &ValueContext::can_repair;
|
creators["can repair"] = &ValueContext::can_repair;
|
||||||
creators["should sell"] = &ValueContext::should_sell;
|
creators["should sell"] = &ValueContext::should_sell;
|
||||||
creators["can sell"] = &ValueContext::can_sell;
|
creators["can sell"] = &ValueContext::can_sell;
|
||||||
|
creators["can train"] = &ValueContext::can_train;
|
||||||
creators["can fight equal"] = &ValueContext::can_fight_equal;
|
creators["can fight equal"] = &ValueContext::can_fight_equal;
|
||||||
creators["can fight elite"] = &ValueContext::can_fight_elite;
|
creators["can fight elite"] = &ValueContext::can_fight_elite;
|
||||||
creators["can fight boss"] = &ValueContext::can_fight_boss;
|
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* current_cc_target(PlayerbotAI* botAI) { return new CurrentCcTargetValue(botAI); }
|
||||||
static UntypedValue* pet_target(PlayerbotAI* botAI) { return new PetTargetValue(botAI); }
|
static UntypedValue* pet_target(PlayerbotAI* botAI) { return new PetTargetValue(botAI); }
|
||||||
static UntypedValue* grind_target(PlayerbotAI* botAI) { return new GrindTargetValue(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_target(PlayerbotAI* botAI) { return new RtiTargetValue(botAI); }
|
||||||
static UntypedValue* rti_cc_target(PlayerbotAI* botAI) { return new RtiCcTargetValue(botAI); }
|
static UntypedValue* rti_cc_target(PlayerbotAI* botAI) { return new RtiCcTargetValue(botAI); }
|
||||||
static UntypedValue* duel_target(PlayerbotAI* botAI) { return new DuelTargetValue(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* can_repair(PlayerbotAI* botAI) { return new CanRepairValue(botAI); }
|
||||||
static UntypedValue* should_sell(PlayerbotAI* botAI) { return new ShouldSellValue(botAI); }
|
static UntypedValue* should_sell(PlayerbotAI* botAI) { return new ShouldSellValue(botAI); }
|
||||||
static UntypedValue* can_sell(PlayerbotAI* botAI) { return new CanSellValue(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_equal(PlayerbotAI* botAI) { return new CanFightEqualValue(botAI); }
|
||||||
static UntypedValue* can_fight_elite(PlayerbotAI* botAI) { return new CanFightEliteValue(botAI); }
|
static UntypedValue* can_fight_elite(PlayerbotAI* botAI) { return new CanFightEliteValue(botAI); }
|
||||||
static UntypedValue* can_fight_boss(PlayerbotAI* botAI) { return new CanFightBossValue(botAI); }
|
static UntypedValue* can_fight_boss(PlayerbotAI* botAI) { return new CanFightBossValue(botAI); }
|
||||||
|
|||||||
@ -201,8 +201,7 @@ bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if position is within maximum allowed distance from boss
|
// Check if position is within maximum allowed distance from boss
|
||||||
if (boss && sqrt(pow(potentialPos.GetPositionX() - boss->GetPositionX(), 2) +
|
if (boss && boss->GetDistance2d(potentialPos.GetPositionX(), potentialPos.GetPositionY()) > MAX_BOSS_DISTANCE)
|
||||||
pow(potentialPos.GetPositionY() - boss->GetPositionY(), 2)) > MAX_BOSS_DISTANCE)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Score this position based on:
|
// Score this position based on:
|
||||||
@ -215,8 +214,7 @@ bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss)
|
|||||||
float minOrbDist = std::numeric_limits<float>::max();
|
float minOrbDist = std::numeric_limits<float>::max();
|
||||||
for (Unit* orb : orbs)
|
for (Unit* orb : orbs)
|
||||||
{
|
{
|
||||||
float orbDist = sqrt(pow(potentialPos.GetPositionX() - orb->GetPositionX(), 2) +
|
float orbDist = orb->GetDistance2d(potentialPos.GetPositionX(), potentialPos.GetPositionY());
|
||||||
pow(potentialPos.GetPositionY() - orb->GetPositionY(), 2));
|
|
||||||
minOrbDist = std::min(minOrbDist, orbDist);
|
minOrbDist = std::min(minOrbDist, orbDist);
|
||||||
}
|
}
|
||||||
score += minOrbDist * 2.0f; // Weight orb distance more heavily
|
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)
|
// Factor in proximity to boss (closer is better, as long as we're safe from orbs)
|
||||||
if (boss)
|
if (boss)
|
||||||
{
|
{
|
||||||
float bossDist = sqrt(pow(potentialPos.GetPositionX() - boss->GetPositionX(), 2) +
|
float bossDist = boss->GetDistance2d(potentialPos.GetPositionX(), potentialPos.GetPositionY());
|
||||||
pow(potentialPos.GetPositionY() - boss->GetPositionY(), 2));
|
|
||||||
// Add points for being closer to boss (inverse relationship)
|
// Add points for being closer to boss (inverse relationship)
|
||||||
// but only if we're safely away from orbs
|
// but only if we're safely away from orbs
|
||||||
if (minOrbDist > SAFE_DISTANCE)
|
if (minOrbDist > SAFE_DISTANCE)
|
||||||
|
|||||||
@ -128,7 +128,7 @@ namespace GruulsLairHelpers
|
|||||||
Unit* krosh = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "krosh firehand")->Get();
|
Unit* krosh = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "krosh firehand")->Get();
|
||||||
if (krosh && krosh->IsAlive())
|
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)
|
if (dist < KROSH_SAFE_DISTANCE)
|
||||||
isSafe = false;
|
isSafe = false;
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ namespace GruulsLairHelpers
|
|||||||
Unit* maulgar = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "high king maulgar")->Get();
|
Unit* maulgar = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "high king maulgar")->Get();
|
||||||
if (botAI->IsRanged(bot) && maulgar && maulgar->IsAlive())
|
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)
|
if (dist < MAULGAR_SAFE_DISTANCE)
|
||||||
isSafe = false;
|
isSafe = false;
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ namespace GruulsLairHelpers
|
|||||||
|
|
||||||
if (IsPositionSafe(botAI, bot, candidatePos))
|
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)
|
if (movementDistance < bestScore)
|
||||||
{
|
{
|
||||||
bestScore = movementDistance;
|
bestScore = movementDistance;
|
||||||
|
|||||||
@ -1800,8 +1800,7 @@ bool IccRotfaceTankPositionAction::HandleBigOozePositioning(Unit*)
|
|||||||
Unit* puddle = botAI->GetUnit(puddleGuid);
|
Unit* puddle = botAI->GetUnit(puddleGuid);
|
||||||
if (puddle && botAI->GetAura("Ooze Flood", puddle))
|
if (puddle && botAI->GetAura("Ooze Flood", puddle))
|
||||||
{
|
{
|
||||||
float puddleDistance = std::sqrt(std::pow(newX - puddle->GetPositionX(), 2) +
|
float puddleDistance = puddle->GetDistance2d(newX, newY);
|
||||||
std::pow(newY - puddle->GetPositionY(), 2));
|
|
||||||
if (puddleDistance < puddleSafeDistance)
|
if (puddleDistance < puddleSafeDistance)
|
||||||
{
|
{
|
||||||
isSafeFromPuddles = false;
|
isSafeFromPuddles = false;
|
||||||
@ -1921,8 +1920,7 @@ bool IccRotfaceGroupPositionAction::MoveAwayFromPuddle(Unit* boss, Unit* puddle,
|
|||||||
float moveZ = bot->GetPositionZ();
|
float moveZ = bot->GetPositionZ();
|
||||||
|
|
||||||
// Check distances and line of sight
|
// Check distances and line of sight
|
||||||
float newPuddleDistance =
|
float newPuddleDistance = puddle->GetDistance2d(moveX, moveY);
|
||||||
sqrt(pow(moveX - puddle->GetPositionX(), 2) + pow(moveY - puddle->GetPositionY(), 2));
|
|
||||||
float newCenterDistance = sqrt(pow(moveX - ICC_ROTFACE_CENTER_POSITION.GetPositionX(), 2) +
|
float newCenterDistance = sqrt(pow(moveX - ICC_ROTFACE_CENTER_POSITION.GetPositionX(), 2) +
|
||||||
pow(moveY - ICC_ROTFACE_CENTER_POSITION.GetPositionY(), 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
|
// Ensure the target position is at least 30 yards away from the puddle
|
||||||
if (puddle)
|
if (puddle)
|
||||||
{
|
{
|
||||||
float puddleDistance = std::sqrt(std::pow(targetX - puddle->GetPositionX(), 2) +
|
float puddleDistance = puddle->GetDistance2d(targetX, targetY);
|
||||||
std::pow(targetY - puddle->GetPositionY(), 2));
|
|
||||||
if (puddleDistance < puddleSafeDistance)
|
if (puddleDistance < puddleSafeDistance)
|
||||||
{
|
{
|
||||||
// Adjust the target position to move further away from the puddle
|
// 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))
|
if (!puddle || !botAI->HasAura("Ooze Flood", puddle))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float puddleDistance =
|
float puddleDistance = puddle->GetDistance2d(moveX, moveY);
|
||||||
std::sqrt(std::pow(moveX - puddle->GetPositionX(), 2) + std::pow(moveY - puddle->GetPositionY(), 2));
|
|
||||||
if (puddleDistance < 30.0f)
|
if (puddleDistance < 30.0f)
|
||||||
{
|
{
|
||||||
// Adjust the position to move further away from the puddle
|
// 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))
|
if (Aura* grow = unit->GetAura(SPELL_GROW_AURA))
|
||||||
safeDistance += (grow->GetStackAmount() * STACK_MULTIPLIER);
|
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)
|
if (dist < safeDistance)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2650,7 +2646,7 @@ bool IccPutricideGasCloudAction::HandleGaseousBloatMovement(Unit* gasCloud)
|
|||||||
float minGasBombDist = FLT_MAX;
|
float minGasBombDist = FLT_MAX;
|
||||||
for (Unit* bomb : gasBombs)
|
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)
|
if (bombDist < minGasBombDist)
|
||||||
minGasBombDist = bombDist;
|
minGasBombDist = bombDist;
|
||||||
}
|
}
|
||||||
@ -2717,8 +2713,7 @@ bool IccPutricideGasCloudAction::HandleGaseousBloatMovement(Unit* gasCloud)
|
|||||||
float minEmergencyGasBombDist = FLT_MAX;
|
float minEmergencyGasBombDist = FLT_MAX;
|
||||||
for (Unit* bomb : gasBombs)
|
for (Unit* bomb : gasBombs)
|
||||||
{
|
{
|
||||||
float bombDist = sqrt(pow(emergencyPos.GetPositionX() - bomb->GetPositionX(), 2) +
|
float bombDist = bomb->GetDistance2d(emergencyPos.GetPositionX(), emergencyPos.GetPositionY());
|
||||||
pow(emergencyPos.GetPositionY() - bomb->GetPositionY(), 2));
|
|
||||||
if (bombDist < minEmergencyGasBombDist)
|
if (bombDist < minEmergencyGasBombDist)
|
||||||
minEmergencyGasBombDist = bombDist;
|
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)
|
// Maintain minimum distance from center position (if too close to center, move out)
|
||||||
float centerX = ICC_BQL_CENTER_POSITION.GetPositionX();
|
float centerX = ICC_BQL_CENTER_POSITION.GetPositionX();
|
||||||
float centerY = ICC_BQL_CENTER_POSITION.GetPositionY();
|
float centerY = ICC_BQL_CENTER_POSITION.GetPositionY();
|
||||||
float centerDist =
|
float centerDist = bot->GetDistance2d(centerX, centerY);
|
||||||
std::sqrt(std::pow(bot->GetPositionX() - centerX, 2) + std::pow(bot->GetPositionY() - centerY, 2));
|
|
||||||
if (centerDist < MIN_CENTER_DISTANCE && !((boss->GetPositionZ() - bot->GetPositionZ()) > 5.0f))
|
if (centerDist < MIN_CENTER_DISTANCE && !((boss->GetPositionZ() - bot->GetPositionZ()) > 5.0f))
|
||||||
{
|
{
|
||||||
float dx = bot->GetPositionX() - centerX;
|
float dx = bot->GetPositionX() - centerX;
|
||||||
@ -6904,7 +6898,7 @@ bool IccLichKingShadowTrapAction::Execute(Event /*event*/)
|
|||||||
Unit* trap = botAI->GetUnit(trapGuid);
|
Unit* trap = botAI->GetUnit(trapGuid);
|
||||||
if (!trap)
|
if (!trap)
|
||||||
continue;
|
continue;
|
||||||
float distToTrap = sqrt(pow(testX - trap->GetPositionX(), 2) + pow(testY - trap->GetPositionY(), 2));
|
float distToTrap = trap->GetDistance2d(testX, testY);
|
||||||
if (distToTrap < SAFE_DISTANCE)
|
if (distToTrap < SAFE_DISTANCE)
|
||||||
{
|
{
|
||||||
isSafe = false;
|
isSafe = false;
|
||||||
|
|||||||
@ -132,7 +132,7 @@ namespace MagtheridonHelpers
|
|||||||
}
|
}
|
||||||
for (Unit* hazard : debrisHazards)
|
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)
|
if (dist < 9.0f)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ namespace MagtheridonHelpers
|
|||||||
if (!go || go->GetEntry() != GO_BLAZE)
|
if (!go || go->GetEntry() != GO_BLAZE)
|
||||||
continue;
|
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)
|
if (dist < 5.0f)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -262,10 +262,10 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
|||||||
// that removes the distance check and keeps all other checks
|
// that removes the distance check and keeps all other checks
|
||||||
switch (questGiver->GetTypeId())
|
switch (questGiver->GetTypeId())
|
||||||
{
|
{
|
||||||
case TYPEID_UNIT:
|
case TYPEID_UNIT: // Player::GetNPCIfCanInteractWith
|
||||||
{
|
{
|
||||||
ObjectGuid guid = questGiver->GetGUID();
|
ObjectGuid guid = questGiver->GetGUID();
|
||||||
uint32 npcflagmask = UNIT_NPC_FLAG_QUESTGIVER;
|
|
||||||
// unit checks
|
// unit checks
|
||||||
if (!guid)
|
if (!guid)
|
||||||
return false;
|
return false;
|
||||||
@ -292,7 +292,7 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// appropriate npc type
|
// appropriate npc type
|
||||||
if (npcflagmask && !creature->HasNpcFlag(NPCFlags(npcflagmask)))
|
if (!creature->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// not allow interaction under control, but allow with own pets
|
// 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)
|
if (creature->GetReactionTo(bot) <= REP_UNFRIENDLY)
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
case TYPEID_GAMEOBJECT:
|
case TYPEID_GAMEOBJECT: // Player::GetGameObjectIfCanInteractWith
|
||||||
{
|
{
|
||||||
ObjectGuid guid = questGiver->GetGUID();
|
ObjectGuid guid = questGiver->GetGUID();
|
||||||
GameobjectTypes type = GAMEOBJECT_TYPE_QUESTGIVER;
|
|
||||||
if (GameObject* go = bot->GetMap()->GetGameObject(guid))
|
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
|
// Players cannot interact with gameobjects that use the "Point" icon
|
||||||
if (go->GetGOInfo()->IconName == "Point")
|
if (go->GetGOInfo()->IconName == "Point")
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// unused for now
|
// unused for now
|
||||||
|
|||||||
@ -4739,38 +4739,13 @@ void PlayerbotFactory::InitAttunementQuests()
|
|||||||
|
|
||||||
uint32 currentXP = bot->GetUInt32Value(PLAYER_XP);
|
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
|
// Complete all level-appropriate attunement quests for the bot
|
||||||
if (level >= 60)
|
if (level >= 60)
|
||||||
{
|
{
|
||||||
std::list<uint32> questsToComplete;
|
std::list<uint32> questsToComplete;
|
||||||
|
|
||||||
// Check each quest status before adding to the completion list
|
// Check each quest status before adding to the completion list
|
||||||
for (uint32 questId : attunementQuestsTBC)
|
for (uint32 questId : sPlayerbotAIConfig.attunementQuests)
|
||||||
{
|
{
|
||||||
QuestStatus questStatus = bot->GetQuestStatus(questId);
|
QuestStatus questStatus = bot->GetQuestStatus(questId);
|
||||||
|
|
||||||
|
|||||||
@ -45,18 +45,18 @@ void StatsCollector::CollectItemStats(ItemTemplate const* proto)
|
|||||||
switch (proto->Spells[j].SpellTrigger)
|
switch (proto->Spells[j].SpellTrigger)
|
||||||
{
|
{
|
||||||
case ITEM_SPELLTRIGGER_ON_USE:
|
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;
|
break;
|
||||||
case ITEM_SPELLTRIGGER_ON_EQUIP:
|
case ITEM_SPELLTRIGGER_ON_EQUIP:
|
||||||
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, 0);
|
CollectSpellStats(proto->Spells[j].SpellId, 1.0f, Milliseconds(0));
|
||||||
break;
|
break;
|
||||||
case ITEM_SPELLTRIGGER_CHANCE_ON_HIT:
|
case ITEM_SPELLTRIGGER_CHANCE_ON_HIT:
|
||||||
if (type_ & CollectorType::MELEE)
|
if (type_ & CollectorType::MELEE)
|
||||||
{
|
{
|
||||||
if (proto->Spells[j].SpellPPMRate > 0.01f)
|
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
|
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;
|
break;
|
||||||
default:
|
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);
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
|
|
||||||
@ -81,21 +81,21 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
|||||||
if (SpecialSpellFilter(spellId))
|
if (SpecialSpellFilter(spellId))
|
||||||
return;
|
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;
|
bool canNextTrigger = true;
|
||||||
|
|
||||||
uint32 procFlags;
|
uint32 procFlags;
|
||||||
uint32 procChance;
|
uint32 procChance;
|
||||||
if (eventEntry && eventEntry->procFlags)
|
if (eventEntry && eventEntry->ProcFlags)
|
||||||
procFlags = eventEntry->procFlags;
|
procFlags = eventEntry->ProcFlags;
|
||||||
else
|
else
|
||||||
procFlags = spellInfo->ProcFlags;
|
procFlags = spellInfo->ProcFlags;
|
||||||
|
|
||||||
if (eventEntry && eventEntry->customChance)
|
if (eventEntry && eventEntry->Chance)
|
||||||
procChance = eventEntry->customChance;
|
procChance = eventEntry->Chance;
|
||||||
else
|
else
|
||||||
procChance = spellInfo->ProcChance;
|
procChance = spellInfo->ProcChance;
|
||||||
bool lowChance = procChance <= 5;
|
bool lowChance = procChance <= 5;
|
||||||
@ -142,11 +142,11 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
float coverage;
|
float coverage;
|
||||||
if (spellCooldown <= 2000 || spellInfo->GetDuration() == -1)
|
if (spellCooldown.count() <= 2000 || spellInfo->GetDuration() == -1)
|
||||||
coverage = 1.0f;
|
coverage = 1.0f;
|
||||||
else
|
else
|
||||||
coverage =
|
coverage =
|
||||||
std::min(1.0f, (float)spellInfo->GetDuration() / (spellInfo->GetDuration() + spellCooldown));
|
std::min(1.0f, (float)spellInfo->GetDuration() / (spellInfo->GetDuration() + spellCooldown.count()));
|
||||||
|
|
||||||
multiplier *= coverage;
|
multiplier *= coverage;
|
||||||
HandleApplyAura(effectInfo, multiplier, canNextTrigger, triggerCooldown);
|
HandleApplyAura(effectInfo, multiplier, canNextTrigger, triggerCooldown);
|
||||||
@ -155,9 +155,9 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
|||||||
case SPELL_EFFECT_HEAL:
|
case SPELL_EFFECT_HEAL:
|
||||||
{
|
{
|
||||||
/// @todo Handle spell without cooldown
|
/// @todo Handle spell without cooldown
|
||||||
if (!spellCooldown)
|
if (!spellCooldown.count())
|
||||||
break;
|
break;
|
||||||
float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f);
|
float normalizedCd = std::max((float)spellCooldown.count() / 1000, 5.0f);
|
||||||
int32 val = AverageValue(effectInfo);
|
int32 val = AverageValue(effectInfo);
|
||||||
float transfer_multiplier = 1;
|
float transfer_multiplier = 1;
|
||||||
stats[STATS_TYPE_HEAL_POWER] += (float)val / normalizedCd * multiplier * transfer_multiplier;
|
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:
|
case SPELL_EFFECT_ENERGIZE:
|
||||||
{
|
{
|
||||||
/// @todo Handle spell without cooldown
|
/// @todo Handle spell without cooldown
|
||||||
if (!spellCooldown)
|
if (!spellCooldown.count())
|
||||||
break;
|
break;
|
||||||
if (effectInfo.MiscValue != POWER_MANA)
|
if (effectInfo.MiscValue != POWER_MANA)
|
||||||
break;
|
break;
|
||||||
float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f);
|
float normalizedCd = std::max((float)spellCooldown.count() / 1000, 5.0f);
|
||||||
int32 val = AverageValue(effectInfo);
|
int32 val = AverageValue(effectInfo);
|
||||||
float transfer_multiplier = 0.2;
|
float transfer_multiplier = 0.2;
|
||||||
stats[STATS_TYPE_MANA_REGENERATION] += (float)val / normalizedCd * multiplier * transfer_multiplier;
|
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:
|
case SPELL_EFFECT_SCHOOL_DAMAGE:
|
||||||
{
|
{
|
||||||
/// @todo Handle spell without cooldown
|
/// @todo Handle spell without cooldown
|
||||||
if (!spellCooldown)
|
if (!spellCooldown.count())
|
||||||
break;
|
break;
|
||||||
float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f);
|
float normalizedCd = std::max((float)spellCooldown.count() / 1000, 5.0f);
|
||||||
int32 val = AverageValue(effectInfo);
|
int32 val = AverageValue(effectInfo);
|
||||||
if (type_ & (CollectorType::MELEE | CollectorType::RANGED))
|
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)
|
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;
|
uint32 spellFamilyName = 0;
|
||||||
if (eventEntry)
|
if (eventEntry)
|
||||||
{
|
{
|
||||||
spellFamilyName = eventEntry->spellFamilyName;
|
spellFamilyName = eventEntry->SpellFamilyName;
|
||||||
flag96 spellFamilyMask = eventEntry->spellFamilyMask;
|
flag96 spellFamilyMask = eventEntry->SpellFamilyMask;
|
||||||
if (spellFamilyName != 0)
|
if (spellFamilyName != 0)
|
||||||
{
|
{
|
||||||
if (!CheckSpellValidation(spellFamilyName, spellFamilyMask, strict))
|
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,
|
void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float multiplier, bool canNextTrigger,
|
||||||
uint32 triggerCooldown)
|
Milliseconds triggerCooldown)
|
||||||
{
|
{
|
||||||
if (effectInfo.Effect != SPELL_EFFECT_APPLY_AURA)
|
if (effectInfo.Effect != SPELL_EFFECT_APPLY_AURA)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -65,7 +65,7 @@ public:
|
|||||||
StatsCollector(StatsCollector& stats) = default;
|
StatsCollector(StatsCollector& stats) = default;
|
||||||
void Reset();
|
void Reset();
|
||||||
void CollectItemStats(ItemTemplate const* proto);
|
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);
|
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount = 0);
|
||||||
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
||||||
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
||||||
@ -79,7 +79,7 @@ private:
|
|||||||
bool SpecialEnchantFilter(uint32 enchantSpellId);
|
bool SpecialEnchantFilter(uint32 enchantSpellId);
|
||||||
|
|
||||||
void HandleApplyAura(const SpellEffectInfo& effectInfo, float multiplier, bool canNextTrigger,
|
void HandleApplyAura(const SpellEffectInfo& effectInfo, float multiplier, bool canNextTrigger,
|
||||||
uint32 triggerCooldown);
|
Milliseconds triggerCooldown);
|
||||||
float AverageValue(const SpellEffectInfo& effectInfo);
|
float AverageValue(const SpellEffectInfo& effectInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -228,13 +228,13 @@ WorldPosition WorldPosition::offset(WorldPosition* center)
|
|||||||
|
|
||||||
float WorldPosition::size()
|
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)
|
float WorldPosition::distance(WorldPosition* center)
|
||||||
{
|
{
|
||||||
if (GetMapId() == center->GetMapId())
|
if (GetMapId() == center->GetMapId())
|
||||||
return relPoint(center).size();
|
return GetExactDist(center->GetPositionX(), center->GetPositionY(), center->GetPositionZ());
|
||||||
|
|
||||||
// this -> mapTransfer | mapTransfer -> center
|
// this -> mapTransfer | mapTransfer -> center
|
||||||
return TravelMgr::instance().mapTransDistance(*this, *center);
|
return TravelMgr::instance().mapTransDistance(*this, *center);
|
||||||
@ -243,7 +243,7 @@ float WorldPosition::distance(WorldPosition* center)
|
|||||||
float WorldPosition::fDist(WorldPosition* center)
|
float WorldPosition::fDist(WorldPosition* center)
|
||||||
{
|
{
|
||||||
if (GetMapId() == center->GetMapId())
|
if (GetMapId() == center->GetMapId())
|
||||||
return sqrt(sqDistance2d(center));
|
return GetExactDist2d(center->GetPositionX(), center->GetPositionY());
|
||||||
|
|
||||||
// this -> mapTransfer | mapTransfer -> center
|
// this -> mapTransfer | mapTransfer -> center
|
||||||
return TravelMgr::instance().fastMapTransDistance(*this, *center);
|
return TravelMgr::instance().fastMapTransDistance(*this, *center);
|
||||||
|
|||||||
@ -179,8 +179,7 @@ public:
|
|||||||
// Quick square distance in 2d plane.
|
// Quick square distance in 2d plane.
|
||||||
float sqDistance2d(WorldPosition center)
|
float sqDistance2d(WorldPosition center)
|
||||||
{
|
{
|
||||||
return (GetPositionX() - center.GetPositionX()) * (GetPositionX() - center.GetPositionX()) +
|
return GetExactDist2dSq(center.GetPositionX(), center.GetPositionY());
|
||||||
(GetPositionY() - center.GetPositionY()) * (GetPositionY() - center.GetPositionY());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quick square distance calculation without map check. Used for getting the minimum distant points.
|
// Quick square distance calculation without map check. Used for getting the minimum distant points.
|
||||||
@ -193,8 +192,7 @@ public:
|
|||||||
|
|
||||||
float sqDistance2d(WorldPosition* center)
|
float sqDistance2d(WorldPosition* center)
|
||||||
{
|
{
|
||||||
return (GetPositionX() - center->GetPositionX()) * (GetPositionX() - center->GetPositionX()) +
|
return GetExactDist2dSq(center->GetPositionX(), center->GetPositionY());
|
||||||
(GetPositionY() - center->GetPositionY()) * (GetPositionY() - center->GetPositionY());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float sqDistance(WorldPosition* center)
|
float sqDistance(WorldPosition* center)
|
||||||
|
|||||||
@ -179,6 +179,9 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
"179490,141596,160836,160845,179516,176224,181085,176112,128308,128403,"
|
"179490,141596,160836,160845,179516,176224,181085,176112,128308,128403,"
|
||||||
"165739,165738,175245,175970,176325,176327,123329,2560"),
|
"165739,165738,175245,175970,176325,176327,123329,2560"),
|
||||||
disallowedGameObjects);
|
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);
|
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||||
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
||||||
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 500);
|
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 500);
|
||||||
@ -620,7 +623,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
syncQuestWithPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestWithPlayer", true);
|
syncQuestWithPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestWithPlayer", true);
|
||||||
syncQuestForPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestForPlayer", false);
|
syncQuestForPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestForPlayer", false);
|
||||||
dropObsoleteQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.DropObsoleteQuests", true);
|
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);
|
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
|
||||||
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
|
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
|
||||||
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
|
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
|
||||||
|
|||||||
@ -98,6 +98,7 @@ public:
|
|||||||
std::set<uint32> aoeAvoidSpellWhitelist;
|
std::set<uint32> aoeAvoidSpellWhitelist;
|
||||||
bool tellWhenAvoidAoe;
|
bool tellWhenAvoidAoe;
|
||||||
std::set<uint32> disallowedGameObjects;
|
std::set<uint32> disallowedGameObjects;
|
||||||
|
std::set<uint32> attunementQuests;
|
||||||
|
|
||||||
uint32 openGoSpell;
|
uint32 openGoSpell;
|
||||||
bool randomBotAutologin;
|
bool randomBotAutologin;
|
||||||
@ -352,7 +353,7 @@ public:
|
|||||||
bool syncQuestWithPlayer;
|
bool syncQuestWithPlayer;
|
||||||
bool syncQuestForPlayer;
|
bool syncQuestForPlayer;
|
||||||
bool dropObsoleteQuests;
|
bool dropObsoleteQuests;
|
||||||
std::string autoTrainSpells;
|
bool allowLearnTrainerSpells;
|
||||||
bool autoPickTalents;
|
bool autoPickTalents;
|
||||||
bool autoUpgradeEquip;
|
bool autoUpgradeEquip;
|
||||||
int32 hunterWolfPet;
|
int32 hunterWolfPet;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user