mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 00:58:33 +00:00
Updated to support latest master (#1965)
This needs extensive testing. What's important is spells given to bots. Class spells, mounts, professions etc. Make sure they get the spells they should, when they should. Requires https://github.com/mod-playerbots/azerothcore-wotlk/pull/132
This commit is contained in:
@@ -2834,22 +2834,20 @@ inline bool ContainsInternal(ItemTemplate const* proto, uint32 skillId)
|
||||
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
|
||||
for (CreatureTemplateContainer::const_iterator itr = creatures->begin(); itr != creatures->end(); ++itr)
|
||||
{
|
||||
if (itr->second.trainer_type != TRAINER_TYPE_TRADESKILLS)
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(itr->first);
|
||||
|
||||
if (!trainer)
|
||||
continue;
|
||||
|
||||
uint32 trainerId = itr->second.Entry;
|
||||
TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
|
||||
if (!trainer_spells)
|
||||
if (trainer->GetTrainerType() != Trainer::Type::Tradeskill)
|
||||
continue;
|
||||
|
||||
for (TrainerSpellMap::const_iterator iter = trainer_spells->spellList.begin();
|
||||
iter != trainer_spells->spellList.end(); ++iter)
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
TrainerSpell const* tSpell = &iter->second;
|
||||
if (!tSpell || tSpell->reqSkill != skillId)
|
||||
if (spell.ReqSkillLine != skillId)
|
||||
continue;
|
||||
|
||||
if (IsCraftedBy(proto, tSpell->spell))
|
||||
if (IsCraftedBy(proto, spell.SpellId))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2526,66 +2526,35 @@ void PlayerbotFactory::InitAvailableSpells()
|
||||
for (CreatureTemplateContainer::const_iterator i = creatureTemplateContainer->begin();
|
||||
i != creatureTemplateContainer->end(); ++i)
|
||||
{
|
||||
CreatureTemplate const& co = i->second;
|
||||
if (co.trainer_type != TRAINER_TYPE_TRADESKILLS && co.trainer_type != TRAINER_TYPE_CLASS)
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(i->first);
|
||||
|
||||
if (!trainer)
|
||||
continue;
|
||||
|
||||
if (co.trainer_type == TRAINER_TYPE_CLASS && co.trainer_class != bot->getClass())
|
||||
if (trainer->GetTrainerType() != Trainer::Type::Tradeskill &&
|
||||
trainer->GetTrainerType() != Trainer::Type::Class)
|
||||
continue;
|
||||
|
||||
uint32 trainerId = co.Entry;
|
||||
trainerIdCache[bot->getClass()].push_back(trainerId);
|
||||
if (trainer->GetTrainerType() == Trainer::Type::Class &&
|
||||
!trainer->IsTrainerValidForPlayer(bot))
|
||||
continue;
|
||||
|
||||
trainerIdCache[bot->getClass()].push_back(i->first);
|
||||
}
|
||||
}
|
||||
for (uint32 trainerId : trainerIdCache[bot->getClass()])
|
||||
{
|
||||
TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
|
||||
if (!trainer_spells)
|
||||
trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(trainerId);
|
||||
|
||||
if (!trainer_spells)
|
||||
continue;
|
||||
|
||||
for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin();
|
||||
itr != trainer_spells->spellList.end(); ++itr)
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
TrainerSpell const* tSpell = &itr->second;
|
||||
|
||||
if (!tSpell)
|
||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
||||
continue;
|
||||
|
||||
if (tSpell->learnedSpell[0] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[0]))
|
||||
continue;
|
||||
|
||||
TrainerSpellState state = bot->GetTrainerSpellState(tSpell);
|
||||
if (state != TRAINER_SPELL_GREEN)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell->spell);
|
||||
bool learn = true;
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
{
|
||||
if (!tSpell->learnedSpell[j] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[j]))
|
||||
continue;
|
||||
|
||||
if (spellInfo->Effects[j].Effect == SPELL_EFFECT_PROFICIENCY ||
|
||||
(spellInfo->Effects[j].Effect == SPELL_EFFECT_SKILL_STEP &&
|
||||
spellInfo->Effects[j].MiscValue != SKILL_RIDING) ||
|
||||
spellInfo->Effects[j].Effect == SPELL_EFFECT_DUAL_WIELD)
|
||||
{
|
||||
learn = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!learn)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tSpell->IsCastable())
|
||||
bot->CastSpell(bot, tSpell->spell, true);
|
||||
if (spell.IsCastable())
|
||||
bot->CastSpell(bot, spell.SpellId, true);
|
||||
else
|
||||
bot->learnSpell(tSpell->learnedSpell[0], false);
|
||||
bot->learnSpell(spell.SpellId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
void TrainerAction::Learn(uint32 cost, TrainerSpell const* tSpell, std::ostringstream& msg)
|
||||
void TrainerAction::Learn(uint32 cost, const Trainer::Spell tSpell, std::ostringstream& msg)
|
||||
{
|
||||
if (sPlayerbotAIConfig->autoTrainSpells != "free" && !botAI->HasCheat(BotCheatMask::gold))
|
||||
{
|
||||
@@ -23,7 +23,7 @@ void TrainerAction::Learn(uint32 cost, TrainerSpell const* tSpell, std::ostrings
|
||||
bot->ModifyMoney(-int32(cost));
|
||||
}
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell->spell);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell.SpellId);
|
||||
if (!spellInfo)
|
||||
return;
|
||||
|
||||
@@ -41,10 +41,8 @@ void TrainerAction::Learn(uint32 cost, TrainerSpell const* tSpell, std::ostrings
|
||||
}
|
||||
}
|
||||
|
||||
if (!learned && !bot->HasSpell(tSpell->spell))
|
||||
{
|
||||
bot->learnSpell(tSpell->spell);
|
||||
}
|
||||
if (!learned && !bot->HasSpell(tSpell.SpellId))
|
||||
bot->learnSpell(tSpell.SpellId);
|
||||
|
||||
msg << " - learned";
|
||||
}
|
||||
@@ -53,37 +51,35 @@ void TrainerAction::Iterate(Creature* creature, TrainerSpellAction action, Spell
|
||||
{
|
||||
TellHeader(creature);
|
||||
|
||||
TrainerSpellData const* trainer_spells = creature->GetTrainerSpells();
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(creature->GetEntry());
|
||||
|
||||
if (!trainer)
|
||||
return;
|
||||
|
||||
float fDiscountMod = bot->GetReputationPriceDiscount(creature);
|
||||
uint32 totalCost = 0;
|
||||
|
||||
for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin();
|
||||
itr != trainer_spells->spellList.end(); ++itr)
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
TrainerSpell const* tSpell = &itr->second;
|
||||
if (!tSpell)
|
||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
||||
continue;
|
||||
|
||||
TrainerSpellState state = bot->GetTrainerSpellState(tSpell);
|
||||
if (state != TRAINER_SPELL_GREEN)
|
||||
if (!spells.empty() && spells.find(spell.SpellId) == spells.end())
|
||||
continue;
|
||||
|
||||
uint32 spellId = tSpell->spell;
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell.SpellId);
|
||||
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (!spells.empty() && spells.find(tSpell->spell) == spells.end())
|
||||
continue;
|
||||
|
||||
uint32 cost = uint32(floor(tSpell->spellCost * fDiscountMod));
|
||||
uint32 cost = uint32(floor(spell.MoneyCost * fDiscountMod));
|
||||
totalCost += cost;
|
||||
|
||||
std::ostringstream out;
|
||||
out << chat->FormatSpell(spellInfo) << chat->formatMoney(cost);
|
||||
|
||||
if (action)
|
||||
(this->*action)(cost, tSpell, out);
|
||||
(this->*action)(cost, spell, out);
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
@@ -112,15 +108,14 @@ bool TrainerAction::Execute(Event event)
|
||||
if (!creature || !creature->IsTrainer())
|
||||
return false;
|
||||
|
||||
if (!creature->IsValidTrainerForPlayer(bot))
|
||||
{
|
||||
botAI->TellError("This trainer cannot teach me");
|
||||
return false;
|
||||
}
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(creature->GetEntry());
|
||||
|
||||
// check present spell in trainer spell list
|
||||
TrainerSpellData const* cSpells = creature->GetTrainerSpells();
|
||||
if (!cSpells)
|
||||
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;
|
||||
@@ -133,7 +128,7 @@ bool TrainerAction::Execute(Event event)
|
||||
|
||||
if (text.find("learn") != std::string::npos || sRandomPlayerbotMgr->IsRandomBot(bot) ||
|
||||
(sPlayerbotAIConfig->autoTrainSpells != "no" &&
|
||||
(creature->GetCreatureTemplate()->trainer_type != TRAINER_TYPE_TRADESKILLS ||
|
||||
(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);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "Action.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Trainer.h"
|
||||
|
||||
class Creature;
|
||||
class PlayerbotAI;
|
||||
@@ -22,9 +23,9 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
typedef void (TrainerAction::*TrainerSpellAction)(uint32, TrainerSpell const*, std::ostringstream& msg);
|
||||
typedef void (TrainerAction::*TrainerSpellAction)(uint32, const Trainer::Spell, std::ostringstream& msg);
|
||||
void Iterate(Creature* creature, TrainerSpellAction action, SpellIds& spells);
|
||||
void Learn(uint32 cost, TrainerSpell const* tSpell, std::ostringstream& msg);
|
||||
void Learn(uint32 cost, const Trainer::Spell tSpell, std::ostringstream& msg);
|
||||
void TellHeader(Creature* creature);
|
||||
void TellFooter(uint32 totalCost);
|
||||
};
|
||||
|
||||
@@ -302,12 +302,14 @@ 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) &&
|
||||
creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS &&
|
||||
!bot->IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
|
||||
trainer->GetTrainerType() == Trainer::Type::Class &&
|
||||
!trainer->IsTrainerValidForPlayer(bot))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -163,43 +163,18 @@ bool RpgRepairTrigger::IsActive()
|
||||
|
||||
bool RpgTrainTrigger::IsTrainerOf(CreatureTemplate const* cInfo, Player* pPlayer)
|
||||
{
|
||||
switch (cInfo->trainer_type)
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cInfo->Entry);
|
||||
|
||||
if (trainer->GetTrainerType() == Trainer::Type::Mount && trainer->GetTrainerRequirement() != pPlayer->getRace())
|
||||
{
|
||||
case TRAINER_TYPE_CLASS:
|
||||
if (pPlayer->getClass() != cInfo->trainer_class)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case TRAINER_TYPE_PETS:
|
||||
if (pPlayer->getClass() != CLASS_HUNTER)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case TRAINER_TYPE_MOUNTS:
|
||||
if (cInfo->trainer_race && pPlayer->getRace() != cInfo->trainer_race)
|
||||
{
|
||||
// Allowed to train if exalted
|
||||
if (FactionTemplateEntry const* faction_template = sFactionTemplateStore.LookupEntry(cInfo->faction))
|
||||
{
|
||||
if (pPlayer->GetReputationRank(faction_template->faction) == REP_EXALTED)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case TRAINER_TYPE_TRADESKILLS:
|
||||
if (cInfo->trainer_spell && !pPlayer->HasSpell(cInfo->trainer_spell))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false; // checked and error output at creature_template loading
|
||||
}
|
||||
|
||||
return true;
|
||||
return trainer->IsTrainerValidForPlayer(pPlayer);
|
||||
}
|
||||
|
||||
bool RpgTrainTrigger::IsActive()
|
||||
@@ -214,37 +189,17 @@ bool RpgTrainTrigger::IsActive()
|
||||
if (!IsTrainerOf(cInfo, bot))
|
||||
return false;
|
||||
|
||||
// check present spell in trainer spell list
|
||||
TrainerSpellData const* cSpells = sObjectMgr->GetNpcTrainerSpells(guidP.GetEntry());
|
||||
if (!cSpells)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cInfo->Entry);
|
||||
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction);
|
||||
float fDiscountMod = bot->GetReputationPriceDiscount(factionTemplate);
|
||||
|
||||
TrainerSpellMap trainer_spells;
|
||||
if (cSpells)
|
||||
trainer_spells.insert(cSpells->spellList.begin(), cSpells->spellList.end());
|
||||
|
||||
for (TrainerSpellMap::const_iterator itr = trainer_spells.begin(); itr != trainer_spells.end(); ++itr)
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
TrainerSpell const* tSpell = &itr->second;
|
||||
|
||||
if (!tSpell)
|
||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
||||
continue;
|
||||
|
||||
TrainerSpellState state = bot->GetTrainerSpellState(tSpell);
|
||||
if (state != TRAINER_SPELL_GREEN)
|
||||
continue;
|
||||
uint32 cost = uint32(floor(spell.MoneyCost * fDiscountMod));
|
||||
|
||||
uint32 spellId = tSpell->spell;
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
uint32 cost = uint32(floor(tSpell->spellCost * fDiscountMod));
|
||||
if (cost > AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -102,35 +102,24 @@ uint32 TrainCostValue::Calculate()
|
||||
{
|
||||
for (CreatureTemplateContainer::const_iterator itr = creatures->begin(); itr != creatures->end(); ++itr)
|
||||
{
|
||||
if (itr->second.trainer_type != TRAINER_TYPE_CLASS && itr->second.trainer_type != TRAINER_TYPE_TRADESKILLS)
|
||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(itr->first);
|
||||
|
||||
if (!trainer)
|
||||
continue;
|
||||
|
||||
if (itr->second.trainer_type == TRAINER_TYPE_CLASS && itr->second.trainer_class != bot->getClass())
|
||||
if (trainer->GetTrainerType() != Trainer::Type::Class || !trainer->IsTrainerValidForPlayer(bot))
|
||||
continue;
|
||||
|
||||
TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(itr->first);
|
||||
if (!trainer_spells)
|
||||
continue;
|
||||
|
||||
for (TrainerSpellMap::const_iterator iter = trainer_spells->spellList.begin();
|
||||
iter != trainer_spells->spellList.end(); ++iter)
|
||||
for (auto& spell : trainer->GetSpells())
|
||||
{
|
||||
TrainerSpell const* tSpell = &iter->second;
|
||||
if (!tSpell)
|
||||
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
|
||||
continue;
|
||||
|
||||
TrainerSpellState state = bot->GetTrainerSpellState(tSpell);
|
||||
if (state != TRAINER_SPELL_GREEN)
|
||||
if (spells.find(spell.SpellId) != spells.end())
|
||||
continue;
|
||||
|
||||
if (itr->second.trainer_type == TRAINER_TYPE_TRADESKILLS)
|
||||
continue;
|
||||
|
||||
if (spells.find(tSpell->spell) != spells.end())
|
||||
continue;
|
||||
|
||||
TotalCost += tSpell->spellCost;
|
||||
spells.insert(tSpell->spell);
|
||||
TotalCost += spell.MoneyCost;
|
||||
spells.insert(spell.SpellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user