mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-22 13:06:23 +00:00
Big update.
This commit is contained in:
24
src/strategy/actions/AcceptBattlegroundInvitationAction.cpp
Normal file
24
src/strategy/actions/AcceptBattlegroundInvitationAction.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AcceptBattlegroundInvitationAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool AcceptBgInvitationAction::Execute(Event event)
|
||||
{
|
||||
uint8 type = 0; // arenatype if arena
|
||||
uint8 unk2 = 0; // unk, can be 0x0 (may be if was invited?) and 0x1
|
||||
uint32 bgTypeId_ = BATTLEGROUND_WS; // type id from dbc
|
||||
uint16 unk = 0x1F90; // 0x1F90 constant?*/
|
||||
uint8 action = 1;
|
||||
|
||||
WorldPacket packet(CMSG_BATTLEFIELD_PORT, 20);
|
||||
packet << type << unk2 << (uint32)bgTypeId_ << unk << action;
|
||||
//packet << bgTypeId_ << action;
|
||||
bot->GetSession()->HandleBattleFieldPortOpcode(packet);
|
||||
|
||||
botAI->ResetStrategies();
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/AcceptBattlegroundInvitationAction.h
Normal file
20
src/strategy/actions/AcceptBattlegroundInvitationAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ACCEPTBATTLEGROUNDINVITATIONACTION_H
|
||||
#define _PLAYERBOT_ACCEPTBATTLEGROUNDINVITATIONACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AcceptBgInvitationAction : public Action
|
||||
{
|
||||
public:
|
||||
AcceptBgInvitationAction(PlayerbotAI* botAI) : Action(botAI, "accept bg invitatio") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
24
src/strategy/actions/AcceptDuelAction.cpp
Normal file
24
src/strategy/actions/AcceptDuelAction.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AcceptDuelAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool AcceptDuelAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
|
||||
ObjectGuid flagGuid;
|
||||
p >> flagGuid;
|
||||
ObjectGuid playerGuid;
|
||||
p >> playerGuid;
|
||||
|
||||
WorldPacket packet(CMSG_DUEL_ACCEPTED, 8);
|
||||
packet << flagGuid;
|
||||
bot->GetSession()->HandleDuelAcceptedOpcode(packet);
|
||||
|
||||
botAI->ResetStrategies();
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/AcceptDuelAction.h
Normal file
20
src/strategy/actions/AcceptDuelAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ACCEPTDUELACTION_H
|
||||
#define _PLAYERBOT_ACCEPTDUELACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AcceptDuelAction : public Action
|
||||
{
|
||||
public:
|
||||
AcceptDuelAction(PlayerbotAI* botAI) : Action(botAI, "accept duel") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
45
src/strategy/actions/AcceptInvitationAction.cpp
Normal file
45
src/strategy/actions/AcceptInvitationAction.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AcceptInvitationAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotSecurity.h"
|
||||
|
||||
bool AcceptInvitationAction::Execute(Event event)
|
||||
{
|
||||
Group* grp = bot->GetGroupInvite();
|
||||
if (!grp)
|
||||
return false;
|
||||
|
||||
Player* inviter = ObjectAccessor::FindPlayer(grp->GetLeaderGUID());
|
||||
if (!inviter)
|
||||
return false;
|
||||
|
||||
if (!botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, inviter))
|
||||
{
|
||||
WorldPacket data(SMSG_GROUP_DECLINE, 10);
|
||||
data << bot->GetName();
|
||||
inviter->SendDirectMessage(&data);
|
||||
bot->UninviteFromGroup();
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldPacket p;
|
||||
uint32 roles_mask = 0;
|
||||
p << roles_mask;
|
||||
bot->GetSession()->HandleGroupAcceptOpcode(p);
|
||||
|
||||
if (sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
botAI->SetMaster(inviter);
|
||||
//else
|
||||
//sPlayerbotDbStore->Save(botAI);
|
||||
|
||||
botAI->ResetStrategies();
|
||||
botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT);
|
||||
botAI->Reset();
|
||||
|
||||
botAI->TellMaster("Hello");
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/AcceptInvitationAction.h
Normal file
20
src/strategy/actions/AcceptInvitationAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ACCEPTINVITATIONACTION_H
|
||||
#define _PLAYERBOT_ACCEPTINVITATIONACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AcceptInvitationAction : public Action
|
||||
{
|
||||
public:
|
||||
AcceptInvitationAction(PlayerbotAI* botAI) : Action(botAI, "accept invitation") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
128
src/strategy/actions/AcceptQuestAction.cpp
Normal file
128
src/strategy/actions/AcceptQuestAction.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AcceptQuestAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
void AcceptAllQuestsAction::ProcessQuest(Quest const* quest, WorldObject* questGiver)
|
||||
{
|
||||
AcceptQuest(quest, questGiver->GetGUID());
|
||||
bot->PlayDistanceSound(620);
|
||||
}
|
||||
|
||||
bool AcceptQuestAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
Player* bot = botAI->GetBot();
|
||||
ObjectGuid guid;
|
||||
uint32 quest = 0;
|
||||
|
||||
std::string const text = event.getParam();
|
||||
PlayerbotChatHandler ch(master);
|
||||
quest = ch.extractQuestId(text);
|
||||
|
||||
if (event.getPacket().empty())
|
||||
{
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||
for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(*i);
|
||||
if (unit && quest && unit->hasQuest(quest))
|
||||
{
|
||||
guid = unit->GetGUID();
|
||||
break;
|
||||
}
|
||||
|
||||
if (unit && text == "*" && bot->GetDistance(unit) <= INTERACTION_DISTANCE)
|
||||
QuestAction::ProcessQuests(unit);
|
||||
}
|
||||
|
||||
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects");
|
||||
for (GuidVector::iterator i = gos.begin(); i != gos.end(); i++)
|
||||
{
|
||||
GameObject* go = botAI->GetGameObject(*i);
|
||||
if (go && quest && go->hasQuest(quest))
|
||||
{
|
||||
guid = go->GetGUID();
|
||||
break;
|
||||
}
|
||||
|
||||
if (go && text == "*" && bot->GetDistance(go) <= INTERACTION_DISTANCE)
|
||||
QuestAction::ProcessQuests(go);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldPacket& p = event.getPacket();
|
||||
p.rpos(0);
|
||||
p >> guid >> quest;
|
||||
}
|
||||
|
||||
if (!quest || !guid)
|
||||
return false;
|
||||
|
||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest);
|
||||
if (!qInfo)
|
||||
return false;
|
||||
|
||||
return AcceptQuest(qInfo, guid);
|
||||
}
|
||||
|
||||
bool AcceptQuestShareAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
Player* bot = botAI->GetBot();
|
||||
|
||||
WorldPacket& p = event.getPacket();
|
||||
p.rpos(0);
|
||||
uint32 quest;
|
||||
p >> quest;
|
||||
|
||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest);
|
||||
if (!qInfo || !bot->GetDivider())
|
||||
return false;
|
||||
|
||||
quest = qInfo->GetQuestId();
|
||||
if (!bot->CanTakeQuest(qInfo, false))
|
||||
{
|
||||
// can't take quest
|
||||
bot->SetDivider(ObjectGuid::Empty);
|
||||
botAI->TellError("I can't take this quest");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bot->GetDivider().IsEmpty())
|
||||
{
|
||||
// send msg to quest giving player
|
||||
master->SendPushToPartyResponse(bot, QUEST_PARTY_MSG_ACCEPT_QUEST);
|
||||
bot->SetDivider(ObjectGuid::Empty);
|
||||
}
|
||||
|
||||
if (bot->CanAddQuest( qInfo, false))
|
||||
{
|
||||
bot->AddQuest(qInfo, master);
|
||||
|
||||
if (bot->CanCompleteQuest(quest))
|
||||
bot->CompleteQuest(quest);
|
||||
|
||||
// Runsttren: did not add typeid switch from WorldSession::HandleQuestgiverAcceptQuestOpcode!
|
||||
// I think it's not needed, cause typeid should be TYPEID_PLAYER - and this one is not handled
|
||||
// there and there is no default case also.
|
||||
|
||||
if (qInfo->GetSrcSpell() > 0)
|
||||
{
|
||||
bot->CastSpell( bot, qInfo->GetSrcSpell(), true);
|
||||
}
|
||||
|
||||
botAI->TellMaster("Quest accepted");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
37
src/strategy/actions/AcceptQuestAction.h
Normal file
37
src/strategy/actions/AcceptQuestAction.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ACCEPTQUESTACTION_H
|
||||
#define _PLAYERBOT_ACCEPTQUESTACTION_H
|
||||
|
||||
#include "QuestAction.h"
|
||||
|
||||
class Quest;
|
||||
class PlayerbotAI;
|
||||
class WorldObject;
|
||||
|
||||
class AcceptAllQuestsAction : public QuestAction
|
||||
{
|
||||
public:
|
||||
AcceptAllQuestsAction(PlayerbotAI* botAI, std::string const name = "accept all quests") : QuestAction(botAI, name) { }
|
||||
|
||||
protected:
|
||||
void ProcessQuest(Quest const* quest, WorldObject* questGiver) override;
|
||||
};
|
||||
|
||||
class AcceptQuestAction : public AcceptAllQuestsAction
|
||||
{
|
||||
public:
|
||||
AcceptQuestAction(PlayerbotAI* botAI) : AcceptAllQuestsAction(botAI, "accept quest") { }
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class AcceptQuestShareAction : public Action
|
||||
{
|
||||
public:
|
||||
AcceptQuestShareAction(PlayerbotAI* botAI) : Action(botAI, "accept quest share") { }
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
27
src/strategy/actions/AcceptResurrectAction.cpp
Normal file
27
src/strategy/actions/AcceptResurrectAction.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AcceptResurrectAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool AcceptResurrectAction::Execute(Event event)
|
||||
{
|
||||
if (bot->IsAlive())
|
||||
return false;
|
||||
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
ObjectGuid guid;
|
||||
p >> guid;
|
||||
|
||||
WorldPacket packet(CMSG_RESURRECT_RESPONSE, 8 + 1);
|
||||
packet << guid;
|
||||
packet << uint8(1); // accept
|
||||
bot->GetSession()->HandleResurrectResponseOpcode(packet); // queue the packet to get around race condition
|
||||
|
||||
botAI->ChangeEngine(BOT_STATE_NON_COMBAT);
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/AcceptResurrectAction.h
Normal file
20
src/strategy/actions/AcceptResurrectAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ACCEPTRESURRECTACTION_H
|
||||
#define _PLAYERBOT_ACCEPTRESURRECTACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AcceptResurrectAction : public Action
|
||||
{
|
||||
public:
|
||||
AcceptResurrectAction(PlayerbotAI* botAI) : Action(botAI, "accept resurrect") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
382
src/strategy/actions/ActionContext.h
Normal file
382
src/strategy/actions/ActionContext.h
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ACTIONCONTEXT_H
|
||||
#define _PLAYERBOT_ACTIONCONTEXT_H
|
||||
|
||||
#include "AddLootAction.h"
|
||||
#include "AttackAction.h"
|
||||
#include "AutoLearnSpellAction.h"
|
||||
#include "BattlegroundTactics.h"
|
||||
#include "BattlegroundJoinAction.h"
|
||||
#include "BuyAction.h"
|
||||
#include "CastCustomSpellAction.h"
|
||||
#include "ChangeStrategyAction.h"
|
||||
#include "ChangeTalentsAction.h"
|
||||
#include "CheckMailAction.h"
|
||||
#include "CheckValuesAction.h"
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "ChooseTravelTargetAction.h"
|
||||
#include "ChooseRpgTargetAction.h"
|
||||
#include "CombatActions.h"
|
||||
#include "DelayAction.h"
|
||||
#include "DestroyItemAction.h"
|
||||
#include "EmoteAction.h"
|
||||
#include "GenericActions.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "GiveItemAction.h"
|
||||
#include "GreetAction.h"
|
||||
#include "GuildAcceptAction.h"
|
||||
#include "GuildCreateActions.h"
|
||||
#include "GuildManagementActions.h"
|
||||
#include "ImbueAction.h"
|
||||
#include "InviteToGroupAction.h"
|
||||
#include "LeaveGroupAction.h"
|
||||
#include "FollowActions.h"
|
||||
#include "LootAction.h"
|
||||
#include "MovementActions.h"
|
||||
#include "MoveToRpgTargetAction.h"
|
||||
#include "MoveToTravelTargetAction.h"
|
||||
#include "NonCombatActions.h"
|
||||
#include "OutfitAction.h"
|
||||
#include "PositionAction.h"
|
||||
#include "RandomBotUpdateAction.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "ReleaseSpiritAction.h"
|
||||
#include "RemoveAuraAction.h"
|
||||
#include "ResetInstancesAction.h"
|
||||
#include "RevealGatheringItemAction.h"
|
||||
#include "RpgAction.h"
|
||||
#include "RpgSubActions.h"
|
||||
#include "RtiAction.h"
|
||||
#include "SayAction.h"
|
||||
#include "StayActions.h"
|
||||
#include "SuggestWhatToDoAction.h"
|
||||
#include "TravelAction.h"
|
||||
#include "XpGainAction.h"
|
||||
#include "VehicleActions.h"
|
||||
#include "WorldBuffAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class ActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
public:
|
||||
ActionContext()
|
||||
{
|
||||
creators["mark rti"] = &ActionContext::mark_rti;
|
||||
creators["set return position"] = &ActionContext::set_return_position;
|
||||
creators["rpg"] = &ActionContext::rpg;
|
||||
creators["crpg"] = &ActionContext::crpg;
|
||||
creators["choose rpg target"] = &ActionContext::choose_rpg_target;
|
||||
creators["move to rpg target"] = &ActionContext::move_to_rpg_target;
|
||||
creators["travel"] = &ActionContext::travel;
|
||||
creators["choose travel target"] = &ActionContext::choose_travel_target;
|
||||
creators["move to travel target"] = &ActionContext::move_to_travel_target;
|
||||
creators["move out of collision"] = &ActionContext::move_out_of_collision;
|
||||
creators["move out of collision"] = &ActionContext::move_out_of_collision;
|
||||
creators["move random"] = &ActionContext::move_random;
|
||||
creators["attack"] = &ActionContext::melee;
|
||||
creators["melee"] = &ActionContext::melee;
|
||||
creators["switch to melee"] = &ActionContext::switch_to_melee;
|
||||
creators["switch to ranged"] = &ActionContext::switch_to_ranged;
|
||||
creators["reach spell"] = &ActionContext::ReachSpell;
|
||||
creators["reach melee"] = &ActionContext::ReachMelee;
|
||||
creators["reach party member to heal"] = &ActionContext::reach_party_member_to_heal;
|
||||
creators["flee"] = &ActionContext::flee;
|
||||
creators["flee with pet"] = &ActionContext::flee_with_pet;
|
||||
creators["gift of the naaru"] = &ActionContext::gift_of_the_naaru;
|
||||
creators["shoot"] = &ActionContext::shoot;
|
||||
creators["lifeblood"] = &ActionContext::lifeblood;
|
||||
creators["arcane torrent"] = &ActionContext::arcane_torrent;
|
||||
creators["end pull"] = &ActionContext::end_pull;
|
||||
creators["healthstone"] = &ActionContext::healthstone;
|
||||
creators["healing potion"] = &ActionContext::healing_potion;
|
||||
creators["mana potion"] = &ActionContext::mana_potion;
|
||||
creators["food"] = &ActionContext::food;
|
||||
creators["drink"] = &ActionContext::drink;
|
||||
creators["tank assist"] = &ActionContext::tank_assist;
|
||||
creators["dps assist"] = &ActionContext::dps_assist;
|
||||
creators["dps aoe"] = &ActionContext::dps_aoe;
|
||||
creators["attack rti target"] = &ActionContext::attack_rti_target;
|
||||
creators["loot"] = &ActionContext::loot;
|
||||
creators["add loot"] = &ActionContext::add_loot;
|
||||
creators["add gathering loot"] = &ActionContext::add_gathering_loot;
|
||||
creators["add all loot"] = &ActionContext::add_all_loot;
|
||||
creators["release loot"] = &ActionContext::release_loot;
|
||||
creators["shoot"] = &ActionContext::shoot;
|
||||
creators["follow"] = &ActionContext::follow;
|
||||
creators["flee to master"] = &ActionContext::flee_to_master;
|
||||
creators["runaway"] = &ActionContext::runaway;
|
||||
creators["stay"] = &ActionContext::stay;
|
||||
creators["sit"] = &ActionContext::sit;
|
||||
creators["attack anything"] = &ActionContext::attack_anything;
|
||||
creators["attack least hp target"] = &ActionContext::attack_least_hp_target;
|
||||
creators["attack enemy player"] = &ActionContext::attack_enemy_player;
|
||||
creators["emote"] = &ActionContext::emote;
|
||||
creators["talk"] = &ActionContext::talk;
|
||||
creators["suggest what to do"] = &ActionContext::suggest_what_to_do;
|
||||
creators["suggest trade"] = &ActionContext::suggest_trade;
|
||||
creators["return"] = &ActionContext::_return;
|
||||
creators["move to loot"] = &ActionContext::move_to_loot;
|
||||
creators["open loot"] = &ActionContext::open_loot;
|
||||
creators["guard"] = &ActionContext::guard;
|
||||
creators["move out of enemy contact"] = &ActionContext::move_out_of_enemy_contact;
|
||||
creators["set facing"] = &ActionContext::set_facing;
|
||||
creators["set behind"] = &ActionContext::set_behind;
|
||||
creators["attack duel opponent"] = &ActionContext::attack_duel_opponent;
|
||||
creators["drop target"] = &ActionContext::drop_target;
|
||||
creators["check mail"] = &ActionContext::check_mail;
|
||||
creators["say"] = &ActionContext::say;
|
||||
creators["reveal gathering item"] = &ActionContext::reveal_gathering_item;
|
||||
creators["outfit"] = &ActionContext::outfit;
|
||||
creators["random bot update"] = &ActionContext::random_bot_update;
|
||||
creators["delay"] = &ActionContext::delay;
|
||||
creators["greet"] = &ActionContext::greet;
|
||||
creators["check values"] = &ActionContext::check_values;
|
||||
creators["ra"] = &ActionContext::ra;
|
||||
creators["give food"] = &ActionContext::give_food;
|
||||
creators["give water"] = &ActionContext::give_water;
|
||||
creators["apply poison"] = &ActionContext::apply_poison;
|
||||
creators["apply stone"] = &ActionContext::apply_stone;
|
||||
creators["apply oil"] = &ActionContext::apply_oil;
|
||||
creators["try emergency"] = &ActionContext::try_emergency;
|
||||
creators["mount"] = &ActionContext::mount;
|
||||
creators["war stomp"] = &ActionContext::war_stomp;
|
||||
creators["auto talents"] = &ActionContext::auto_talents;
|
||||
creators["auto learn spell"] = &ActionContext::auto_learn_spell;
|
||||
creators["xp gain"] = &ActionContext::xp_gain;
|
||||
creators["invite nearby"] = &ActionContext::invite_nearby;
|
||||
creators["invite guild"] = &ActionContext::invite_guild;
|
||||
creators["leave far away"] = &ActionContext::leave_far_away;
|
||||
creators["move to dark portal"] = &ActionContext::move_to_dark_portal;
|
||||
creators["move from dark portal"] = &ActionContext::move_from_dark_portal;
|
||||
creators["use dark portal azeroth"] = &ActionContext::use_dark_portal_azeroth;
|
||||
creators["world buff"] = &ActionContext::world_buff;
|
||||
creators["hearthstone"] = &ActionContext::hearthstone;
|
||||
creators["cast random spell"] = &ActionContext::cast_random_spell;
|
||||
creators["free bg join"] = &ActionContext::free_bg_join;
|
||||
creators["use random recipe"] = &ActionContext::use_random_recipe;
|
||||
creators["use random quest item"] = &ActionContext::use_random_quest_item;
|
||||
creators["craft random item"] = &ActionContext::craft_random_item;
|
||||
creators["smart destroy item"] = &ActionContext::smart_destroy_item;
|
||||
creators["disenchant random item"] = &ActionContext::disenchant_random_item;
|
||||
creators["enchant random item"] = &ActionContext::enchant_random_item;
|
||||
creators["reset instances"] = &ActionContext::reset_instances;
|
||||
creators["buy petition"] = &ActionContext::buy_petition;
|
||||
creators["offer petition"] = &ActionContext::offer_petition;
|
||||
creators["offer petition nearby"] = &ActionContext::offer_petition_nearby;
|
||||
creators["turn in petition"] = &ActionContext::turn_in_petition;
|
||||
creators["buy tabard"] = &ActionContext::buy_tabard;
|
||||
creators["guild manage nearby"] = &ActionContext::guild_manage_nearby;
|
||||
|
||||
// BG Tactics
|
||||
creators["bg tactics"] = &ActionContext::bg_tactics;
|
||||
creators["bg move to start"] = &ActionContext::bg_move_to_start;
|
||||
creators["bg move to objective"] = &ActionContext::bg_move_to_objective;
|
||||
creators["bg select objective"] = &ActionContext::bg_select_objective;
|
||||
creators["bg check objective"] = &ActionContext::bg_check_objective;
|
||||
creators["bg attack fc"] = &ActionContext::bg_attack_fc;
|
||||
creators["bg protect fc"] = &ActionContext::bg_protect_fc;
|
||||
creators["bg use buff"] = &ActionContext::bg_use_buff;
|
||||
creators["attack enemy flag carrier"] = &ActionContext::attack_enemy_fc;
|
||||
creators["bg check flag"] = &ActionContext::bg_check_flag;
|
||||
|
||||
// Vehicles
|
||||
creators["enter vehicle"] = &ActionContext::enter_vehicle;
|
||||
creators["leave vehicle"] = &ActionContext::leave_vehicle;
|
||||
creators["hurl boulder"] = &ActionContext::hurl_boulder;
|
||||
creators["ram"] = &ActionContext::ram;
|
||||
creators["steam rush"] = &ActionContext::steam_rush;
|
||||
creators["steam blast"] = &ActionContext::steam_blast;
|
||||
creators["napalm"] = &ActionContext::napalm;
|
||||
creators["fire cannon"] = &ActionContext::fire_cannon;
|
||||
creators["incendiary rocket"] = &ActionContext::incendiary_rocket;
|
||||
creators["rocket blast"] = &ActionContext::rocket_blast;
|
||||
creators["blade salvo"] = &ActionContext::blade_salvo;
|
||||
creators["glaive throw"] = &ActionContext::glaive_throw;
|
||||
|
||||
//Rpg
|
||||
creators["rpg stay"] = &ActionContext::rpg_stay;
|
||||
creators["rpg work"] = &ActionContext::rpg_work;
|
||||
creators["rpg emote"] = &ActionContext::rpg_emote;
|
||||
creators["rpg cancel"] = &ActionContext::rpg_cancel;
|
||||
creators["rpg taxi"] = &ActionContext::rpg_taxi;
|
||||
creators["rpg discover"] = &ActionContext::rpg_discover;
|
||||
creators["rpg start quest"] = &ActionContext::rpg_start_quest;
|
||||
creators["rpg end quest"] = &ActionContext::rpg_end_quest;
|
||||
creators["rpg buy"] = &ActionContext::rpg_buy;
|
||||
creators["rpg sell"] = &ActionContext::rpg_sell;
|
||||
creators["rpg repair"] = &ActionContext::rpg_repair;
|
||||
creators["rpg train"] = &ActionContext::rpg_train;
|
||||
creators["rpg heal"] = &ActionContext::rpg_heal;
|
||||
creators["rpg home bind"] = &ActionContext::rpg_home_bind;
|
||||
creators["rpg queue bg"] = &ActionContext::rpg_queue_bg;
|
||||
creators["rpg buy petition"] = &ActionContext::rpg_buy_petition;
|
||||
creators["rpg use"] = &ActionContext::rpg_use;
|
||||
creators["rpg spell"] = &ActionContext::rpg_spell;
|
||||
creators["rpg craft"] = &ActionContext::rpg_craft;
|
||||
creators["rpg trade useful"] = &ActionContext::rpg_trade_useful;
|
||||
creators["rpg duel"] = &ActionContext::rpg_duel;
|
||||
}
|
||||
|
||||
private:
|
||||
static Action* give_water(PlayerbotAI* botAI) { return new GiveWaterAction(botAI); }
|
||||
static Action* give_food(PlayerbotAI* botAI) { return new GiveFoodAction(botAI); }
|
||||
static Action* ra(PlayerbotAI* botAI) { return new RemoveAuraAction(botAI); }
|
||||
static Action* mark_rti(PlayerbotAI* botAI) { return new MarkRtiAction(botAI); }
|
||||
static Action* set_return_position(PlayerbotAI* botAI) { return new SetReturnPositionAction(botAI); }
|
||||
static Action* rpg(PlayerbotAI* botAI) { return new RpgAction(botAI); }
|
||||
static Action* crpg(PlayerbotAI* botAI) { return new CRpgAction(botAI); }
|
||||
static Action* choose_rpg_target(PlayerbotAI* botAI) { return new ChooseRpgTargetAction(botAI); }
|
||||
static Action* move_to_rpg_target(PlayerbotAI* botAI) { return new MoveToRpgTargetAction(botAI); }
|
||||
static Action* travel(PlayerbotAI* botAI) { return new TravelAction(botAI); }
|
||||
static Action* choose_travel_target(PlayerbotAI* botAI) { return new ChooseTravelTargetAction(botAI); }
|
||||
static Action* move_to_travel_target(PlayerbotAI* botAI) { return new MoveToTravelTargetAction(botAI); }
|
||||
static Action* move_out_of_collision(PlayerbotAI* botAI) { return new MoveOutOfCollisionAction(botAI); }
|
||||
static Action* move_random(PlayerbotAI* botAI) { return new MoveRandomAction(botAI); }
|
||||
static Action* check_values(PlayerbotAI* botAI) { return new CheckValuesAction(botAI); }
|
||||
static Action* greet(PlayerbotAI* botAI) { return new GreetAction(botAI); }
|
||||
static Action* check_mail(PlayerbotAI* botAI) { return new CheckMailAction(botAI); }
|
||||
static Action* drop_target(PlayerbotAI* botAI) { return new DropTargetAction(botAI); }
|
||||
static Action* attack_duel_opponent(PlayerbotAI* botAI) { return new AttackDuelOpponentAction(botAI); }
|
||||
static Action* guard(PlayerbotAI* botAI) { return new GuardAction(botAI); }
|
||||
static Action* open_loot(PlayerbotAI* botAI) { return new OpenLootAction(botAI); }
|
||||
static Action* move_to_loot(PlayerbotAI* botAI) { return new MoveToLootAction(botAI); }
|
||||
static Action* _return(PlayerbotAI* botAI) { return new ReturnAction(botAI); }
|
||||
static Action* shoot(PlayerbotAI* botAI) { return new CastShootAction(botAI); }
|
||||
static Action* melee(PlayerbotAI* botAI) { return new MeleeAction(botAI); }
|
||||
static Action* switch_to_melee(PlayerbotAI* botAI) { return new SwitchToMeleeAction(botAI); }
|
||||
static Action* switch_to_ranged(PlayerbotAI* botAI) { return new SwitchToRangedAction(botAI); }
|
||||
static Action* ReachSpell(PlayerbotAI* botAI) { return new ReachSpellAction(botAI); }
|
||||
static Action* ReachMelee(PlayerbotAI* botAI) { return new ReachMeleeAction(botAI); }
|
||||
static Action* reach_party_member_to_heal(PlayerbotAI* botAI) { return new ReachPartyMemberToHealAction(botAI); }
|
||||
static Action* flee(PlayerbotAI* botAI) { return new FleeAction(botAI); }
|
||||
static Action* flee_with_pet(PlayerbotAI* botAI) { return new FleeWithPetAction(botAI); }
|
||||
static Action* gift_of_the_naaru(PlayerbotAI* botAI) { return new CastGiftOfTheNaaruAction(botAI); }
|
||||
static Action* lifeblood(PlayerbotAI* botAI) { return new CastLifeBloodAction(botAI); }
|
||||
static Action* arcane_torrent(PlayerbotAI* botAI) { return new CastArcaneTorrentAction(botAI); }
|
||||
static Action* mana_tap(PlayerbotAI* botAI) { return new CastManaTapAction(botAI); }
|
||||
static Action* end_pull(PlayerbotAI* botAI) { return new ChangeCombatStrategyAction(botAI, "-pull"); }
|
||||
|
||||
static Action* emote(PlayerbotAI* botAI) { return new EmoteAction(botAI); }
|
||||
static Action* talk(PlayerbotAI* botAI) { return new TalkAction(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* attack_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); }
|
||||
static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); }
|
||||
static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); }
|
||||
static Action* stay(PlayerbotAI* botAI) { return new StayAction(botAI); }
|
||||
static Action* sit(PlayerbotAI* botAI) { return new SitAction(botAI); }
|
||||
static Action* runaway(PlayerbotAI* botAI) { return new RunAwayAction(botAI); }
|
||||
static Action* follow(PlayerbotAI* botAI) { return new FollowAction(botAI); }
|
||||
static Action* flee_to_master(PlayerbotAI* botAI) { return new FleeToMasterAction(botAI); }
|
||||
static Action* add_gathering_loot(PlayerbotAI* botAI) { return new AddGatheringLootAction(botAI); }
|
||||
static Action* add_loot(PlayerbotAI* botAI) { return new AddLootAction(botAI); }
|
||||
static Action* add_all_loot(PlayerbotAI* botAI) { return new AddAllLootAction(botAI); }
|
||||
static Action* loot(PlayerbotAI* botAI) { return new LootAction(botAI); }
|
||||
static Action* release_loot(PlayerbotAI* botAI) { return new ReleaseLootAction(botAI); }
|
||||
static Action* dps_assist(PlayerbotAI* botAI) { return new DpsAssistAction(botAI); }
|
||||
static Action* dps_aoe(PlayerbotAI* botAI) { return new DpsAoeAction(botAI); }
|
||||
static Action* attack_rti_target(PlayerbotAI* botAI) { return new AttackRtiTargetAction(botAI); }
|
||||
static Action* tank_assist(PlayerbotAI* botAI) { return new TankAssistAction(botAI); }
|
||||
static Action* drink(PlayerbotAI* botAI) { return new DrinkAction(botAI); }
|
||||
static Action* food(PlayerbotAI* botAI) { return new EatAction(botAI); }
|
||||
static Action* mana_potion(PlayerbotAI* botAI) { return new UseManaPotion(botAI); }
|
||||
static Action* healing_potion(PlayerbotAI* botAI) { return new UseHealingPotion(botAI); }
|
||||
static Action* healthstone(PlayerbotAI* botAI) { return new UseItemAction(botAI, "healthstone"); }
|
||||
static Action* move_out_of_enemy_contact(PlayerbotAI* botAI) { return new MoveOutOfEnemyContactAction(botAI); }
|
||||
static Action* set_facing(PlayerbotAI* botAI) { return new SetFacingTargetAction(botAI); }
|
||||
static Action* set_behind(PlayerbotAI* botAI) { return new SetBehindTargetAction(botAI); }
|
||||
static Action* say(PlayerbotAI* botAI) { return new SayAction(botAI); }
|
||||
static Action* reveal_gathering_item(PlayerbotAI* botAI) { return new RevealGatheringItemAction(botAI); }
|
||||
static Action* outfit(PlayerbotAI* botAI) { return new OutfitAction(botAI); }
|
||||
static Action* random_bot_update(PlayerbotAI* botAI) { return new RandomBotUpdateAction(botAI); }
|
||||
static Action* delay(PlayerbotAI* botAI) { return new DelayAction(botAI); }
|
||||
|
||||
static Action* apply_poison(PlayerbotAI* botAI) { return new ImbueWithPoisonAction(botAI); }
|
||||
static Action* apply_oil(PlayerbotAI* botAI) { return new ImbueWithOilAction(botAI); }
|
||||
static Action* apply_stone(PlayerbotAI* botAI) { return new ImbueWithStoneAction(botAI); }
|
||||
static Action* try_emergency(PlayerbotAI* botAI) { return new TryEmergencyAction(botAI); }
|
||||
static Action* mount(PlayerbotAI* botAI) { return new CastSpellAction(botAI, "mount"); }
|
||||
static Action* war_stomp(PlayerbotAI* botAI) { return new CastWarStompAction(botAI); }
|
||||
static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); }
|
||||
static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); }
|
||||
static Action* xp_gain(PlayerbotAI* botAI) { return new XpGainAction(botAI); }
|
||||
static Action* invite_nearby(PlayerbotAI* botAI) { return new InviteNearbyToGroupAction(botAI); }
|
||||
static Action* invite_guild(PlayerbotAI* botAI) { return new InviteGuildToGroupAction(botAI); }
|
||||
static Action* leave_far_away(PlayerbotAI* botAI) { return new LeaveFarAwayAction(botAI); }
|
||||
static Action* move_to_dark_portal(PlayerbotAI* botAI) { return new MoveToDarkPortalAction(botAI); }
|
||||
static Action* use_dark_portal_azeroth(PlayerbotAI* botAI) { return new DarkPortalAzerothAction(botAI); }
|
||||
static Action* move_from_dark_portal(PlayerbotAI* botAI) { return new MoveFromDarkPortalAction(botAI); }
|
||||
static Action* world_buff(PlayerbotAI* botAI) { return new WorldBuffAction(botAI); }
|
||||
static Action* hearthstone(PlayerbotAI* botAI) { return new UseHearthStone(botAI); }
|
||||
static Action* cast_random_spell(PlayerbotAI* botAI) { return new CastRandomSpellAction(botAI); }
|
||||
static Action* free_bg_join(PlayerbotAI* botAI) { return new FreeBGJoinAction(botAI); }
|
||||
|
||||
static Action* use_random_recipe(PlayerbotAI* botAI) { return new UseRandomRecipe(botAI); }
|
||||
static Action* use_random_quest_item(PlayerbotAI* botAI) { return new UseRandomQuestItem(botAI); }
|
||||
static Action* craft_random_item(PlayerbotAI* botAI) { return new CraftRandomItemAction(botAI); }
|
||||
static Action* smart_destroy_item(PlayerbotAI* botAI) { return new SmartDestroyItemAction(botAI); }
|
||||
static Action* disenchant_random_item(PlayerbotAI* botAI) { return new DisEnchantRandomItemAction(botAI); }
|
||||
static Action* enchant_random_item(PlayerbotAI* botAI) { return new EnchantRandomItemAction(botAI); }
|
||||
static Action* reset_instances(PlayerbotAI* botAI) { return new ResetInstancesAction(botAI); }
|
||||
static Action* buy_petition(PlayerbotAI* botAI) { return new BuyPetitionAction(botAI); }
|
||||
static Action* offer_petition(PlayerbotAI* botAI) { return new PetitionOfferAction(botAI); }
|
||||
static Action* offer_petition_nearby(PlayerbotAI* botAI) { return new PetitionOfferNearbyAction(botAI); }
|
||||
static Action* turn_in_petition(PlayerbotAI* botAI) { return new PetitionTurnInAction(botAI); }
|
||||
static Action* buy_tabard(PlayerbotAI* botAI) { return new BuyTabardAction(botAI); }
|
||||
static Action* guild_manage_nearby(PlayerbotAI* botAI) { return new GuildManageNearbyAction(botAI); }
|
||||
|
||||
// BG Tactics
|
||||
static Action* bg_tactics(PlayerbotAI* botAI) { return new BGTactics(botAI); }
|
||||
static Action* bg_move_to_start(PlayerbotAI* botAI) { return new BGTactics(botAI, "move to start"); }
|
||||
static Action* bg_move_to_objective(PlayerbotAI* botAI) { return new BGTactics(botAI, "move to objective"); }
|
||||
static Action* bg_select_objective(PlayerbotAI* botAI) { return new BGTactics(botAI, "select objective"); }
|
||||
static Action* bg_check_objective(PlayerbotAI* botAI) { return new BGTactics(botAI, "check objective"); }
|
||||
static Action* bg_attack_fc(PlayerbotAI* botAI) { return new BGTactics(botAI, "attack fc"); }
|
||||
static Action* bg_protect_fc(PlayerbotAI* botAI) { return new BGTactics(botAI, "protect fc"); }
|
||||
static Action* attack_enemy_fc(PlayerbotAI* botAI) { return new AttackEnemyFlagCarrierAction(botAI); }
|
||||
static Action* bg_use_buff(PlayerbotAI* botAI) { return new BGTactics(botAI, "use buff"); }
|
||||
static Action* bg_check_flag(PlayerbotAI* botAI) { return new BGTactics(botAI, "check flag"); }
|
||||
|
||||
// Vehicles
|
||||
static Action* enter_vehicle(PlayerbotAI* botAI) { return new EnterVehicleAction(botAI); }
|
||||
static Action* leave_vehicle(PlayerbotAI* botAI) { return new LeaveVehicleAction(botAI); }
|
||||
static Action* hurl_boulder(PlayerbotAI* botAI) { return new CastHurlBoulderAction(botAI); }
|
||||
static Action* ram(PlayerbotAI* botAI) { return new CastRamAction(botAI); }
|
||||
static Action* steam_blast(PlayerbotAI* botAI) { return new CastSteamBlastAction(botAI); }
|
||||
static Action* steam_rush(PlayerbotAI* botAI) { return new CastSteamRushAction(botAI); }
|
||||
static Action* napalm(PlayerbotAI* botAI) { return new CastNapalmAction(botAI); }
|
||||
static Action* fire_cannon(PlayerbotAI* botAI) { return new CastFireCannonAction(botAI); }
|
||||
static Action* incendiary_rocket(PlayerbotAI* botAI) { return new CastIncendiaryRocketAction(botAI); }
|
||||
static Action* rocket_blast(PlayerbotAI* botAI) { return new CastRocketBlastAction(botAI); }
|
||||
static Action* glaive_throw(PlayerbotAI* botAI) { return new CastGlaiveThrowAction(botAI); }
|
||||
static Action* blade_salvo(PlayerbotAI* botAI) { return new CastBladeSalvoAction(botAI); }
|
||||
|
||||
//Rpg
|
||||
static Action* rpg_stay(PlayerbotAI* botAI) { return new RpgStayAction(botAI); }
|
||||
static Action* rpg_work(PlayerbotAI* botAI) { return new RpgWorkAction(botAI); }
|
||||
static Action* rpg_emote(PlayerbotAI* botAI) { return new RpgEmoteAction(botAI); }
|
||||
static Action* rpg_cancel(PlayerbotAI* botAI) { return new RpgCancelAction(botAI); }
|
||||
static Action* rpg_taxi(PlayerbotAI* botAI) { return new RpgTaxiAction(botAI); }
|
||||
static Action* rpg_discover(PlayerbotAI* botAI) { return new RpgDiscoverAction(botAI); }
|
||||
static Action* rpg_start_quest(PlayerbotAI* botAI) { return new RpgStartQuestAction(botAI); }
|
||||
static Action* rpg_end_quest(PlayerbotAI* botAI) { return new RpgEndQuestAction(botAI); }
|
||||
static Action* rpg_buy(PlayerbotAI* botAI) { return new RpgBuyAction(botAI); }
|
||||
static Action* rpg_sell(PlayerbotAI* botAI) { return new RpgSellAction(botAI); }
|
||||
static Action* rpg_repair(PlayerbotAI* botAI) { return new RpgRepairAction(botAI); }
|
||||
static Action* rpg_train(PlayerbotAI* botAI) { return new RpgTrainAction(botAI); }
|
||||
static Action* rpg_heal(PlayerbotAI* botAI) { return new RpgHealAction(botAI); }
|
||||
static Action* rpg_home_bind(PlayerbotAI* botAI) { return new RpgHomeBindAction(botAI); }
|
||||
static Action* rpg_queue_bg(PlayerbotAI* botAI) { return new RpgQueueBgAction(botAI); }
|
||||
static Action* rpg_buy_petition(PlayerbotAI* botAI) { return new RpgBuyPetitionAction(botAI); }
|
||||
static Action* rpg_use(PlayerbotAI* botAI) { return new RpgUseAction(botAI); }
|
||||
static Action* rpg_spell(PlayerbotAI* botAI) { return new RpgSpellAction(botAI); }
|
||||
static Action* rpg_craft(PlayerbotAI* botAI) { return new RpgCraftAction(botAI); }
|
||||
static Action* rpg_trade_useful(PlayerbotAI* botAI) { return new RpgTradeUsefulAction(botAI); }
|
||||
static Action* rpg_duel(PlayerbotAI* botAI) { return new RpgDuelAction(botAI); }
|
||||
};
|
||||
|
||||
#endif
|
||||
86
src/strategy/actions/AddLootAction.cpp
Normal file
86
src/strategy/actions/AddLootAction.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AddLootAction.h"
|
||||
#include "CellImpl.h"
|
||||
#include "Event.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "LootObjectStack.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
bool AddLootAction::Execute(Event event)
|
||||
{
|
||||
ObjectGuid guid = event.getObject();
|
||||
if (!guid)
|
||||
return false;
|
||||
|
||||
return AI_VALUE(LootObjectStack*, "available loot")->Add(guid);
|
||||
}
|
||||
|
||||
bool AddAllLootAction::Execute(Event event)
|
||||
{
|
||||
bool added = false;
|
||||
|
||||
GuidVector gos = context->GetValue<GuidVector>("nearest game objects")->Get();
|
||||
for (GuidVector::iterator i = gos.begin(); i != gos.end(); i++)
|
||||
added |= AddLoot(*i);
|
||||
|
||||
GuidVector corpses = context->GetValue<GuidVector>("nearest corpses")->Get();
|
||||
for (GuidVector::iterator i = corpses.begin(); i != corpses.end(); i++)
|
||||
added |= AddLoot(*i);
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
bool AddLootAction::isUseful()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddAllLootAction::isUseful()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddAllLootAction::AddLoot(ObjectGuid guid)
|
||||
{
|
||||
return AI_VALUE(LootObjectStack*, "available loot")->Add(guid);
|
||||
}
|
||||
|
||||
bool AddGatheringLootAction::AddLoot(ObjectGuid guid)
|
||||
{
|
||||
LootObject loot(bot, guid);
|
||||
|
||||
WorldObject* wo = loot.GetWorldObject(bot);
|
||||
if (loot.IsEmpty() || !wo)
|
||||
return false;
|
||||
|
||||
if (!bot->IsWithinLOSInMap(wo))
|
||||
return false;
|
||||
|
||||
if (loot.skillId == SKILL_NONE)
|
||||
return false;
|
||||
|
||||
if (!loot.IsLootPossible(bot))
|
||||
return false;
|
||||
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, wo), INTERACTION_DISTANCE))
|
||||
{
|
||||
std::list<Unit*> targets;
|
||||
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(bot, bot, sPlayerbotAIConfig->lootDistance);
|
||||
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(bot, targets, u_check);
|
||||
Cell::VisitAllObjects(bot, searcher, sPlayerbotAIConfig->lootDistance * 1.5f);
|
||||
if (!targets.empty())
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Kill that " << targets.front()->GetName() << " so I can loot freely";
|
||||
botAI->TellError(out.str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return AddAllLootAction::AddLoot(guid);
|
||||
}
|
||||
41
src/strategy/actions/AddLootAction.h
Normal file
41
src/strategy/actions/AddLootAction.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ADDLOOTACTION_H
|
||||
#define _PLAYERBOT_ADDLOOTACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class ObjectGuid;
|
||||
class PlayerbotAI;
|
||||
|
||||
class AddLootAction : public Action
|
||||
{
|
||||
public:
|
||||
AddLootAction(PlayerbotAI* botAI) : Action(botAI, "add loot") { }
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class AddAllLootAction : public Action
|
||||
{
|
||||
public:
|
||||
AddAllLootAction(PlayerbotAI* botAI, std::string const name = "add all loot") : Action(botAI, name) { }
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
virtual bool AddLoot(ObjectGuid guid);
|
||||
};
|
||||
|
||||
class AddGatheringLootAction : public AddAllLootAction
|
||||
{
|
||||
public:
|
||||
AddGatheringLootAction(PlayerbotAI* botAI) : AddAllLootAction(botAI, "add gathering loot") { }
|
||||
|
||||
protected:
|
||||
bool AddLoot(ObjectGuid guid) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
72
src/strategy/actions/AreaTriggerAction.cpp
Normal file
72
src/strategy/actions/AreaTriggerAction.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AreaTriggerAction.h"
|
||||
#include "Event.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Transport.h"
|
||||
|
||||
bool ReachAreaTriggerAction::Execute(Event event)
|
||||
{
|
||||
if (botAI->IsRealPlayer()) //Do not trigger own area trigger.
|
||||
return false;
|
||||
|
||||
uint32 triggerId;
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
p >> triggerId;
|
||||
|
||||
AreaTrigger const* at = sObjectMgr->GetAreaTrigger(triggerId);
|
||||
if (!at)
|
||||
return false;
|
||||
|
||||
if (!sObjectMgr->GetAreaTriggerTeleport(triggerId))
|
||||
{
|
||||
WorldPacket p1(CMSG_AREATRIGGER);
|
||||
p1 << triggerId;
|
||||
p1.rpos(0);
|
||||
bot->GetSession()->HandleAreaTriggerOpcode(p1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bot->GetMapId() != at->map || sqrt(bot->GetDistance(at->x, at->y, at->z)) > sPlayerbotAIConfig->sightDistance)
|
||||
{
|
||||
botAI->TellError("I won't follow: too far away");
|
||||
return true;
|
||||
}
|
||||
|
||||
bot->GetMotionMaster()->MovePoint(at->map, at->x, at->y, at->z);
|
||||
|
||||
float distance = sqrt(bot->GetDistance(at->x, at->y, at->z));
|
||||
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay;
|
||||
botAI->TellError("Wait for me");
|
||||
botAI->SetNextCheckDelay(delay);
|
||||
context->GetValue<LastMovement&>("last area trigger")->Get().lastAreaTrigger = triggerId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AreaTriggerAction::Execute(Event event)
|
||||
{
|
||||
LastMovement& movement = context->GetValue<LastMovement&>("last area trigger")->Get();
|
||||
|
||||
uint32 triggerId = movement.lastAreaTrigger;
|
||||
movement.lastAreaTrigger = 0;
|
||||
|
||||
if (!sObjectMgr->GetAreaTrigger(triggerId))
|
||||
return false;
|
||||
|
||||
if (!sObjectMgr->GetAreaTriggerTeleport(triggerId))
|
||||
return true;
|
||||
|
||||
WorldPacket p(CMSG_AREATRIGGER);
|
||||
p << triggerId;
|
||||
p.rpos(0);
|
||||
bot->GetSession()->HandleAreaTriggerOpcode(p);
|
||||
|
||||
botAI->TellMaster("Hello");
|
||||
return true;
|
||||
}
|
||||
28
src/strategy/actions/AreaTriggerAction.h
Normal file
28
src/strategy/actions/AreaTriggerAction.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AREATRIGGERACTION_H
|
||||
#define _PLAYERBOT_AREATRIGGERACTION_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class ReachAreaTriggerAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
ReachAreaTriggerAction(PlayerbotAI* botAI) : MovementAction(botAI, "reach area trigger") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class AreaTriggerAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
AreaTriggerAction(PlayerbotAI* botAI) : MovementAction(botAI, "area trigger") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
53
src/strategy/actions/ArenaTeamActions.cpp
Normal file
53
src/strategy/actions/ArenaTeamActions.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ArenaTeamActions.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool ArenaTeamAcceptAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
Player* inviter = nullptr;
|
||||
std::string Invitedname;
|
||||
p >> Invitedname;
|
||||
|
||||
if (normalizePlayerName(Invitedname))
|
||||
inviter = ObjectAccessor::FindPlayerByName(Invitedname.c_str());
|
||||
|
||||
if (!inviter)
|
||||
return false;
|
||||
|
||||
ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(bot->GetArenaTeamIdInvited());
|
||||
if (!at)
|
||||
return false;
|
||||
|
||||
bool accept = true;
|
||||
|
||||
if (bot->GetArenaTeamId(at->GetSlot()))
|
||||
{
|
||||
// bot is already in an arena team
|
||||
bot->Say("Sorry, I am already in such team", LANG_UNIVERSAL);
|
||||
accept = false;
|
||||
}
|
||||
|
||||
if (accept)
|
||||
{
|
||||
WorldPacket data(CMSG_ARENA_TEAM_ACCEPT);
|
||||
bot->GetSession()->HandleArenaTeamAcceptOpcode(data);
|
||||
bot->Say("Thanks for the invite!", LANG_UNIVERSAL);
|
||||
LOG_INFO("playerbots", "Bot {} <{}> accepts Arena Team invite", bot->GetGUID().ToString().c_str(), bot->GetName().c_str());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldPacket data(CMSG_ARENA_TEAM_DECLINE);
|
||||
bot->GetSession()->HandleArenaTeamDeclineOpcode(data);
|
||||
LOG_INFO("playerbots", "Bot {} <{}> declines Arena Team invite", bot->GetGUID().ToString().c_str(), bot->GetName().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
20
src/strategy/actions/ArenaTeamActions.h
Normal file
20
src/strategy/actions/ArenaTeamActions.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ARENATEAMACTION_H
|
||||
#define _PLAYERBOT_ARENATEAMACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class ArenaTeamAcceptAction : public Action
|
||||
{
|
||||
public:
|
||||
ArenaTeamAcceptAction(PlayerbotAI* botAI) : Action(botAI, "arena team accept") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
140
src/strategy/actions/AttackAction.cpp
Normal file
140
src/strategy/actions/AttackAction.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AttackAction.h"
|
||||
#include "Event.h"
|
||||
#include "LootObjectStack.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "CreatureAI.h"
|
||||
|
||||
bool AttackAction::Execute(Event event)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
return Attack(target);
|
||||
}
|
||||
|
||||
bool AttackMyTargetAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
ObjectGuid guid = master->GetTarget();
|
||||
if (!guid)
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("You have no target");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = Attack(botAI->GetUnit(guid));
|
||||
if (result)
|
||||
context->GetValue<ObjectGuid>("pull target")->Set(guid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AttackAction::Attack(Unit* target)
|
||||
{
|
||||
if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE || bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I cannot attack in flight");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I have no target");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostringstream msg;
|
||||
msg << target->GetName();
|
||||
|
||||
if (bot->IsFriendlyTo(target))
|
||||
{
|
||||
msg << " is friendly to me";
|
||||
if (verbose)
|
||||
botAI->TellError(msg.str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bot->IsWithinLOSInMap(target))
|
||||
{
|
||||
msg << " is not on my sight";
|
||||
if (verbose)
|
||||
botAI->TellError(msg.str());
|
||||
}
|
||||
|
||||
if (target->isDead())
|
||||
{
|
||||
msg << " is dead";
|
||||
if (verbose)
|
||||
botAI->TellError(msg.str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->IsMounted() && bot->IsWithinLOSInMap(target) && sServerFacade->GetDistance2d(bot, target) < 40.0f)
|
||||
{
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
}
|
||||
|
||||
ObjectGuid guid = target->GetGUID();
|
||||
bot->SetTarget(target->GetGUID());
|
||||
|
||||
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
|
||||
context->GetValue<Unit*>("old target")->Set(oldTarget);
|
||||
|
||||
context->GetValue<Unit*>("current target")->Set(target);
|
||||
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
if (CreatureAI* creatureAI = ((Creature*)pet)->AI())
|
||||
{
|
||||
pet->SetReactState(REACT_PASSIVE);
|
||||
pet->GetCharmInfo()->SetCommandState(COMMAND_ATTACK);
|
||||
creatureAI->AttackStart(target);
|
||||
}
|
||||
}
|
||||
|
||||
if (!urand(0, 300) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
std::vector<uint32> sounds;
|
||||
sounds.push_back(TEXT_EMOTE_OPENFIRE);
|
||||
sounds.push_back(305);
|
||||
sounds.push_back(307);
|
||||
botAI->PlayEmote(sounds[urand(0, sounds.size() - 1)]);
|
||||
}
|
||||
|
||||
if (IsMovingAllowed() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target, sPlayerbotAIConfig->sightDistance))
|
||||
bot->SetFacingToObject(target);
|
||||
|
||||
bool attacked = bot->Attack(target, !botAI->IsRanged(bot));
|
||||
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
||||
|
||||
return attacked;
|
||||
}
|
||||
|
||||
bool AttackDuelOpponentAction::isUseful()
|
||||
{
|
||||
return AI_VALUE(Unit*, "duel target");
|
||||
}
|
||||
|
||||
bool AttackDuelOpponentAction::Execute(Event event)
|
||||
{
|
||||
return Attack(AI_VALUE(Unit*, "duel target"));
|
||||
}
|
||||
41
src/strategy/actions/AttackAction.h
Normal file
41
src/strategy/actions/AttackAction.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_ATTACKACTION_H
|
||||
#define _PLAYERBOT_ATTACKACTION_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AttackAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
AttackAction(PlayerbotAI* botAI, std::string const name) : MovementAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
bool Attack(Unit* target);
|
||||
};
|
||||
|
||||
class AttackMyTargetAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackMyTargetAction(PlayerbotAI* botAI, std::string const name = "attack my target") : AttackAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class AttackDuelOpponentAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackDuelOpponentAction(PlayerbotAI* botAI, std::string const name = "attack duel opponent") : AttackAction(botAI, name) { }
|
||||
|
||||
public:
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
165
src/strategy/actions/AutoLearnSpellAction.cpp
Normal file
165
src/strategy/actions/AutoLearnSpellAction.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AutoLearnSpellAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool AutoLearnSpellAction::Execute(Event event)
|
||||
{
|
||||
std::string const param = event.getParam();
|
||||
|
||||
std::ostringstream out;
|
||||
LearnSpells(&out);
|
||||
|
||||
if (!out.str().empty())
|
||||
{
|
||||
std::string const temp = out.str();
|
||||
out.seekp(0);
|
||||
out << "Learned spells: ";
|
||||
out << temp;
|
||||
out.seekp(-2, out.cur);
|
||||
out << ".";
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void AutoLearnSpellAction::LearnSpells(std::ostringstream* out)
|
||||
{
|
||||
if (sPlayerbotAIConfig->autoLearnTrainerSpells)// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot)))
|
||||
LearnTrainerSpells(out);
|
||||
|
||||
if (sPlayerbotAIConfig->autoLearnQuestSpells)// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot)))
|
||||
LearnQuestSpells(out);
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnTrainerSpells(std::ostringstream* out)
|
||||
{
|
||||
bot->LearnDefaultSkills();
|
||||
bot->LearnCustomSpells();
|
||||
|
||||
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
|
||||
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)
|
||||
continue;
|
||||
|
||||
if (itr->second.trainer_type == TRAINER_TYPE_CLASS && itr->second.trainer_class != bot->getClass())
|
||||
continue;
|
||||
|
||||
TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(itr->second.Entry);
|
||||
if (!trainer_spells)
|
||||
continue;
|
||||
|
||||
for (TrainerSpellMap::const_iterator iter = trainer_spells->spellList.begin(); iter != trainer_spells->spellList.end(); ++iter)
|
||||
{
|
||||
TrainerSpell const* tSpell = &iter->second;
|
||||
if (!tSpell)
|
||||
continue;
|
||||
|
||||
TrainerSpellState state = bot->GetTrainerSpellState(tSpell);
|
||||
if (state != TRAINER_SPELL_GREEN)
|
||||
continue;
|
||||
|
||||
if (itr->second.trainer_type == TRAINER_TYPE_TRADESKILLS)
|
||||
{
|
||||
SpellInfo const* spell = sSpellMgr->GetSpellInfo(tSpell->spell);
|
||||
if (spell)
|
||||
{
|
||||
std::string const SpellName = spell->SpellName[0];
|
||||
if (spell->Effects[EFFECT_1].Effect == SPELL_EFFECT_SKILL_STEP)
|
||||
{
|
||||
uint32 skill = spell->Effects[EFFECT_1].MiscValue;
|
||||
if (skill)
|
||||
{
|
||||
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill);
|
||||
if (pSkill)
|
||||
{
|
||||
if (SpellName.find("Apprentice") != std::string::npos && pSkill->categoryId == SKILL_CATEGORY_PROFESSION || pSkill->categoryId == SKILL_CATEGORY_SECONDARY)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LearnSpell(tSpell->spell, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnQuestSpells(std::ostringstream* out)
|
||||
{
|
||||
//CreatureTemplate const* co = sCreatureStorage.LookupEntry<CreatureTemplate>(id);
|
||||
ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates();
|
||||
for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i)
|
||||
{
|
||||
uint32 questId = i->first;
|
||||
Quest const* quest = i->second;
|
||||
|
||||
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10)
|
||||
continue;
|
||||
|
||||
if (!bot->SatisfyQuestClass(quest, false) || quest->GetMinLevel() > bot->getLevel() || !bot->SatisfyQuestRace(quest, false))
|
||||
continue;
|
||||
|
||||
if (quest->GetRewSpellCast() > 0)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpellCast(), out);
|
||||
}
|
||||
else if (quest->GetRewSpell() > 0)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpell(), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string const FormatSpell(SpellInfo const* sInfo)
|
||||
{
|
||||
std::ostringstream out;
|
||||
std::string const rank = sInfo->Rank[0];
|
||||
|
||||
if (rank.empty())
|
||||
out << "|cffffffff|Hspell:" << sInfo->Id << "|h[" << sInfo->SpellName[LOCALE_enUS] << "]|h|r";
|
||||
else
|
||||
out << "|cffffffff|Hspell:" << sInfo->Id << "|h[" << sInfo->SpellName[LOCALE_enUS] << " " << rank << "]|h|r";
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnSpell(uint32 spellId, std::ostringstream* out)
|
||||
{
|
||||
SpellInfo const* proto = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!proto)
|
||||
return;
|
||||
|
||||
bool learned = false;
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
{
|
||||
if (proto->Effects[j].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
{
|
||||
uint32 learnedSpell = proto->Effects[j].TriggerSpell;
|
||||
|
||||
if (!bot->HasSpell(learnedSpell))
|
||||
{
|
||||
bot->learnSpell(learnedSpell);
|
||||
*out << FormatSpell(sSpellMgr->GetSpellInfo(learnedSpell)) << ", ";
|
||||
}
|
||||
|
||||
learned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!learned)
|
||||
{
|
||||
if (!bot->HasSpell(spellId))
|
||||
{
|
||||
bot->learnSpell(spellId);
|
||||
*out << FormatSpell(proto) << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/strategy/actions/AutoLearnSpellAction.h
Normal file
26
src/strategy/actions/AutoLearnSpellAction.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AUTOLEARNSPELLACTION_H
|
||||
#define _PLAYERBOT_AUTOLEARNSPELLACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AutoLearnSpellAction : public Action
|
||||
{
|
||||
public:
|
||||
AutoLearnSpellAction(PlayerbotAI* botAI, std::string const name = "auto learn spell") : Action(botAI, name) { }
|
||||
|
||||
bool Execute(Event event);
|
||||
|
||||
private:
|
||||
void LearnSpells(std::ostringstream* out);
|
||||
void LearnTrainerSpells(std::ostringstream* out);
|
||||
void LearnQuestSpells(std::ostringstream* out);
|
||||
void LearnSpell(uint32 spellId, std::ostringstream* out);
|
||||
};
|
||||
|
||||
#endif
|
||||
171
src/strategy/actions/BankAction.cpp
Normal file
171
src/strategy/actions/BankAction.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "BankAction.h"
|
||||
#include "Event.h"
|
||||
#include "ItemCountValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool BankAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||
for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++)
|
||||
{
|
||||
Unit* npc = botAI->GetUnit(*i);
|
||||
if (!npc || !npc->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BANKER))
|
||||
continue;
|
||||
|
||||
return ExecuteBank(text, npc);
|
||||
}
|
||||
|
||||
botAI->TellError("Cannot find banker nearby");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BankAction::ExecuteBank(std::string const text, Unit* bank)
|
||||
{
|
||||
if (text.empty() || text == "?")
|
||||
{
|
||||
ListItems();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (text[0] == '-')
|
||||
{
|
||||
std::vector<Item*> found = parseItems(text.substr(1), ITERATE_ITEMS_IN_BANK);
|
||||
for (std::vector<Item*>::iterator i = found.begin(); i != found.end(); i++)
|
||||
{
|
||||
Item* item = *i;
|
||||
result &= Withdraw(item->GetTemplate()->ItemId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<Item*> found = parseItems(text, ITERATE_ITEMS_IN_BAGS);
|
||||
if (found.empty())
|
||||
return false;
|
||||
|
||||
for (std::vector<Item*>::iterator i = found.begin(); i != found.end(); i++)
|
||||
{
|
||||
Item* item = *i;
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
result &= Deposit(item);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BankAction::Withdraw(uint32 itemid)
|
||||
{
|
||||
Item* pItem = FindItemInBank(itemid);
|
||||
if (!pItem)
|
||||
return false;
|
||||
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = bot->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
bot->SendEquipError(msg, pItem, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bot->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
|
||||
bot->StoreItem(dest, pItem, true);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "got " << chat->FormatItem(pItem->GetTemplate(), pItem->GetCount()) << " from bank";
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BankAction::Deposit(Item* pItem)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = bot->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
bot->SendEquipError(msg, pItem, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bot->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
|
||||
bot->BankItem(dest, pItem, true);
|
||||
|
||||
out << "put " << chat->FormatItem(pItem->GetTemplate(), pItem->GetCount()) << " to bank";
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void BankAction::ListItems()
|
||||
{
|
||||
botAI->TellMaster("=== Bank ===");
|
||||
|
||||
std::map<uint32, uint32> items;
|
||||
std::map<uint32, bool> soulbound;
|
||||
for (uint32 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i)
|
||||
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
if (pItem)
|
||||
{
|
||||
items[pItem->GetTemplate()->ItemId] += pItem->GetCount();
|
||||
soulbound[pItem->GetTemplate()->ItemId] = pItem->IsSoulBound();
|
||||
}
|
||||
|
||||
for (uint32 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
|
||||
if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
if (pBag)
|
||||
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
|
||||
if (Item* pItem = pBag->GetItemByPos(j))
|
||||
if (pItem)
|
||||
{
|
||||
items[pItem->GetTemplate()->ItemId] += pItem->GetCount();
|
||||
soulbound[pItem->GetTemplate()->ItemId] = pItem->IsSoulBound();
|
||||
}
|
||||
|
||||
TellItems(items, soulbound);
|
||||
}
|
||||
|
||||
Item* BankAction::FindItemInBank(uint32 ItemId)
|
||||
{
|
||||
for (uint8 slot = BANK_SLOT_ITEM_START; slot < BANK_SLOT_ITEM_END; slot++)
|
||||
{
|
||||
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||
{
|
||||
ItemTemplate const* const pItemProto = pItem->GetTemplate();
|
||||
if (!pItemProto)
|
||||
continue;
|
||||
|
||||
if (pItemProto->ItemId == ItemId) // have required item
|
||||
return pItem;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 bag = BANK_SLOT_BAG_START; bag < BANK_SLOT_BAG_END; ++bag)
|
||||
{
|
||||
Bag const* const pBag = (Bag *) bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag);
|
||||
if (pBag)
|
||||
for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot)
|
||||
{
|
||||
Item* const pItem = bot->GetItemByPos(bag, slot);
|
||||
if (pItem)
|
||||
{
|
||||
ItemTemplate const* const pItemProto = pItem->GetTemplate();
|
||||
if (!pItemProto)
|
||||
continue;
|
||||
|
||||
if (pItemProto->ItemId == ItemId)
|
||||
return pItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
28
src/strategy/actions/BankAction.h
Normal file
28
src/strategy/actions/BankAction.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_BANKACTION_H
|
||||
#define _PLAYERBOT_BANKACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class Item;
|
||||
class PlayerbotAI;
|
||||
|
||||
class BankAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
BankAction(PlayerbotAI* botAI) : InventoryAction(botAI, "bank") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool ExecuteBank(std::string const text, Unit* bank);
|
||||
void ListItems();
|
||||
bool Withdraw(uint32 itemid);
|
||||
bool Deposit(Item* pItem);
|
||||
Item* FindItemInBank(uint32 ItemId);
|
||||
};
|
||||
|
||||
#endif
|
||||
1101
src/strategy/actions/BattleGroundJoinAction.cpp
Normal file
1101
src/strategy/actions/BattleGroundJoinAction.cpp
Normal file
File diff suppressed because it is too large
Load Diff
69
src/strategy/actions/BattleGroundJoinAction.h
Normal file
69
src/strategy/actions/BattleGroundJoinAction.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_BATTLEGROUNDJOINACTION_H
|
||||
#define _PLAYERBOT_BATTLEGROUNDJOINACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "DBCEnums.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
struct CreatureData;
|
||||
|
||||
enum ArenaType : uint8;
|
||||
enum BattlegroundQueueTypeId : uint8;
|
||||
|
||||
class BGJoinAction : public Action
|
||||
{
|
||||
public:
|
||||
BGJoinAction(PlayerbotAI* botAI, std::string const name = "bg join") : Action(botAI, name) { }
|
||||
|
||||
bool isUseful() override;
|
||||
bool canJoinBg(BattlegroundQueueTypeId queueTypeId, BattlegroundBracketId bracketId);
|
||||
virtual bool shouldJoinBg(BattlegroundQueueTypeId queueTypeId, BattlegroundBracketId bracketId);
|
||||
bool Execute(Event event) override;
|
||||
virtual bool gatherArenaTeam(ArenaType type);
|
||||
|
||||
protected:
|
||||
bool JoinQueue(uint32 type);
|
||||
std::vector<uint32> bgList;
|
||||
std::vector<uint32> ratedList;
|
||||
};
|
||||
|
||||
class FreeBGJoinAction : public BGJoinAction
|
||||
{
|
||||
public:
|
||||
FreeBGJoinAction(PlayerbotAI* botAI, std::string const name = "free bg join") : BGJoinAction(botAI, name) { }
|
||||
|
||||
bool shouldJoinBg(BattlegroundQueueTypeId queueTypeId, BattlegroundBracketId bracketId) override;
|
||||
};
|
||||
|
||||
class BGLeaveAction : public Action
|
||||
{
|
||||
public:
|
||||
BGLeaveAction(PlayerbotAI* botAI, std::string const name = "bg leave") : Action(botAI) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class BGStatusAction : public Action
|
||||
{
|
||||
public:
|
||||
BGStatusAction(PlayerbotAI* botAI) : Action(botAI, "bg status") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class BGStatusCheckAction : public Action
|
||||
{
|
||||
public:
|
||||
BGStatusCheckAction(PlayerbotAI* botAI, std::string const name = "bg status check") : Action(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
4909
src/strategy/actions/BattleGroundTactics.cpp
Normal file
4909
src/strategy/actions/BattleGroundTactics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
73
src/strategy/actions/BattleGroundTactics.h
Normal file
73
src/strategy/actions/BattleGroundTactics.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_BATTLEGROUNDTACTICSACTION_H
|
||||
#define _PLAYERBOT_BATTLEGROUNDTACTICSACTION_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
|
||||
class Battleground;
|
||||
class PlayerbotAI;
|
||||
struct Position;
|
||||
|
||||
#define SPELL_CAPTURE_BANNER 21651
|
||||
|
||||
typedef void(*BattleBotWaypointFunc)();
|
||||
|
||||
struct BattleBotWaypoint
|
||||
{
|
||||
BattleBotWaypoint(float x_, float y_, float z_, BattleBotWaypointFunc func) : x(x_), y(y_), z(z_), pFunc(func) { };
|
||||
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
BattleBotWaypointFunc pFunc = nullptr;
|
||||
};
|
||||
|
||||
typedef std::vector<BattleBotWaypoint> BattleBotPath;
|
||||
|
||||
extern std::vector<BattleBotPath*> const vPaths_WS;
|
||||
extern std::vector<BattleBotPath*> const vPaths_AB;
|
||||
extern std::vector<BattleBotPath*> const vPaths_AV;
|
||||
extern std::vector<BattleBotPath*> const vPaths_EY;
|
||||
extern std::vector<BattleBotPath*> const vPaths_IC;
|
||||
|
||||
class BGTactics : public MovementAction
|
||||
{
|
||||
public:
|
||||
BGTactics(PlayerbotAI* botAI, std::string const name = "bg tactics") : MovementAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool moveToStart(bool force = false);
|
||||
bool selectObjective(bool reset = false);
|
||||
bool moveToObjective();
|
||||
bool selectObjectiveWp(std::vector<BattleBotPath*> const& vPaths);
|
||||
bool moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 currentPoint, bool reverse = false);
|
||||
bool startNewPathBegin(std::vector<BattleBotPath*> const& vPaths);
|
||||
bool startNewPathFree(std::vector<BattleBotPath*> const& vPaths);
|
||||
bool resetObjective();
|
||||
bool wsgPaths();
|
||||
bool atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<uint32> const& vFlagIds);
|
||||
bool flagTaken();
|
||||
bool teamFlagTaken();
|
||||
bool protectFC();
|
||||
bool useBuff();
|
||||
uint32 getDefendersCount(Position point, float range, bool combat = true);
|
||||
bool IsLockedInsideKeep();
|
||||
};
|
||||
|
||||
class ArenaTactics : public MovementAction
|
||||
{
|
||||
public:
|
||||
ArenaTactics(PlayerbotAI* botAI, std::string const name = "arena tactics") : MovementAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool moveToCenter(Battleground *bg);
|
||||
};
|
||||
|
||||
#endif
|
||||
113
src/strategy/actions/BuffAction.cpp
Normal file
113
src/strategy/actions/BuffAction.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "BuffAction.h"
|
||||
#include "Event.h"
|
||||
#include "ItemCountValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
class FindBuffVisitor : public IterateItemsVisitor
|
||||
{
|
||||
public:
|
||||
FindBuffVisitor(Player* bot) : IterateItemsVisitor(), bot(bot)
|
||||
{
|
||||
}
|
||||
|
||||
bool Visit(Item* item) override
|
||||
{
|
||||
if (bot->CanUseItem(item->GetTemplate()) != EQUIP_ERR_OK)
|
||||
return true;
|
||||
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
|
||||
if (proto->Class != ITEM_CLASS_CONSUMABLE)
|
||||
return true;
|
||||
|
||||
if (proto->SubClass != ITEM_SUBCLASS_ELIXIR && proto->SubClass != ITEM_SUBCLASS_FLASK && proto->SubClass != ITEM_SUBCLASS_SCROLL &&
|
||||
proto->SubClass != ITEM_SUBCLASS_FOOD && proto->SubClass != ITEM_SUBCLASS_CONSUMABLE_OTHER && proto->SubClass != ITEM_SUBCLASS_ITEM_ENHANCEMENT)
|
||||
return true;
|
||||
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; i++)
|
||||
{
|
||||
uint32 spellId = proto->Spells[i].SpellId;
|
||||
if (!spellId)
|
||||
continue;
|
||||
|
||||
if (bot->HasAura(spellId))
|
||||
return true;
|
||||
|
||||
Item* itemForSpell = *GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<Item*>("item for spell", spellId);
|
||||
if (itemForSpell && itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
|
||||
return true;
|
||||
|
||||
if (items.find(proto->SubClass) == items.end())
|
||||
items[proto->SubClass] = std::vector<Item*>();
|
||||
|
||||
items[proto->SubClass].push_back(item);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<uint32, std::vector<Item*> > items;
|
||||
|
||||
private:
|
||||
Player* bot;
|
||||
};
|
||||
|
||||
void BuffAction::TellHeader(uint32 subClass)
|
||||
{
|
||||
switch (subClass)
|
||||
{
|
||||
case ITEM_SUBCLASS_ELIXIR:
|
||||
botAI->TellMaster("--- Elixir ---");
|
||||
return;
|
||||
case ITEM_SUBCLASS_FLASK:
|
||||
botAI->TellMaster("--- Flask ---");
|
||||
return;
|
||||
case ITEM_SUBCLASS_SCROLL:
|
||||
botAI->TellMaster("--- Scroll ---");
|
||||
return;
|
||||
case ITEM_SUBCLASS_FOOD:
|
||||
botAI->TellMaster("--- Food ---");
|
||||
return;
|
||||
case ITEM_SUBCLASS_ITEM_ENHANCEMENT:
|
||||
botAI->TellMaster("--- Enchant ---");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool BuffAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
|
||||
FindBuffVisitor visitor(bot);
|
||||
IterateItems(&visitor);
|
||||
|
||||
uint32 oldSubClass = -1;
|
||||
for (std::map<uint32, std::vector<Item*> >::iterator i = visitor.items.begin(); i != visitor.items.end(); ++i)
|
||||
{
|
||||
std::vector<Item*> items = i->second;
|
||||
|
||||
uint32 subClass = i->first;
|
||||
if (oldSubClass != subClass)
|
||||
{
|
||||
if (!items.empty())
|
||||
TellHeader(subClass);
|
||||
|
||||
oldSubClass = subClass;
|
||||
}
|
||||
|
||||
for (std::vector<Item*>::iterator j = items.begin(); j != items.end(); ++j)
|
||||
{
|
||||
Item* item = *j;
|
||||
std::ostringstream out;
|
||||
out << chat->FormatItem(item->GetTemplate(), item->GetCount());
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
23
src/strategy/actions/BuffAction.h
Normal file
23
src/strategy/actions/BuffAction.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_BUFFACTION_H
|
||||
#define _PLAYERBOT_BUFFACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class BuffAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
BuffAction(PlayerbotAI* botAI) : InventoryAction(botAI, "buff") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
void TellHeader(uint32 subClass);
|
||||
};
|
||||
|
||||
#endif
|
||||
184
src/strategy/actions/BuyAction.cpp
Normal file
184
src/strategy/actions/BuyAction.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "BuyAction.h"
|
||||
#include "BudgetValues.h"
|
||||
#include "Event.h"
|
||||
#include "ItemVisitors.h"
|
||||
#include "ItemCountValue.h"
|
||||
#include "ItemUsageValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool BuyAction::Execute(Event event)
|
||||
{
|
||||
bool buyUseful = false;
|
||||
ItemIds itemIds;
|
||||
std::string const link = event.getParam();
|
||||
|
||||
if (link == "vendor")
|
||||
buyUseful = true;
|
||||
else
|
||||
{
|
||||
itemIds = chat->parseItems(link);
|
||||
}
|
||||
|
||||
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||
|
||||
bool vendored = false;
|
||||
bool result = false;
|
||||
for (GuidVector::iterator i = vendors.begin(); i != vendors.end(); ++i)
|
||||
{
|
||||
ObjectGuid vendorguid = *i;
|
||||
Creature* pCreature = bot->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
|
||||
if (!pCreature)
|
||||
continue;
|
||||
|
||||
vendored = true;
|
||||
|
||||
if (buyUseful)
|
||||
{
|
||||
// Items are evaluated from high-level to low level.
|
||||
// For each item the bot checks again if an item is usefull.
|
||||
// Bot will buy until no usefull items are left.
|
||||
|
||||
VendorItemData const* tItems = pCreature->GetVendorItems();
|
||||
if (!tItems)
|
||||
continue;
|
||||
|
||||
VendorItemList m_items_sorted = tItems->m_items;
|
||||
|
||||
m_items_sorted.erase(std::remove_if(m_items_sorted.begin(), m_items_sorted.end(), [](VendorItem* i)
|
||||
{
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(i->item);
|
||||
return !proto;
|
||||
}), m_items_sorted.end());
|
||||
|
||||
if (m_items_sorted.empty())
|
||||
continue;
|
||||
|
||||
std::sort(m_items_sorted.begin(), m_items_sorted.end(), [](VendorItem* i, VendorItem* j) { return sObjectMgr->GetItemTemplate(i->item)->ItemLevel > sObjectMgr->GetItemTemplate(j->item)->ItemLevel; });
|
||||
|
||||
for (auto& tItem : m_items_sorted)
|
||||
{
|
||||
for (uint32 i = 0; i < 10; i++) // Buy 10 times or until no longer usefull/possible
|
||||
{
|
||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", tItem->item);
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(tItem->item);
|
||||
|
||||
uint32 price = proto->BuyPrice;
|
||||
|
||||
// reputation discount
|
||||
price = uint32(floor(price * bot->GetReputationPriceDiscount(pCreature)));
|
||||
|
||||
NeedMoneyFor needMoneyFor = NeedMoneyFor::none;
|
||||
|
||||
switch (usage)
|
||||
{
|
||||
case ITEM_USAGE_REPLACE:
|
||||
case ITEM_USAGE_EQUIP:
|
||||
needMoneyFor = NeedMoneyFor::gear;
|
||||
break;
|
||||
case ITEM_USAGE_AMMO:
|
||||
needMoneyFor = NeedMoneyFor::ammo;
|
||||
break;
|
||||
case ITEM_USAGE_QUEST:
|
||||
needMoneyFor = NeedMoneyFor::anything;
|
||||
break;
|
||||
case ITEM_USAGE_USE:
|
||||
needMoneyFor = NeedMoneyFor::consumables;
|
||||
break;
|
||||
case ITEM_USAGE_SKILL:
|
||||
needMoneyFor = NeedMoneyFor::tradeskill;
|
||||
break;
|
||||
}
|
||||
|
||||
if (needMoneyFor == NeedMoneyFor::none)
|
||||
break;
|
||||
|
||||
if (AI_VALUE2(uint32, "free money for", uint32(needMoneyFor)) < price)
|
||||
break;
|
||||
|
||||
if (!BuyItem(tItems, vendorguid, proto))
|
||||
break;
|
||||
|
||||
if (usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_EQUIP) // Equip upgrades and stop buying this time.
|
||||
{
|
||||
botAI->DoSpecificAction("equip upgrades");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (itemIds.empty())
|
||||
return false;
|
||||
|
||||
for (ItemIds::iterator i = itemIds.begin(); i != itemIds.end(); i++)
|
||||
{
|
||||
uint32 itemId = *i;
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
result |= BuyItem(pCreature->GetVendorItems(), vendorguid, proto);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Nobody sells " << ChatHelper::FormatItem(proto) << " nearby";
|
||||
botAI->TellMaster(out.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!vendored)
|
||||
{
|
||||
botAI->TellError("There are no vendors nearby");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuyAction::BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, ItemTemplate const* proto)
|
||||
{
|
||||
uint32 oldCount = AI_VALUE2(uint32, "item count", proto->Name1);
|
||||
|
||||
if (!tItems)
|
||||
return false;
|
||||
|
||||
uint32 itemId = proto->ItemId;
|
||||
for (uint32 slot = 0; slot < tItems->GetItemCount(); slot++)
|
||||
{
|
||||
if (tItems->GetItem(slot)->item == itemId)
|
||||
{
|
||||
uint32 botMoney = bot->GetMoney();
|
||||
if (botAI->HasCheat(BotCheatMask::gold))
|
||||
{
|
||||
bot->SetMoney(10000000);
|
||||
}
|
||||
|
||||
bot->BuyItemFromVendorSlot(vendorguid, slot, itemId, 1, NULL_BAG, NULL_SLOT);
|
||||
|
||||
if (botAI->HasCheat(BotCheatMask::gold))
|
||||
{
|
||||
bot->SetMoney(botMoney);
|
||||
}
|
||||
|
||||
if (oldCount < AI_VALUE2(uint32, "item count", proto->Name1)) // BuyItem Always returns false (unless unique) so we have to check the item counts.
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Buying " << ChatHelper::FormatItem(proto);
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
33
src/strategy/actions/BuyAction.h
Normal file
33
src/strategy/actions/BuyAction.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_BUYACTION_H
|
||||
#define _PLAYERBOT_BUYACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class FindItemVisitor;
|
||||
class ObjectGuid;
|
||||
class Item;
|
||||
class Player;
|
||||
class PlayerbotAI;
|
||||
|
||||
struct ItemTemplate;
|
||||
struct VendorItemData;
|
||||
|
||||
class BuyAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
BuyAction(PlayerbotAI* botAI) : InventoryAction(botAI, "buy") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, ItemTemplate const* proto);
|
||||
bool TradeItem(FindItemVisitor* visitor, int8 slot);
|
||||
bool TradeItem(Item const* item, int8 slot);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
343
src/strategy/actions/CastCustomSpellAction.cpp
Normal file
343
src/strategy/actions/CastCustomSpellAction.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CastCustomSpellAction.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Event.h"
|
||||
#include "ItemUsageValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
uint32 FindLastSeparator(std::string const text, std::string const sep)
|
||||
{
|
||||
uint32 pos = text.rfind(sep);
|
||||
if (pos == std::string::npos)
|
||||
return pos;
|
||||
|
||||
uint32 lastLinkBegin = text.rfind("|H");
|
||||
uint32 lastLinkEnd = text.find("|h|r", lastLinkBegin + 1);
|
||||
if (pos >= lastLinkBegin && pos <= lastLinkEnd)
|
||||
pos = text.find_last_of(sep, lastLinkBegin);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static inline void ltrim(std::string& s)
|
||||
{
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
|
||||
}
|
||||
|
||||
bool CastCustomSpellAction::Execute(Event event)
|
||||
{
|
||||
// only allow proper vehicle seats
|
||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||
return false;
|
||||
|
||||
Player* master = GetMaster();
|
||||
Unit* target = nullptr;
|
||||
std::string text = event.getParam();
|
||||
|
||||
GuidVector gos = chat->parseGameobjects(text);
|
||||
if (!gos.empty())
|
||||
{
|
||||
for (auto go : gos)
|
||||
{
|
||||
if (!target)
|
||||
target = botAI->GetUnit(go);
|
||||
|
||||
chat->eraseAllSubStr(text, chat->FormatWorldobject(botAI->GetUnit(go)));
|
||||
}
|
||||
|
||||
ltrim(text);
|
||||
}
|
||||
|
||||
if (!target)
|
||||
if (master && master->GetTarget())
|
||||
target = botAI->GetUnit(master->GetTarget());
|
||||
|
||||
if (!target)
|
||||
target = bot;
|
||||
|
||||
if (!master) // Use self as master for permissions.
|
||||
master = bot;
|
||||
|
||||
Item* itemTarget = nullptr;
|
||||
|
||||
uint32 pos = FindLastSeparator(text, " ");
|
||||
uint32 castCount = 1;
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string const param = text.substr(pos + 1);
|
||||
std::vector<Item*> items = InventoryAction::parseItems(param, ITERATE_ITEMS_IN_BAGS);
|
||||
if (!items.empty())
|
||||
itemTarget = *items.begin();
|
||||
else
|
||||
{
|
||||
castCount = atoi(param.c_str());
|
||||
if (castCount > 0)
|
||||
text = text.substr(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 spell = AI_VALUE2(uint32, "spell id", text);
|
||||
|
||||
std::ostringstream msg;
|
||||
if (!spell)
|
||||
{
|
||||
msg << "Unknown spell " << text;
|
||||
botAI->TellError(msg.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell);
|
||||
if (!spellInfo)
|
||||
{
|
||||
msg << "Unknown spell " << text;
|
||||
botAI->TellError(msg.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target != bot && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target, sPlayerbotAIConfig->sightDistance))
|
||||
{
|
||||
bot->SetFacingToObject(target);
|
||||
botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
|
||||
msg << "cast " << text;
|
||||
botAI->HandleCommand(CHAT_MSG_WHISPER, msg.str(), master);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ostringstream spellName;
|
||||
spellName << ChatHelper::FormatSpell(spellInfo) << " on ";
|
||||
|
||||
if (bot->GetTrader())
|
||||
spellName << "trade item";
|
||||
else if (itemTarget)
|
||||
spellName << chat->FormatItem(itemTarget->GetTemplate());
|
||||
else if (target == bot)
|
||||
spellName << "self";
|
||||
else
|
||||
spellName << target->GetName();
|
||||
|
||||
if (!bot->GetTrader() && !botAI->CanCastSpell(spell, target, true, itemTarget))
|
||||
{
|
||||
msg << "Cannot cast " << spellName.str();
|
||||
botAI->TellError(msg.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = spell ? botAI->CastSpell(spell, target, itemTarget) : botAI->CastSpell(text, target, itemTarget);
|
||||
if (result)
|
||||
{
|
||||
msg << "Casting " << spellName.str();
|
||||
|
||||
if (castCount > 1)
|
||||
{
|
||||
std::ostringstream cmd;
|
||||
cmd << castString(target) << " " << text << " " << (castCount - 1);
|
||||
botAI->HandleCommand(CHAT_MSG_WHISPER, cmd.str(), master);
|
||||
msg << "|cffffff00(x" << (castCount-1) << " left)|r";
|
||||
}
|
||||
|
||||
botAI->TellMasterNoFacing(msg.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "Cast " << spellName.str() << " is failed";
|
||||
botAI->TellError(msg.str());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CastCustomNcSpellAction::isUseful()
|
||||
{
|
||||
return !bot->IsInCombat();
|
||||
}
|
||||
|
||||
std::string const CastCustomNcSpellAction::castString(WorldObject* target)
|
||||
{
|
||||
return "castnc " + chat->FormatWorldobject(target);
|
||||
}
|
||||
|
||||
bool CastRandomSpellAction::AcceptSpell(SpellInfo const* spellInfo)
|
||||
{
|
||||
bool isTradeSkill = spellInfo->Effects[EFFECT_0].Effect == SPELL_EFFECT_CREATE_ITEM && spellInfo->ReagentCount[EFFECT_0] > 0 && spellInfo->SchoolMask == 1;
|
||||
return !isTradeSkill && spellInfo->GetRecoveryTime() < MINUTE * IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
bool CastRandomSpellAction::Execute(Event event)
|
||||
{
|
||||
std::vector<std::pair<uint32, std::string>> spellMap = GetSpellList();
|
||||
Player* master = GetMaster();
|
||||
|
||||
Unit* target = nullptr;
|
||||
GameObject* got = nullptr;
|
||||
|
||||
std::string name = event.getParam();
|
||||
if (name.empty())
|
||||
name = getName();
|
||||
|
||||
GuidVector wos = chat->parseGameobjects(name);
|
||||
for (auto wo : wos)
|
||||
{
|
||||
target = botAI->GetUnit(wo);
|
||||
got = botAI->GetGameObject(wo);
|
||||
|
||||
if (got || target)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!got && !target && bot->GetTarget())
|
||||
{
|
||||
target = botAI->GetUnit(bot->GetTarget());
|
||||
got = botAI->GetGameObject(bot->GetTarget());
|
||||
}
|
||||
|
||||
if (!got && !target)
|
||||
if (master && master->GetTarget())
|
||||
target = botAI->GetUnit(master->GetTarget());
|
||||
|
||||
if (!got && !target)
|
||||
target = bot;
|
||||
|
||||
std::vector<std::pair<uint32, std::pair<uint32, WorldObject*>>> spellList;
|
||||
|
||||
for (auto& spell : spellMap)
|
||||
{
|
||||
uint32 spellId = spell.first;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (!AcceptSpell(spellInfo))
|
||||
continue;
|
||||
|
||||
if (bot->HasSpell(spellId))
|
||||
{
|
||||
uint32 spellPriority = GetSpellPriority(spellInfo);
|
||||
|
||||
if (target && botAI->CanCastSpell(spellId, target, true))
|
||||
spellList.push_back(std::make_pair(spellId, std::make_pair(spellPriority, target)));
|
||||
if (got && botAI->CanCastSpell(spellId, got->GetPositionX(), got->GetPositionY(), got->GetPositionZ(), true))
|
||||
spellList.push_back(std::make_pair(spellId, std::make_pair(spellPriority, got)));
|
||||
if (botAI->CanCastSpell(spellId, bot, true))
|
||||
spellList.push_back(std::make_pair(spellId, std::make_pair(spellPriority, bot)));
|
||||
}
|
||||
}
|
||||
|
||||
if (spellList.empty())
|
||||
return false;
|
||||
|
||||
bool isCast = false;
|
||||
|
||||
std::sort(spellList.begin(), spellList.end(), [](std::pair<uint32, std::pair<uint32, WorldObject*>> i, std::pair<uint32, std::pair<uint32, WorldObject*>> j)
|
||||
{
|
||||
return i.first > j.first;
|
||||
});
|
||||
|
||||
uint32 rndBound = spellList.size() / 4;
|
||||
|
||||
rndBound = std::min(rndBound, (uint32)10);
|
||||
rndBound = std::max(rndBound, (uint32)0);
|
||||
|
||||
for (uint32 i = 0; i < 5; i++)
|
||||
{
|
||||
uint32 rnd = urand(0, rndBound);
|
||||
|
||||
auto spell = spellList[rnd];
|
||||
|
||||
uint32 spellId = spell.first;
|
||||
WorldObject* wo = spell.second.second;
|
||||
|
||||
bool isCast = castSpell(spellId, wo);
|
||||
|
||||
if (isCast)
|
||||
{
|
||||
if (MultiCast && ((wo && bot->HasInArc(CAST_ANGLE_IN_FRONT, wo, sPlayerbotAIConfig->sightDistance))))
|
||||
{
|
||||
std::ostringstream cmd;
|
||||
cmd << "castnc " << chat->FormatWorldobject(wo) + " " << spellId << " " << 19;
|
||||
botAI->HandleCommand(CHAT_MSG_WHISPER, cmd.str(), bot);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CraftRandomItemAction::AcceptSpell(SpellInfo const* spellInfo)
|
||||
{
|
||||
return spellInfo->Effects[EFFECT_0].Effect == SPELL_EFFECT_CREATE_ITEM && spellInfo->ReagentCount[EFFECT_0] > 0 && spellInfo->SchoolMask == 0;
|
||||
}
|
||||
|
||||
uint32 CraftRandomItemAction::GetSpellPriority(SpellInfo const* spellInfo)
|
||||
{
|
||||
if (spellInfo->Effects[EFFECT_0].Effect != SPELL_EFFECT_CREATE_ITEM)
|
||||
{
|
||||
uint32 newItemId = spellInfo->Effects[EFFECT_0].ItemType;
|
||||
if (newItemId)
|
||||
{
|
||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", newItemId);
|
||||
|
||||
if (usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_AMMO || usage == ITEM_USAGE_QUEST || usage == ITEM_USAGE_SKILL || usage == ITEM_USAGE_USE)
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (ItemUsageValue::SpellGivesSkillUp(spellInfo->Id, bot))
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool CastRandomSpellAction::castSpell(uint32 spellId, WorldObject* wo)
|
||||
{
|
||||
|
||||
if (wo->GetGUID().IsUnit())
|
||||
return botAI->CastSpell(spellId, (Unit*)(wo));
|
||||
else
|
||||
return botAI->CastSpell(spellId, wo->GetPositionX(), wo->GetPositionY(), wo->GetPositionZ());
|
||||
}
|
||||
|
||||
bool DisEnchantRandomItemAction::Execute(Event event)
|
||||
{
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "usage " + std::to_string(ITEM_USAGE_DISENCHANT));
|
||||
std::reverse(items.begin(), items.end());
|
||||
|
||||
for (auto& item: items)
|
||||
{
|
||||
if(CastCustomSpellAction::Execute(Event("disenchant random item", "13262 "+ chat->FormatQItem(item->GetEntry()))))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DisEnchantRandomItemAction::isUseful()
|
||||
{
|
||||
return botAI->HasSkill(SKILL_ENCHANTING) && !bot->IsInCombat() && AI_VALUE2(uint32, "item count", "usage " + std::to_string(ITEM_USAGE_DISENCHANT)) > 0;
|
||||
}
|
||||
|
||||
bool EnchantRandomItemAction::isUseful()
|
||||
{
|
||||
return botAI->HasSkill(SKILL_ENCHANTING) && !bot->IsInCombat();
|
||||
}
|
||||
|
||||
bool EnchantRandomItemAction::AcceptSpell(SpellInfo const* spellInfo)
|
||||
{
|
||||
return spellInfo->Effects[EFFECT_0].Effect == SPELL_EFFECT_ENCHANT_ITEM && spellInfo->ReagentCount[EFFECT_0] > 0;
|
||||
}
|
||||
|
||||
uint32 EnchantRandomItemAction::GetSpellPriority(SpellInfo const* spellInfo)
|
||||
{
|
||||
if (spellInfo->Effects[EFFECT_0].Effect == SPELL_EFFECT_ENCHANT_ITEM)
|
||||
{
|
||||
if (AI_VALUE2(Item*, "item for spell", spellInfo->Id) && ItemUsageValue::SpellGivesSkillUp(spellInfo->Id, bot))
|
||||
return 10;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
81
src/strategy/actions/CastCustomSpellAction.h
Normal file
81
src/strategy/actions/CastCustomSpellAction.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CASTCUSTOMSPELLACTION_H
|
||||
#define _PLAYERBOT_CASTCUSTOMSPELLACTION_H
|
||||
|
||||
#include "ListSpellsAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
class SpellInfo;
|
||||
class WorldObject;
|
||||
|
||||
class CastCustomSpellAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
CastCustomSpellAction(PlayerbotAI* botAI, std::string const name = "cast custom spell") : InventoryAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
virtual std::string const castString(WorldObject* target) { return "cast"; }
|
||||
|
||||
protected:
|
||||
bool ncCast = false;
|
||||
};
|
||||
|
||||
class CastCustomNcSpellAction : public CastCustomSpellAction
|
||||
{
|
||||
public:
|
||||
CastCustomNcSpellAction(PlayerbotAI* botAI, std::string const name = "cast custom nc spell") : CastCustomSpellAction(botAI, name) { }
|
||||
|
||||
bool isUseful() override;
|
||||
std::string const castString(WorldObject* target) override;
|
||||
};
|
||||
|
||||
class CastRandomSpellAction : public ListSpellsAction
|
||||
{
|
||||
public:
|
||||
CastRandomSpellAction(PlayerbotAI* botAI, std::string const name = "cast random spell") : ListSpellsAction(botAI, name) { }
|
||||
|
||||
bool isUseful() override { return false; }
|
||||
virtual bool AcceptSpell(SpellInfo const* spellInfo);
|
||||
virtual uint32 GetSpellPriority(SpellInfo const* spellInfo) { return 1; }
|
||||
virtual bool castSpell(uint32 spellId, WorldObject* wo);
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
bool MultiCast = false;
|
||||
};
|
||||
|
||||
class CraftRandomItemAction : public CastRandomSpellAction
|
||||
{
|
||||
public:
|
||||
CraftRandomItemAction(PlayerbotAI* botAI) : CastRandomSpellAction(botAI, "craft random item")
|
||||
{
|
||||
MultiCast = true;
|
||||
}
|
||||
|
||||
bool AcceptSpell(SpellInfo const* spellInfo) override;
|
||||
uint32 GetSpellPriority(SpellInfo const* spellInfo) override;
|
||||
};
|
||||
|
||||
class DisEnchantRandomItemAction : public CastCustomSpellAction
|
||||
{
|
||||
public:
|
||||
DisEnchantRandomItemAction(PlayerbotAI* botAI) : CastCustomSpellAction(botAI, "disenchant random item") {}
|
||||
|
||||
bool isUseful() override;
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class EnchantRandomItemAction : public CastRandomSpellAction
|
||||
{
|
||||
public:
|
||||
EnchantRandomItemAction(PlayerbotAI* botAI) : CastRandomSpellAction(botAI, "enchant random item") { }
|
||||
|
||||
bool isUseful() override;
|
||||
bool AcceptSpell(SpellInfo const* spellInfo) override;
|
||||
uint32 GetSpellPriority(SpellInfo const* spellInfo) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
29
src/strategy/actions/ChangeChatAction.cpp
Normal file
29
src/strategy/actions/ChangeChatAction.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChangeChatAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool ChangeChatAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
ChatMsg parsed = chat->parseChat(text);
|
||||
if (parsed == CHAT_MSG_SYSTEM)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Current chat is " << chat->FormatChat(*context->GetValue<ChatMsg>("chat"));
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
else
|
||||
{
|
||||
context->GetValue<ChatMsg>("chat")->Set(parsed);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Chat set to " << chat->FormatChat(parsed);
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/ChangeChatAction.h
Normal file
20
src/strategy/actions/ChangeChatAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHANGECHATACTION_H
|
||||
#define _PLAYERBOT_CHANGECHATACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class ChangeChatAction : public Action
|
||||
{
|
||||
public:
|
||||
ChangeChatAction(PlayerbotAI* botAI) : Action(botAI, "chat") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
78
src/strategy/actions/ChangeStrategyAction.cpp
Normal file
78
src/strategy/actions/ChangeStrategyAction.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChangeStrategyAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotDbStore.h"
|
||||
|
||||
bool ChangeCombatStrategyAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
botAI->ChangeStrategy(text.empty() ? getName() : text, BOT_STATE_COMBAT);
|
||||
if (event.GetSource() == "co")
|
||||
{
|
||||
std::vector<std::string> splitted = split(text, ',');
|
||||
for (std::vector<std::string>::iterator i = splitted.begin(); i != splitted.end(); i++)
|
||||
{
|
||||
const char* name = i->c_str();
|
||||
switch (name[0])
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
case '~':
|
||||
sPlayerbotDbStore->Save(botAI);
|
||||
break;
|
||||
case '?':
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChangeNonCombatStrategyAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
|
||||
uint32 account = bot->GetSession()->GetAccountId();
|
||||
if (sPlayerbotAIConfig->IsInRandomAccountList(account) && botAI->GetMaster() && botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER)
|
||||
{
|
||||
if (text.find("loot") != std::string::npos || text.find("gather") != std::string::npos)
|
||||
{
|
||||
botAI->TellError("You can change any strategy except loot and gather");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
botAI->ChangeStrategy(text, BOT_STATE_NON_COMBAT);
|
||||
if (event.GetSource() == "nc")
|
||||
{
|
||||
std::vector<std::string> splitted = split(text, ',');
|
||||
for (std::vector<std::string>::iterator i = splitted.begin(); i != splitted.end(); i++)
|
||||
{
|
||||
const char* name = i->c_str();
|
||||
switch (name[0])
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
case '~':
|
||||
sPlayerbotDbStore->Save(botAI);
|
||||
break;
|
||||
case '?':
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChangeDeadStrategyAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
botAI->ChangeStrategy(text, BOT_STATE_DEAD);
|
||||
return true;
|
||||
}
|
||||
36
src/strategy/actions/ChangeStrategyAction.h
Normal file
36
src/strategy/actions/ChangeStrategyAction.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHANGESTRATEGYACTION_H
|
||||
#define _PLAYERBOT_CHANGESTRATEGYACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class ChangeCombatStrategyAction : public Action
|
||||
{
|
||||
public:
|
||||
ChangeCombatStrategyAction(PlayerbotAI* botAI, std::string const name = "co") : Action(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ChangeNonCombatStrategyAction : public Action
|
||||
{
|
||||
public:
|
||||
ChangeNonCombatStrategyAction(PlayerbotAI* botAI) : Action(botAI, "nc") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ChangeDeadStrategyAction : public Action
|
||||
{
|
||||
public:
|
||||
ChangeDeadStrategyAction(PlayerbotAI* botAI) : Action(botAI, "de") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
338
src/strategy/actions/ChangeTalentsAction.cpp
Normal file
338
src/strategy/actions/ChangeTalentsAction.cpp
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChangeTalentsAction.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool ChangeTalentsAction::Execute(Event event)
|
||||
{
|
||||
std::string param = event.getParam();
|
||||
|
||||
std::ostringstream out;
|
||||
|
||||
TalentSpec botSpec(bot);
|
||||
|
||||
if (!param.empty())
|
||||
{
|
||||
if (param.find("auto") != std::string::npos)
|
||||
{
|
||||
AutoSelectTalents(&out);
|
||||
}
|
||||
else if (param.find("list ") != std::string::npos)
|
||||
{
|
||||
listPremadePaths(getPremadePaths(param.substr(5)), &out);
|
||||
}
|
||||
else if (param.find("list") != std::string::npos)
|
||||
{
|
||||
listPremadePaths(getPremadePaths(""), &out);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool crop = false;
|
||||
bool shift = false;
|
||||
if (param.find("do ") != std::string::npos)
|
||||
{
|
||||
crop = true;
|
||||
param = param.substr(3);
|
||||
}
|
||||
else if (param.find("shift ") != std::string::npos)
|
||||
{
|
||||
shift = true;
|
||||
param = param.substr(6);
|
||||
}
|
||||
|
||||
out << "Apply talents [" << param << "] ";
|
||||
if (botSpec.CheckTalentLink(param, &out))
|
||||
{
|
||||
TalentSpec newSpec(bot, param);
|
||||
std::string const specLink = newSpec.GetTalentLink();
|
||||
|
||||
if (crop)
|
||||
{
|
||||
newSpec.CropTalents(bot->getLevel());
|
||||
out << "becomes: " << newSpec.GetTalentLink();
|
||||
}
|
||||
|
||||
if (shift)
|
||||
{
|
||||
TalentSpec botSpec(bot);
|
||||
newSpec.ShiftTalents(&botSpec, bot->getLevel());
|
||||
out << "becomes: " << newSpec.GetTalentLink();
|
||||
}
|
||||
|
||||
if (newSpec.CheckTalents(bot->getLevel(), &out))
|
||||
{
|
||||
newSpec.ApplyTalents(bot, &out);
|
||||
sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specNo", 0);
|
||||
sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 1, specLink);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<TalentPath*> paths = getPremadePaths(param);
|
||||
if (paths.size() > 0)
|
||||
{
|
||||
out.str("");
|
||||
out.clear();
|
||||
|
||||
if (paths.size() > 1 && sPlayerbotAIConfig->autoPickTalents != "full")
|
||||
{
|
||||
out << "Found multiple specs: ";
|
||||
listPremadePaths(paths, &out);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (paths.size() > 1)
|
||||
out << "Found " << paths.size() << " possible specs to choose from. ";
|
||||
|
||||
TalentPath* path = PickPremadePath(paths, sRandomPlayerbotMgr->IsRandomBot(bot));
|
||||
TalentSpec newSpec = *GetBestPremadeSpec(path->id);
|
||||
std::string const specLink = newSpec.GetTalentLink();
|
||||
newSpec.CropTalents(bot->getLevel());
|
||||
newSpec.ApplyTalents(bot, &out);
|
||||
|
||||
if (newSpec.GetTalentPoints() > 0)
|
||||
{
|
||||
out << "Apply spec " << "|h|cffffffff" << path->name << " " << newSpec.FormatSpec(bot);
|
||||
sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specNo", path->id + 1);
|
||||
sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 specId = sRandomPlayerbotMgr->GetValue(bot->GetGUID().GetCounter(), "specNo") - 1;
|
||||
std::string specName = "";
|
||||
TalentPath* specPath;
|
||||
if (specId)
|
||||
{
|
||||
specPath = getPremadePath(specId);
|
||||
if (specPath->id == specId)
|
||||
specName = specPath->name;
|
||||
}
|
||||
|
||||
out << "My current talent spec is: " << "|h|cffffffff";
|
||||
if (specName != "")
|
||||
out << specName << " (" << botSpec.FormatSpec(bot) << ")";
|
||||
else
|
||||
out << chat->FormatClass(bot, botSpec.highestTree());
|
||||
out << " Link: ";
|
||||
out << botSpec.GetTalentLink();
|
||||
}
|
||||
|
||||
botAI->TellMaster(out);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<TalentPath*> ChangeTalentsAction::getPremadePaths(std::string const findName)
|
||||
{
|
||||
std::vector<TalentPath*> ret;
|
||||
for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath)
|
||||
{
|
||||
if (findName.empty() || path.name.find(findName) != std::string::npos)
|
||||
{
|
||||
ret.push_back(&path);
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
std::vector<TalentPath*> ChangeTalentsAction::getPremadePaths(TalentSpec* oldSpec)
|
||||
{
|
||||
std::vector<TalentPath*> ret;
|
||||
|
||||
for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath)
|
||||
{
|
||||
TalentSpec newSpec = *GetBestPremadeSpec(path.id);
|
||||
newSpec.CropTalents(bot->getLevel());
|
||||
if (oldSpec->isEarlierVersionOf(newSpec))
|
||||
{
|
||||
ret.push_back(&path);
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
TalentPath* ChangeTalentsAction::getPremadePath(uint32 id)
|
||||
{
|
||||
for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath)
|
||||
{
|
||||
if (id == path.id)
|
||||
{
|
||||
return &path;
|
||||
}
|
||||
}
|
||||
|
||||
return &sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath[0];
|
||||
}
|
||||
|
||||
void ChangeTalentsAction::listPremadePaths(std::vector<TalentPath*> paths, std::ostringstream* out)
|
||||
{
|
||||
if (paths.size() == 0)
|
||||
{
|
||||
*out << "No predefined talents found..";
|
||||
}
|
||||
|
||||
*out << "|h|cffffffff";
|
||||
|
||||
for (auto path : paths)
|
||||
{
|
||||
*out << path->name << " (" << path->talentSpec.back().FormatSpec(bot) << "), ";
|
||||
}
|
||||
|
||||
out->seekp(-2, out->cur);
|
||||
*out << ".";
|
||||
}
|
||||
|
||||
TalentPath* ChangeTalentsAction::PickPremadePath(std::vector<TalentPath*> paths, bool useProbability)
|
||||
{
|
||||
uint32 totProbability = 0;
|
||||
uint32 curProbability = 0;
|
||||
|
||||
if (paths.size() == 1)
|
||||
return paths[0];
|
||||
|
||||
for (auto path : paths)
|
||||
{
|
||||
totProbability += useProbability ? path->probability : 1;
|
||||
}
|
||||
|
||||
totProbability = urand(0, totProbability);
|
||||
|
||||
for (auto path : paths)
|
||||
{
|
||||
curProbability += (useProbability ? path->probability : 1);
|
||||
if (curProbability >= totProbability)
|
||||
return path;
|
||||
}
|
||||
|
||||
return paths[0];
|
||||
}
|
||||
|
||||
bool ChangeTalentsAction::AutoSelectTalents(std::ostringstream* out)
|
||||
{
|
||||
// Does the bot have talentpoints?
|
||||
if (bot->getLevel() < 10)
|
||||
{
|
||||
*out << "No free talent points.";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 specNo = sRandomPlayerbotMgr->GetValue(bot->GetGUID().GetCounter(), "specNo");
|
||||
uint32 specId = specNo - 1;
|
||||
std::string specLink = sRandomPlayerbotMgr->GetData(bot->GetGUID().GetCounter(), "specLink");
|
||||
|
||||
//Continue the current spec
|
||||
if (specNo > 0)
|
||||
{
|
||||
TalentSpec newSpec = *GetBestPremadeSpec(specId);
|
||||
newSpec.CropTalents(bot->getLevel());
|
||||
newSpec.ApplyTalents(bot, out);
|
||||
if (newSpec.GetTalentPoints() > 0)
|
||||
{
|
||||
*out << "Upgrading spec " << "|h|cffffffff" << getPremadePath(specId)->name << "" << newSpec.FormatSpec(bot);
|
||||
}
|
||||
}
|
||||
else if (!specLink.empty())
|
||||
{
|
||||
TalentSpec newSpec(bot, specLink);
|
||||
newSpec.CropTalents(bot->getLevel());
|
||||
newSpec.ApplyTalents(bot, out);
|
||||
if (newSpec.GetTalentPoints() > 0)
|
||||
{
|
||||
*out << "Upgrading saved spec "
|
||||
<< "|h|cffffffff" << chat->FormatClass(bot, newSpec.highestTree()) << " (" << newSpec.FormatSpec(bot) << ")";
|
||||
}
|
||||
}
|
||||
|
||||
//Spec was not found or not sufficient
|
||||
if (bot->GetFreeTalentPoints() > 0 || (!specNo && specLink.empty()))
|
||||
{
|
||||
TalentSpec oldSpec(bot);
|
||||
std::vector<TalentPath*> paths = getPremadePaths(&oldSpec);
|
||||
|
||||
if (paths.size() == 0) //No spec like the old one found. Pick any.
|
||||
{
|
||||
if (bot->CalculateTalentsPoints() > 0)
|
||||
*out << "No specs like the current spec found. ";
|
||||
|
||||
paths = getPremadePaths("");
|
||||
}
|
||||
|
||||
if (paths.size() == 0)
|
||||
{
|
||||
*out << "No predefined talents found for this class.";
|
||||
specId = -1;
|
||||
// specLink = "";
|
||||
}
|
||||
else if (paths.size() > 1 && sPlayerbotAIConfig->autoPickTalents != "full" && !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
*out << "Found multiple specs: ";
|
||||
listPremadePaths(paths, out);
|
||||
}
|
||||
else
|
||||
{
|
||||
specId = PickPremadePath(paths, sRandomPlayerbotMgr->IsRandomBot(bot))->id;
|
||||
TalentSpec newSpec = *GetBestPremadeSpec(specId);
|
||||
specLink = newSpec.GetTalentLink();
|
||||
newSpec.CropTalents(bot->getLevel());
|
||||
newSpec.ApplyTalents(bot, out);
|
||||
|
||||
if (paths.size() > 1)
|
||||
*out << "Found " << paths.size() << " possible specs to choose from. ";
|
||||
|
||||
*out << "Apply spec " << "|h|cffffffff" << getPremadePath(specId)->name << " " << newSpec.FormatSpec(bot);
|
||||
}
|
||||
}
|
||||
|
||||
sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specNo", specId + 1);
|
||||
|
||||
if (!specLink.empty() && specId == -1)
|
||||
sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 1, specLink);
|
||||
else
|
||||
sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 0);
|
||||
|
||||
return (specNo == 0) ? false : true;
|
||||
}
|
||||
|
||||
//Returns a pre-made talentspec that best suits the bots current talents.
|
||||
TalentSpec* ChangeTalentsAction::GetBestPremadeSpec(uint32 specId)
|
||||
{
|
||||
TalentPath* path = getPremadePath(specId);
|
||||
for (auto& spec : path->talentSpec)
|
||||
{
|
||||
if (spec.points >= bot->CalculateTalentsPoints())
|
||||
return &spec;
|
||||
}
|
||||
|
||||
if (path->talentSpec.size())
|
||||
return &path->talentSpec.back();
|
||||
|
||||
return &sPlayerbotAIConfig->classSpecs[bot->getClassMask()].baseSpec;
|
||||
}
|
||||
|
||||
bool AutoSetTalentsAction::Execute(Event event)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
if (sPlayerbotAIConfig->autoPickTalents == "no" && !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
return false;
|
||||
|
||||
if (bot->GetFreeTalentPoints() <= 0)
|
||||
return false;
|
||||
|
||||
AutoSelectTalents(&out);
|
||||
|
||||
botAI->TellMaster(out);
|
||||
|
||||
return true;
|
||||
}
|
||||
38
src/strategy/actions/ChangeTalentsAction.h
Normal file
38
src/strategy/actions/ChangeTalentsAction.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHANGETALENTSACTION_H
|
||||
#define _PLAYERBOT_CHANGETALENTSACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "Talentspec.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class ChangeTalentsAction : public Action
|
||||
{
|
||||
public:
|
||||
ChangeTalentsAction(PlayerbotAI* botAI, std::string const name = "talents") : Action(botAI, name) { }
|
||||
|
||||
bool Execute(Event event);
|
||||
bool AutoSelectTalents(std::ostringstream* out);
|
||||
|
||||
private:
|
||||
std::vector<TalentPath*> getPremadePaths(std::string const findName);
|
||||
std::vector<TalentPath*> getPremadePaths(TalentSpec* oldSpec);
|
||||
TalentPath* getPremadePath(uint32 id);
|
||||
void listPremadePaths(std::vector<TalentPath*> paths, std::ostringstream* out);
|
||||
TalentPath* PickPremadePath(std::vector<TalentPath*> paths, bool useProbability);
|
||||
TalentSpec* GetBestPremadeSpec(uint32 spec);
|
||||
};
|
||||
|
||||
class AutoSetTalentsAction : public ChangeTalentsAction
|
||||
{
|
||||
public:
|
||||
AutoSetTalentsAction(PlayerbotAI* botAI) : ChangeTalentsAction(botAI, "auto talents") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
255
src/strategy/actions/ChatActionContext.h
Normal file
255
src/strategy/actions/ChatActionContext.h
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHATACTIONCONTEXTACTION_H
|
||||
#define _PLAYERBOT_CHATACTIONCONTEXTACTION_H
|
||||
|
||||
#include "AddLootAction.h"
|
||||
#include "AttackAction.h"
|
||||
#include "BankAction.h"
|
||||
#include "BuffAction.h"
|
||||
#include "BuyAction.h"
|
||||
#include "CastCustomSpellAction.h"
|
||||
#include "ChangeChatAction.h"
|
||||
#include "ChangeTalentsAction.h"
|
||||
#include "ChangeStrategyAction.h"
|
||||
#include "ChatShortcutActions.h"
|
||||
#include "CheatAction.h"
|
||||
#include "CustomStrategyEditAction.h"
|
||||
#include "DebugAction.h"
|
||||
#include "DestroyItemAction.h"
|
||||
#include "DropQuestAction.h"
|
||||
#include "EquipAction.h"
|
||||
#include "FlagAction.h"
|
||||
#include "GoAction.h"
|
||||
#include "GossipHelloAction.h"
|
||||
#include "GuildBankAction.h"
|
||||
#include "GuildManagementActions.h"
|
||||
#include "HelpAction.h"
|
||||
#include "HireAction.h"
|
||||
#include "InviteToGroupAction.h"
|
||||
#include "LeaveGroupAction.h"
|
||||
#include "ListQuestsActions.h"
|
||||
#include "ListSpellsAction.h"
|
||||
#include "LogLevelAction.h"
|
||||
#include "LootStrategyAction.h"
|
||||
#include "MailAction.h"
|
||||
#include "QueryItemUsageAction.h"
|
||||
#include "QueryQuestAction.h"
|
||||
#include "PassLeadershipToMasterAction.h"
|
||||
#include "PositionAction.h"
|
||||
#include "RangeAction.h"
|
||||
#include "ReleaseSpiritAction.h"
|
||||
#include "RepairAllAction.h"
|
||||
#include "ResetAiAction.h"
|
||||
#include "ReviveFromCorpseAction.h"
|
||||
#include "RewardAction.h"
|
||||
#include "RtiAction.h"
|
||||
#include "RTSCAction.h"
|
||||
#include "SaveManaAction.h"
|
||||
#include "SellAction.h"
|
||||
#include "SetCraftAction.h"
|
||||
#include "SendMailAction.h"
|
||||
#include "SetHomeAction.h"
|
||||
#include "ShareQuestAction.h"
|
||||
#include "SkipSpellsListAction.h"
|
||||
#include "StatsAction.h"
|
||||
#include "TaxiAction.h"
|
||||
#include "TeleportAction.h"
|
||||
#include "TellCastFailedAction.h"
|
||||
#include "TellItemCountAction.h"
|
||||
#include "TellLosAction.h"
|
||||
#include "TellReputationAction.h"
|
||||
#include "TellTargetAction.h"
|
||||
#include "TradeAction.h"
|
||||
#include "TrainerAction.h"
|
||||
#include "UnequipAction.h"
|
||||
#include "UseItemAction.h"
|
||||
#include "UseMeetingStoneAction.h"
|
||||
#include "WhoAction.h"
|
||||
#include "WtsAction.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "Formations.h"
|
||||
#include "Stances.h"
|
||||
|
||||
class ChatActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
public:
|
||||
ChatActionContext()
|
||||
{
|
||||
creators["range"] = &ChatActionContext::range;
|
||||
creators["stats"] = &ChatActionContext::stats;
|
||||
creators["quests"] = &ChatActionContext::quests;
|
||||
creators["leave"] = &ChatActionContext::leave;
|
||||
creators["reputation"] = &ChatActionContext::reputation;
|
||||
creators["log"] = &ChatActionContext::log;
|
||||
creators["los"] = &ChatActionContext::los;
|
||||
creators["drop"] = &ChatActionContext::drop;
|
||||
creators["clean quest log"] = &ChatActionContext::clean_quest_log;
|
||||
creators["share"] = &ChatActionContext::share;
|
||||
creators["query quest"] = &ChatActionContext::query_quest;
|
||||
creators["query item usage"] = &ChatActionContext::query_item_usage;
|
||||
creators["ll"] = &ChatActionContext::ll;
|
||||
creators["ss"] = &ChatActionContext::ss;
|
||||
creators["add all loot"] = &ChatActionContext::add_all_loot;
|
||||
creators["release"] = &ChatActionContext::release;
|
||||
creators["repop"] = &ChatActionContext::repop;
|
||||
creators["teleport"] = &ChatActionContext::teleport;
|
||||
creators["taxi"] = &ChatActionContext::taxi;
|
||||
creators["repair"] = &ChatActionContext::repair;
|
||||
creators["use"] = &ChatActionContext::use;
|
||||
creators["item count"] = &ChatActionContext::item_count;
|
||||
creators["equip"] = &ChatActionContext::equip;
|
||||
creators["equip upgrades"] = &ChatActionContext::equip_upgrades;
|
||||
creators["unequip"] = &ChatActionContext::unequip;
|
||||
creators["sell"] = &ChatActionContext::sell;
|
||||
creators["buy"] = &ChatActionContext::buy;
|
||||
creators["reward"] = &ChatActionContext::reward;
|
||||
creators["trade"] = &ChatActionContext::trade;
|
||||
creators["talents"] = &ChatActionContext::talents;
|
||||
creators["spells"] = &ChatActionContext::spells;
|
||||
creators["co"] = &ChatActionContext::co;
|
||||
creators["nc"] = &ChatActionContext::nc;
|
||||
creators["de"] = &ChatActionContext::dead;
|
||||
creators["trainer"] = &ChatActionContext::trainer;
|
||||
creators["attack my target"] = &ChatActionContext::attack_my_target;
|
||||
creators["chat"] = &ChatActionContext::chat;
|
||||
creators["home"] = &ChatActionContext::home;
|
||||
creators["destroy"] = &ChatActionContext::destroy;
|
||||
creators["reset botAI"] = &ChatActionContext::reset_ai;
|
||||
creators["buff"] = &ChatActionContext::buff;
|
||||
creators["help"] = &ChatActionContext::help;
|
||||
creators["gb"] = &ChatActionContext::gb;
|
||||
creators["bank"] = &ChatActionContext::bank;
|
||||
creators["follow chat shortcut"] = &ChatActionContext::follow_chat_shortcut;
|
||||
creators["stay chat shortcut"] = &ChatActionContext::stay_chat_shortcut;
|
||||
creators["flee chat shortcut"] = &ChatActionContext::flee_chat_shortcut;
|
||||
creators["runaway chat shortcut"] = &ChatActionContext::runaway_chat_shortcut;
|
||||
creators["grind chat shortcut"] = &ChatActionContext::grind_chat_shortcut;
|
||||
creators["tank attack chat shortcut"] = &ChatActionContext::tank_attack_chat_shortcut;
|
||||
creators["gossip hello"] = &ChatActionContext::gossip_hello;
|
||||
creators["cast custom spell"] = &ChatActionContext::cast_custom_spell;
|
||||
creators["cast custom nc spell"] = &ChatActionContext::cast_custom_nc_spell;
|
||||
creators["invite"] = &ChatActionContext::invite;
|
||||
creators["spell"] = &ChatActionContext::spell;
|
||||
creators["rti"] = &ChatActionContext::rti;
|
||||
creators["spirit healer"] = &ChatActionContext::spirit_healer;
|
||||
creators["position"] = &ChatActionContext::position;
|
||||
creators["tell target"] = &ChatActionContext::tell_target;
|
||||
creators["summon"] = &ChatActionContext::summon;
|
||||
creators["who"] = &ChatActionContext::who;
|
||||
creators["save mana"] = &ChatActionContext::save_mana;
|
||||
creators["max dps chat shortcut"] = &ChatActionContext::max_dps_chat_shortcut;
|
||||
creators["tell attackers"] = &ChatActionContext::tell_attackers;
|
||||
creators["formation"] = &ChatActionContext::formation;
|
||||
creators["stance"] = &ChatActionContext::stance;
|
||||
creators["sendmail"] = &ChatActionContext::sendmail;
|
||||
creators["mail"] = &ChatActionContext::mail;
|
||||
creators["go"] = &ChatActionContext::go;
|
||||
creators["debug"] = &ChatActionContext::debug;
|
||||
creators["cdebug"] = &ChatActionContext::debug;
|
||||
creators["cs"] = &ChatActionContext::cs;
|
||||
creators["wts"] = &ChatActionContext::wts;
|
||||
creators["hire"] = &ChatActionContext::hire;
|
||||
creators["craft"] = &ChatActionContext::craft;
|
||||
creators["flag"] = &ChatActionContext::flag;
|
||||
creators["give leader"] = &ChatActionContext::give_leader;
|
||||
creators["cheat"] = &ChatActionContext::cheat;
|
||||
creators["ginvite"] = &ChatActionContext::ginvite;
|
||||
creators["guild promote"] = &ChatActionContext::guild_promote;
|
||||
creators["guild demote"] = &ChatActionContext::guild_demote;
|
||||
creators["guild remove"] = &ChatActionContext::guild_remove;
|
||||
creators["guild leave"] = &ChatActionContext::guild_leave;
|
||||
creators["rtsc"] = &ChatActionContext::rtsc;
|
||||
}
|
||||
|
||||
private:
|
||||
static Action* range(PlayerbotAI* botAI) { return new RangeAction(botAI); }
|
||||
static Action* flag(PlayerbotAI* botAI) { return new FlagAction(botAI); }
|
||||
static Action* craft(PlayerbotAI* botAI) { return new SetCraftAction(botAI); }
|
||||
static Action* hire(PlayerbotAI* botAI) { return new HireAction(botAI); }
|
||||
static Action* wts(PlayerbotAI* botAI) { return new WtsAction(botAI); }
|
||||
static Action* cs(PlayerbotAI* botAI) { return new CustomStrategyEditAction(botAI); }
|
||||
static Action* debug(PlayerbotAI* botAI) { return new DebugAction(botAI); }
|
||||
static Action* mail(PlayerbotAI* botAI) { return new MailAction(botAI); }
|
||||
static Action* go(PlayerbotAI* botAI) { return new GoAction(botAI); }
|
||||
static Action* sendmail(PlayerbotAI* botAI) { return new SendMailAction(botAI); }
|
||||
static Action* formation(PlayerbotAI* botAI) { return new SetFormationAction(botAI); }
|
||||
static Action* stance(PlayerbotAI* botAI) { return new SetStanceAction(botAI); }
|
||||
static Action* tell_attackers(PlayerbotAI* botAI) { return new TellAttackersAction(botAI); }
|
||||
static Action* max_dps_chat_shortcut(PlayerbotAI* botAI) { return new MaxDpsChatShortcutAction(botAI); }
|
||||
static Action* save_mana(PlayerbotAI* botAI) { return new SaveManaAction(botAI); }
|
||||
static Action* who(PlayerbotAI* botAI) { return new WhoAction(botAI); }
|
||||
static Action* summon(PlayerbotAI* botAI) { return new SummonAction(botAI); }
|
||||
static Action* tell_target(PlayerbotAI* botAI) { return new TellTargetAction(botAI); }
|
||||
static Action* position(PlayerbotAI* botAI) { return new PositionAction(botAI); }
|
||||
static Action* spirit_healer(PlayerbotAI* botAI) { return new SpiritHealerAction(botAI); }
|
||||
static Action* rti(PlayerbotAI* botAI) { return new RtiAction(botAI); }
|
||||
static Action* invite(PlayerbotAI* botAI) { return new InviteToGroupAction(botAI); }
|
||||
static Action* spell(PlayerbotAI* botAI) { return new TellSpellAction(botAI); }
|
||||
static Action* cast_custom_spell(PlayerbotAI* botAI) { return new CastCustomSpellAction(botAI); }
|
||||
static Action* cast_custom_nc_spell(PlayerbotAI* botAI) { return new CastCustomNcSpellAction(botAI); }
|
||||
static Action* tank_attack_chat_shortcut(PlayerbotAI* botAI) { return new TankAttackChatShortcutAction(botAI); }
|
||||
static Action* grind_chat_shortcut(PlayerbotAI* botAI) { return new GrindChatShortcutAction(botAI); }
|
||||
static Action* flee_chat_shortcut(PlayerbotAI* botAI) { return new FleeChatShortcutAction(botAI); }
|
||||
static Action* runaway_chat_shortcut(PlayerbotAI* botAI) { return new GoawayChatShortcutAction(botAI); }
|
||||
static Action* stay_chat_shortcut(PlayerbotAI* botAI) { return new StayChatShortcutAction(botAI); }
|
||||
static Action* follow_chat_shortcut(PlayerbotAI* botAI) { return new FollowChatShortcutAction(botAI); }
|
||||
static Action* gb(PlayerbotAI* botAI) { return new GuildBankAction(botAI); }
|
||||
static Action* bank(PlayerbotAI* botAI) { return new BankAction(botAI); }
|
||||
static Action* help(PlayerbotAI* botAI) { return new HelpAction(botAI); }
|
||||
static Action* buff(PlayerbotAI* botAI) { return new BuffAction(botAI); }
|
||||
static Action* destroy(PlayerbotAI* botAI) { return new DestroyItemAction(botAI); }
|
||||
static Action* home(PlayerbotAI* botAI) { return new SetHomeAction(botAI); }
|
||||
static Action* chat(PlayerbotAI* botAI) { return new ChangeChatAction(botAI); }
|
||||
static Action* attack_my_target(PlayerbotAI* botAI) { return new AttackMyTargetAction(botAI); }
|
||||
static Action* trainer(PlayerbotAI* botAI) { return new TrainerAction(botAI); }
|
||||
static Action* co(PlayerbotAI* botAI) { return new ChangeCombatStrategyAction(botAI); }
|
||||
static Action* nc(PlayerbotAI* botAI) { return new ChangeNonCombatStrategyAction(botAI); }
|
||||
static Action* dead(PlayerbotAI* botAI) { return new ChangeDeadStrategyAction(botAI); }
|
||||
static Action* spells(PlayerbotAI* botAI) { return new ListSpellsAction(botAI); }
|
||||
static Action* talents(PlayerbotAI* botAI) { return new ChangeTalentsAction(botAI); }
|
||||
|
||||
static Action* equip(PlayerbotAI* botAI) { return new EquipAction(botAI); }
|
||||
static Action* equip_upgrades(PlayerbotAI* botAI) { return new EquipUpgradesAction(botAI); }
|
||||
static Action* unequip(PlayerbotAI* botAI) { return new UnequipAction(botAI); }
|
||||
static Action* sell(PlayerbotAI* botAI) { return new SellAction(botAI); }
|
||||
static Action* buy(PlayerbotAI* botAI) { return new BuyAction(botAI); }
|
||||
static Action* reward(PlayerbotAI* botAI) { return new RewardAction(botAI); }
|
||||
static Action* trade(PlayerbotAI* botAI) { return new TradeAction(botAI); }
|
||||
|
||||
static Action* item_count(PlayerbotAI* botAI) { return new TellItemCountAction(botAI); }
|
||||
static Action* use(PlayerbotAI* botAI) { return new UseItemAction(botAI); }
|
||||
static Action* repair(PlayerbotAI* botAI) { return new RepairAllAction(botAI); }
|
||||
static Action* taxi(PlayerbotAI* botAI) { return new TaxiAction(botAI); }
|
||||
static Action* teleport(PlayerbotAI* botAI) { return new TeleportAction(botAI); }
|
||||
static Action* release(PlayerbotAI* botAI) { return new ReleaseSpiritAction(botAI); }
|
||||
static Action* repop(PlayerbotAI* botAI) { return new RepopAction(botAI); }
|
||||
static Action* query_item_usage(PlayerbotAI* botAI) { return new QueryItemUsageAction(botAI); }
|
||||
static Action* query_quest(PlayerbotAI* botAI) { return new QueryQuestAction(botAI); }
|
||||
static Action* drop(PlayerbotAI* botAI) { return new DropQuestAction(botAI); }
|
||||
static Action* clean_quest_log(PlayerbotAI* botAI) { return new CleanQuestLogAction(botAI); }
|
||||
static Action* share(PlayerbotAI* botAI) { return new ShareQuestAction(botAI); }
|
||||
static Action* stats(PlayerbotAI* botAI) { return new StatsAction(botAI); }
|
||||
static Action* quests(PlayerbotAI* botAI) { return new ListQuestsAction(botAI); }
|
||||
static Action* leave(PlayerbotAI* botAI) { return new LeaveGroupAction(botAI); }
|
||||
static Action* reputation(PlayerbotAI* botAI) { return new TellReputationAction(botAI); }
|
||||
static Action* log(PlayerbotAI* botAI) { return new LogLevelAction(botAI); }
|
||||
static Action* los(PlayerbotAI* botAI) { return new TellLosAction(botAI); }
|
||||
static Action* ll(PlayerbotAI* botAI) { return new LootStrategyAction(botAI); }
|
||||
static Action* ss(PlayerbotAI* botAI) { return new SkipSpellsListAction(botAI); }
|
||||
static Action* add_all_loot(PlayerbotAI* botAI) { return new AddAllLootAction(botAI); }
|
||||
static Action* reset_ai(PlayerbotAI* botAI) { return new ResetAiAction(botAI); }
|
||||
static Action* gossip_hello(PlayerbotAI* botAI) { return new GossipHelloAction(botAI); }
|
||||
static Action* give_leader(PlayerbotAI* botAI) { return new GiveLeaderAction(botAI); }
|
||||
static Action* cheat(PlayerbotAI* botAI) { return new CheatAction(botAI); }
|
||||
static Action* ginvite(PlayerbotAI* botAI) { return new GuildInviteAction(botAI); }
|
||||
static Action* guild_promote(PlayerbotAI* botAI) { return new GuildPromoteAction(botAI); }
|
||||
static Action* guild_demote(PlayerbotAI* botAI) { return new GuildDemoteAction(botAI); }
|
||||
static Action* guild_remove(PlayerbotAI* botAI) { return new GuildRemoveAction(botAI); }
|
||||
static Action* guild_leave(PlayerbotAI* botAI) { return new GuildLeaveAction(botAI); }
|
||||
static Action* rtsc(PlayerbotAI* botAI) { return new RTSCAction(botAI); }
|
||||
};
|
||||
|
||||
#endif
|
||||
190
src/strategy/actions/ChatShortcutActions.cpp
Normal file
190
src/strategy/actions/ChatShortcutActions.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChatShortcutActions.h"
|
||||
#include "Event.h"
|
||||
#include "Formations.h"
|
||||
#include "PositionValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
void ReturnPositionResetAction::ResetReturnPosition()
|
||||
{
|
||||
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||
PositionInfo pos = posMap["return"];
|
||||
pos.Reset();
|
||||
posMap["return"] = pos;
|
||||
}
|
||||
|
||||
void ReturnPositionResetAction::SetReturnPosition(float x, float y, float z)
|
||||
{
|
||||
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||
PositionInfo pos = posMap["return"];
|
||||
pos.Set(x, y, z, botAI->GetBot()->GetMapId());
|
||||
posMap["return"] = pos;
|
||||
}
|
||||
|
||||
bool FollowChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
botAI->ChangeStrategy("+follow,-passive", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("-follow,-passive", BOT_STATE_COMBAT);
|
||||
|
||||
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||
PositionInfo pos = posMap["return"];
|
||||
pos.Reset();
|
||||
posMap["return"] = pos;
|
||||
|
||||
if (bot->IsInCombat())
|
||||
{
|
||||
Formation* formation = AI_VALUE(Formation*, "formation");
|
||||
std::string const target = formation->GetTargetName();
|
||||
bool moved = false;
|
||||
if (!target.empty())
|
||||
{
|
||||
moved = Follow(AI_VALUE(Unit*, target));
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldLocation loc = formation->GetLocation();
|
||||
if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1)
|
||||
return false;
|
||||
|
||||
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ());
|
||||
}
|
||||
|
||||
if (moved)
|
||||
{
|
||||
botAI->TellMaster("Following");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default mechanics takes care of this now.
|
||||
if (bot->GetMapId() != master->GetMapId() || (master && bot->GetDistance(master) > sPlayerbotAIConfig->sightDistance))
|
||||
{
|
||||
if (bot->isDead())
|
||||
{
|
||||
bot->ResurrectPlayer(1.0f, false);
|
||||
botAI->TellMasterNoFacing("Back from the grave!");
|
||||
}
|
||||
else
|
||||
botAI->TellMaster("You are too far away from me! I will there soon.");
|
||||
|
||||
bot->TeleportTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), master->GetOrientation());
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
botAI->TellMaster("Following");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StayChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
botAI->ChangeStrategy("+stay,-passive", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("-follow,-passive", BOT_STATE_COMBAT);
|
||||
|
||||
SetReturnPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
||||
|
||||
botAI->TellMaster("Staying");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FleeChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
botAI->ChangeStrategy("+follow,+passive", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("+follow,+passive", BOT_STATE_COMBAT);
|
||||
|
||||
ResetReturnPosition();
|
||||
|
||||
if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig->sightDistance)
|
||||
{
|
||||
botAI->TellError("I will not flee with you - too far away");
|
||||
return true;
|
||||
}
|
||||
|
||||
botAI->TellMaster("Fleeing");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GoawayChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
botAI->ChangeStrategy("+runaway", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("+runaway", BOT_STATE_COMBAT);
|
||||
|
||||
ResetReturnPosition();
|
||||
|
||||
botAI->TellMaster("Running away");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrindChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
botAI->ChangeStrategy("+grind,-passive", BOT_STATE_NON_COMBAT);
|
||||
|
||||
ResetReturnPosition();
|
||||
|
||||
botAI->TellMaster("Grinding");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TankAttackChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
if (!botAI->IsTank(bot))
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
botAI->ChangeStrategy("-passive", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("-passive", BOT_STATE_COMBAT);
|
||||
|
||||
ResetReturnPosition();
|
||||
|
||||
botAI->TellMaster("Attacking");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaxDpsChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
if (!botAI->ContainsStrategy(STRATEGY_TYPE_DPS))
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
|
||||
botAI->ChangeStrategy("-threat,-conserve mana,-cast time,+dps debuff,+boost", BOT_STATE_COMBAT);
|
||||
botAI->TellMaster("Max DPS!");
|
||||
|
||||
return true;
|
||||
}
|
||||
77
src/strategy/actions/ChatShortcutActions.h
Normal file
77
src/strategy/actions/ChatShortcutActions.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHATSHORTCUTACTION_H
|
||||
#define _PLAYERBOT_CHATSHORTCUTACTION_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class ReturnPositionResetAction : public Action
|
||||
{
|
||||
public:
|
||||
ReturnPositionResetAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { }
|
||||
|
||||
void ResetReturnPosition();
|
||||
void SetReturnPosition(float x, float y, float z);
|
||||
};
|
||||
|
||||
class FollowChatShortcutAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
FollowChatShortcutAction(PlayerbotAI* botAI) : MovementAction(botAI, "follow chat shortcut") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class StayChatShortcutAction : public ReturnPositionResetAction
|
||||
{
|
||||
public:
|
||||
StayChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "stay chat shortcut") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class FleeChatShortcutAction : public ReturnPositionResetAction
|
||||
{
|
||||
public:
|
||||
FleeChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "flee chat shortcut") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class GoawayChatShortcutAction : public ReturnPositionResetAction
|
||||
{
|
||||
public:
|
||||
GoawayChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "runaway chat shortcut") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class GrindChatShortcutAction : public ReturnPositionResetAction
|
||||
{
|
||||
public:
|
||||
GrindChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "grind chat shortcut") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class TankAttackChatShortcutAction : public ReturnPositionResetAction
|
||||
{
|
||||
public:
|
||||
TankAttackChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "tank attack chat shortcut") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class MaxDpsChatShortcutAction : public Action
|
||||
{
|
||||
public:
|
||||
MaxDpsChatShortcutAction(PlayerbotAI* botAI) : Action(botAI, "max dps chat shortcut") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
89
src/strategy/actions/CheatAction.cpp
Normal file
89
src/strategy/actions/CheatAction.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CheatAction.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool CheatAction::Execute(Event event)
|
||||
{
|
||||
std::string const param = event.getParam();
|
||||
|
||||
uint32 cheatMask = (uint32)botAI->GetCheat();
|
||||
|
||||
std::vector<std::string> splitted = split(param, ',');
|
||||
for (std::vector<std::string>::iterator i = splitted.begin(); i != splitted.end(); i++)
|
||||
{
|
||||
const char* name = i->c_str();
|
||||
switch (name[0])
|
||||
{
|
||||
case '+':
|
||||
cheatMask |= (uint32)GetCheatMask(name + 1);
|
||||
break;
|
||||
case '-':
|
||||
cheatMask ^= (uint32)GetCheatMask(name + 1);
|
||||
break;
|
||||
case '?':
|
||||
ListCheats();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
botAI->SetCheat(BotCheatMask(cheatMask));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BotCheatMask CheatAction::GetCheatMask(std::string const cheat)
|
||||
{
|
||||
if (cheat=="taxi")
|
||||
return BotCheatMask::taxi;
|
||||
|
||||
if (cheat == "gold")
|
||||
return BotCheatMask::gold;
|
||||
|
||||
if (cheat == "health")
|
||||
return BotCheatMask::health;
|
||||
|
||||
if (cheat == "mana")
|
||||
return BotCheatMask::mana;
|
||||
|
||||
if (cheat == "power")
|
||||
return BotCheatMask::power;
|
||||
|
||||
return BotCheatMask::none;
|
||||
}
|
||||
|
||||
std::string const CheatAction::GetCheatName(BotCheatMask cheatMask)
|
||||
{
|
||||
switch (cheatMask)
|
||||
{
|
||||
case BotCheatMask::taxi:
|
||||
return "taxi";
|
||||
case BotCheatMask::gold:
|
||||
return "gold";
|
||||
case BotCheatMask::health:
|
||||
return "health";
|
||||
case BotCheatMask::mana:
|
||||
return "mana";
|
||||
case BotCheatMask::power:
|
||||
return "power";
|
||||
default:
|
||||
return "none";
|
||||
}
|
||||
}
|
||||
|
||||
void CheatAction::ListCheats()
|
||||
{
|
||||
std::ostringstream out;
|
||||
for (int i = 0; i < log2((uint32)BotCheatMask::maxMask); i++)
|
||||
{
|
||||
BotCheatMask cheatMask = BotCheatMask(1 << i);
|
||||
if ((uint32)cheatMask & (uint32)sPlayerbotAIConfig->botCheatMask)
|
||||
out << "[conf:" << GetCheatName(BotCheatMask(cheatMask)) << "]";
|
||||
else if (botAI->HasCheat(cheatMask))
|
||||
out << "[" << GetCheatName(BotCheatMask(cheatMask)) << "]";
|
||||
}
|
||||
|
||||
botAI->TellMasterNoFacing(out);
|
||||
}
|
||||
22
src/strategy/actions/CheatAction.h
Normal file
22
src/strategy/actions/CheatAction.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
enum class BotCheatMask : uint32;
|
||||
|
||||
class CheatAction : public Action
|
||||
{
|
||||
public:
|
||||
CheatAction(PlayerbotAI* botAI) : Action(botAI, "cheat") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
static BotCheatMask GetCheatMask(std::string const cheat);
|
||||
static std::string const GetCheatName(BotCheatMask cheatMask);
|
||||
void ListCheats();
|
||||
};
|
||||
101
src/strategy/actions/CheckMailAction.cpp
Normal file
101
src/strategy/actions/CheckMailAction.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CheckMailAction.h"
|
||||
#include "Event.h"
|
||||
#include "GuildTaskMgr.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool CheckMailAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p;
|
||||
bot->GetSession()->HandleQueryNextMailTime(p);
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
std::vector<uint32> ids;
|
||||
for (PlayerMails::const_iterator i = bot->GetMails().begin(); i != bot->GetMails().end(); ++i)
|
||||
{
|
||||
Mail* mail = *i;
|
||||
if (!mail || mail->state == MAIL_STATE_DELETED)
|
||||
continue;
|
||||
|
||||
Player* owner = ObjectAccessor::FindConnectedPlayer(ObjectGuid::Create<HighGuid::Player>(mail->sender));
|
||||
if (!owner)
|
||||
continue;
|
||||
|
||||
uint32 account = owner->GetSession()->GetAccountId();
|
||||
if (sPlayerbotAIConfig->IsInRandomAccountList(account))
|
||||
continue;
|
||||
|
||||
ProcessMail(mail, owner, trans);
|
||||
ids.push_back(mail->messageID);
|
||||
mail->state = MAIL_STATE_DELETED;
|
||||
}
|
||||
|
||||
for (uint32 id : ids)
|
||||
{
|
||||
bot->SendMailResult(id, MAIL_DELETED, MAIL_OK);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
|
||||
stmt->SetData(0, id);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
|
||||
stmt->SetData(0, id);
|
||||
trans->Append(stmt);
|
||||
|
||||
bot->RemoveMail(id);
|
||||
}
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckMailAction::isUseful()
|
||||
{
|
||||
if (botAI->GetMaster() || !bot->GetMailSize() || bot->InBattleground())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckMailAction::ProcessMail(Mail* mail, Player* owner, CharacterDatabaseTransaction trans)
|
||||
{
|
||||
if (mail->items.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mail->subject.find("Item(s) you asked for") != std::string::npos)
|
||||
return;
|
||||
|
||||
for (MailItemInfoVec::iterator i = mail->items.begin(); i != mail->items.end(); ++i)
|
||||
{
|
||||
Item *item = bot->GetMItem(i->item_guid);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
if (!sGuildTaskMgr->CheckItemTask(i->item_template, item->GetCount(), owner, bot, true))
|
||||
{
|
||||
std::ostringstream body;
|
||||
body << "Hello, " << owner->GetName() << ",\n";
|
||||
body << "\n";
|
||||
body << "Here are the item(s) you've sent me by mistake";
|
||||
body << "\n";
|
||||
body << "Thanks,\n";
|
||||
body << bot->GetName() << "\n";
|
||||
|
||||
MailDraft draft("Item(s) you've sent me", body.str());
|
||||
draft.AddItem(item);
|
||||
bot->RemoveMItem(i->item_guid);
|
||||
draft.SendMailTo(trans, MailReceiver(owner), MailSender(bot));
|
||||
return;
|
||||
}
|
||||
|
||||
bot->RemoveMItem(i->item_guid);
|
||||
item->DestroyForPlayer(bot);
|
||||
}
|
||||
}
|
||||
27
src/strategy/actions/CheckMailAction.h
Normal file
27
src/strategy/actions/CheckMailAction.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHECKMAILACTION_H
|
||||
#define _PLAYERBOT_CHECKMAILACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "DatabaseEnvFwd.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
struct Mail;
|
||||
|
||||
class CheckMailAction : public Action
|
||||
{
|
||||
public:
|
||||
CheckMailAction(PlayerbotAI* botAI) : Action(botAI, "check mail") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
private:
|
||||
void ProcessMail(Mail* mail, Player* owner, CharacterDatabaseTransaction trans);
|
||||
};
|
||||
|
||||
#endif
|
||||
274
src/strategy/actions/CheckMountStateAction.cpp
Normal file
274
src/strategy/actions/CheckMountStateAction.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CheckMountStateAction.h"
|
||||
#include "BattlegroundWS.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
|
||||
bool CheckMountStateAction::Execute(Event event)
|
||||
{
|
||||
bool noattackers = AI_VALUE2(bool, "combat", "self target") ? (AI_VALUE(uint8, "attacker count") > 0 ? false : true) : true;
|
||||
bool enemy = AI_VALUE(Unit*, "enemy player target");
|
||||
bool dps = (AI_VALUE(Unit*, "dps target") || AI_VALUE(Unit*, "grind target"));
|
||||
bool fartarget = (enemy && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player target"), 40.0f)) ||
|
||||
(dps && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "dps target"), 50.0f));
|
||||
bool attackdistance = false;
|
||||
bool chasedistance = false;
|
||||
float attack_distance = 35.0f;
|
||||
|
||||
switch (bot->getClass())
|
||||
{
|
||||
case CLASS_WARRIOR:
|
||||
case CLASS_PALADIN:
|
||||
attack_distance = 10.0f;
|
||||
break;
|
||||
case CLASS_ROGUE:
|
||||
attack_distance = 40.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (enemy)
|
||||
attack_distance /= 2;
|
||||
|
||||
if (dps || enemy)
|
||||
{
|
||||
attackdistance = (enemy || dps) && sServerFacade->IsDistanceLessThan(AI_VALUE2(float, "distance", "current target"), attack_distance);
|
||||
chasedistance = enemy && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player target"), 45.0f) && AI_VALUE2(bool, "moving", "enemy player target");
|
||||
}
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (master != nullptr && !bot->InBattleground())
|
||||
{
|
||||
if (!bot->GetGroup() || bot->GetGroup()->GetLeaderGUID() != master->GetGUID())
|
||||
return false;
|
||||
|
||||
bool farFromMaster = sServerFacade->GetDistance2d(bot, master) > sPlayerbotAIConfig->sightDistance;
|
||||
if (master->IsMounted() && !bot->IsMounted() && noattackers)
|
||||
{
|
||||
return Mount();
|
||||
}
|
||||
|
||||
if (!bot->IsMounted() && (chasedistance || (farFromMaster && botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))) && !bot->IsInCombat() && !dps)
|
||||
return Mount();
|
||||
|
||||
if (!bot->IsFlying() && ((!farFromMaster && !master->IsMounted()) || attackdistance) && bot->IsMounted())
|
||||
{
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->InBattleground() && !attackdistance && (noattackers || fartarget) && !bot->IsInCombat() && !bot->IsMounted())
|
||||
{
|
||||
if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS)
|
||||
{
|
||||
BattlegroundWS *bg = (BattlegroundWS*)botAI->GetBot()->GetBattleground();
|
||||
if (bot->HasAura(23333) || bot->HasAura(23335))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return Mount();
|
||||
}
|
||||
|
||||
if (!bot->InBattleground())
|
||||
{
|
||||
if (AI_VALUE(GuidPosition, "rpg target"))
|
||||
{
|
||||
if (sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "rpg target"), sPlayerbotAIConfig->farDistance) && noattackers && !dps && !enemy)
|
||||
return Mount();
|
||||
}
|
||||
|
||||
if (((!AI_VALUE(GuidVector, "possible rpg targets").empty()) && noattackers && !dps && !enemy) && urand(0, 100) > 50)
|
||||
return Mount();
|
||||
}
|
||||
|
||||
if (!bot->IsMounted() && !attackdistance && (fartarget || chasedistance))
|
||||
return Mount();
|
||||
|
||||
if (!bot->IsFlying() && attackdistance && bot->IsMounted() && (enemy || dps || (!noattackers && bot->IsInCombat())))
|
||||
{
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckMountStateAction::isUseful()
|
||||
{
|
||||
// do not use on vehicle
|
||||
if (botAI->IsInVehicle())
|
||||
return false;
|
||||
|
||||
if (bot->isDead())
|
||||
return false;
|
||||
|
||||
bool isOutdoor = bot->IsOutdoors();
|
||||
if (!isOutdoor)
|
||||
return false;
|
||||
|
||||
if (bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||
return false;
|
||||
|
||||
if (bot->InArena())
|
||||
return false;
|
||||
|
||||
if (!GET_PLAYERBOT_AI(bot)->HasStrategy("mount", BOT_STATE_NON_COMBAT) && !bot->IsMounted())
|
||||
return false;
|
||||
|
||||
bool firstmount = bot->getLevel() >= 20;
|
||||
if (!firstmount)
|
||||
return false;
|
||||
|
||||
// Do not use with BG Flags
|
||||
if (bot->HasAura(23333) || bot->HasAura(23335) || bot->HasAura(34976))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only mount if BG starts in less than 30 sec
|
||||
if (bot->InBattleground())
|
||||
{
|
||||
if (Battleground* bg = bot->GetBattleground())
|
||||
if (bg->GetStatus() == STATUS_WAIT_JOIN)
|
||||
{
|
||||
if (bg->GetStartDelayTime() > BG_START_DELAY_30S)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckMountStateAction::Mount()
|
||||
{
|
||||
uint32 secondmount = 40;
|
||||
|
||||
if (bot->isMoving())
|
||||
{
|
||||
bot->StopMoving();
|
||||
bot->GetMotionMaster()->Clear();
|
||||
bot->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
|
||||
Player* master = GetMaster();
|
||||
botAI->RemoveShapeshift();
|
||||
|
||||
int32 masterSpeed = 59;
|
||||
SpellInfo const* masterSpell = nullptr;
|
||||
|
||||
if (master && !master->GetAuraEffectsByType(SPELL_AURA_MOUNTED).empty() && !bot->InBattleground())
|
||||
{
|
||||
masterSpell = master->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetSpellInfo();
|
||||
masterSpeed = std::max(masterSpell->Effects[1].BasePoints, masterSpell->Effects[2].BasePoints);
|
||||
}
|
||||
else
|
||||
{
|
||||
masterSpeed = 59;
|
||||
for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr)
|
||||
{
|
||||
uint32 spellId = itr->first;
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo || spellInfo->Effects[0].ApplyAuraName != SPELL_AURA_MOUNTED)
|
||||
continue;
|
||||
|
||||
if (itr->second->State == PLAYERSPELL_REMOVED || !itr->second->Active || spellInfo->IsPassive())
|
||||
continue;
|
||||
|
||||
int32 effect = std::max(spellInfo->Effects[1].BasePoints, spellInfo->Effects[2].BasePoints);
|
||||
if (effect > masterSpeed)
|
||||
masterSpeed = effect;
|
||||
}
|
||||
}
|
||||
|
||||
if (bot->GetPureSkillValue(SKILL_RIDING) <= 75 && bot->getLevel() < secondmount)
|
||||
masterSpeed = 59;
|
||||
|
||||
if (bot->InBattleground() && masterSpeed > 99)
|
||||
masterSpeed = 99;
|
||||
|
||||
bool hasSwiftMount = false;
|
||||
|
||||
//std::map<int32, std::vector<uint32> > spells;
|
||||
std::map<uint32, std::map<int32, std::vector<uint32>>> allSpells;
|
||||
for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr)
|
||||
{
|
||||
uint32 spellId = itr->first;
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo || spellInfo->Effects[0].ApplyAuraName != SPELL_AURA_MOUNTED)
|
||||
continue;
|
||||
|
||||
if (itr->second->State == PLAYERSPELL_REMOVED || !itr->second->Active || spellInfo->IsPassive())
|
||||
continue;
|
||||
|
||||
int32 effect = std::max(spellInfo->Effects[1].BasePoints, spellInfo->Effects[2].BasePoints);
|
||||
//if (effect < masterSpeed)
|
||||
//continue;
|
||||
|
||||
uint32 index = (spellInfo->Effects[1].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED ||
|
||||
spellInfo->Effects[2].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) ? 1 : 0;
|
||||
|
||||
if (index == 0 && std::max(spellInfo->Effects[EFFECT_1].BasePoints, spellInfo->Effects[EFFECT_2].BasePoints) > 59)
|
||||
hasSwiftMount = true;
|
||||
|
||||
if (index == 1 && std::max(spellInfo->Effects[EFFECT_1].BasePoints, spellInfo->Effects[EFFECT_2].BasePoints) > 149)
|
||||
hasSwiftMount = true;
|
||||
|
||||
allSpells[index][effect].push_back(spellId);
|
||||
}
|
||||
|
||||
int32 masterMountType = 0;
|
||||
if (masterSpell)
|
||||
{
|
||||
masterMountType = (masterSpell->Effects[1].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED ||
|
||||
masterSpell->Effects[2].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) ? 1 : 0;
|
||||
}
|
||||
|
||||
std::map<int32, std::vector<uint32>>& spells = allSpells[masterMountType];
|
||||
if (hasSwiftMount)
|
||||
{
|
||||
for (auto i : spells)
|
||||
{
|
||||
std::vector<uint32> ids = i.second;
|
||||
for (auto itr : ids)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (masterMountType == 0 && masterSpeed > 59 && std::max(spellInfo->Effects[EFFECT_1].BasePoints, spellInfo->Effects[EFFECT_2].BasePoints) < 99)
|
||||
spells[59].clear();
|
||||
|
||||
if (masterMountType == 1 && masterSpeed > 149 && std::max(spellInfo->Effects[EFFECT_1].BasePoints, spellInfo->Effects[EFFECT_2].BasePoints) < 279)
|
||||
spells[149].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<int32, std::vector<uint32>>::iterator i = spells.begin(); i != spells.end(); ++i)
|
||||
{
|
||||
std::vector<uint32>& ids = i->second;
|
||||
uint32 index = urand(0, ids.size() - 1);
|
||||
if (index >= ids.size())
|
||||
continue;
|
||||
|
||||
botAI->CastSpell(ids[index], bot);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "mount");
|
||||
if (!items.empty())
|
||||
return UseItemAuto(*items.begin());
|
||||
|
||||
return false;
|
||||
}
|
||||
23
src/strategy/actions/CheckMountStateAction.h
Normal file
23
src/strategy/actions/CheckMountStateAction.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHECKMOUNTSTATEACTION_H
|
||||
#define _PLAYERBOT_CHECKMOUNTSTATEACTION_H
|
||||
|
||||
#include "UseItemAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class CheckMountStateAction : public UseItemAction
|
||||
{
|
||||
public:
|
||||
CheckMountStateAction(PlayerbotAI* botAI) : UseItemAction(botAI, "check mount state", true) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
bool isPossible() override { return true; }
|
||||
bool Mount();
|
||||
};
|
||||
|
||||
#endif
|
||||
34
src/strategy/actions/CheckValuesAction.cpp
Normal file
34
src/strategy/actions/CheckValuesAction.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CheckValuesAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
CheckValuesAction::CheckValuesAction(PlayerbotAI* botAI) : Action(botAI, "check values")
|
||||
{
|
||||
}
|
||||
|
||||
bool CheckValuesAction::Execute(Event event)
|
||||
{
|
||||
if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
botAI->Ping(bot->GetPositionX(), bot->GetPositionY());
|
||||
}
|
||||
|
||||
if (botAI->HasStrategy("map", BOT_STATE_NON_COMBAT) || botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
sTravelNodeMap->manageNodes(bot, botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT));
|
||||
}
|
||||
|
||||
GuidVector possible_targets = *context->GetValue<GuidVector>("possible targets");
|
||||
GuidVector all_targets = *context->GetValue<GuidVector>("all targets");
|
||||
GuidVector npcs = *context->GetValue<GuidVector>("nearest npcs");
|
||||
GuidVector corpses = *context->GetValue<GuidVector>("nearest corpses");
|
||||
GuidVector gos = *context->GetValue<GuidVector>("nearest game objects");
|
||||
GuidVector nfp = *context->GetValue<GuidVector>("nearest friendly players");
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/CheckValuesAction.h
Normal file
20
src/strategy/actions/CheckValuesAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHECKVALUESACTION_H
|
||||
#define _PLAYERBOT_CHECKVALUESACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class CheckValuesAction : public Action
|
||||
{
|
||||
public:
|
||||
CheckValuesAction(PlayerbotAI* botAI);
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
316
src/strategy/actions/ChooseRpgTargetAction.cpp
Normal file
316
src/strategy/actions/ChooseRpgTargetAction.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChooseRpgTargetAction.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "BudgetValues.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Event.h"
|
||||
#include "Formations.h"
|
||||
#include "GuildCreateActions.h"
|
||||
#include "PossibleRpgTargetsValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
bool ChooseRpgTargetAction::HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids)
|
||||
{
|
||||
if (botAI->HasRealPlayerMaster())
|
||||
return false;
|
||||
|
||||
uint32 num = 0;
|
||||
|
||||
for (auto& i : nearGuids)
|
||||
{
|
||||
Player* player = ObjectAccessor::FindPlayer(i);
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||
if (!botAI)
|
||||
continue;
|
||||
|
||||
if (!botAI->AllowActivity(GRIND_ACTIVITY))
|
||||
continue;
|
||||
|
||||
if (PAI_VALUE(GuidPosition, "rpg target") != guid)
|
||||
continue;
|
||||
|
||||
num++;
|
||||
if (num >= max)
|
||||
break;
|
||||
}
|
||||
|
||||
return num > 0;
|
||||
}
|
||||
|
||||
float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP)
|
||||
{
|
||||
GuidPosition currentRpgTarget = AI_VALUE(GuidPosition, "rpg target");
|
||||
SET_AI_VALUE(GuidPosition, "rpg target", guidP);
|
||||
|
||||
Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg");
|
||||
|
||||
std::vector<TriggerNode*> triggerNodes;
|
||||
rpgStrategy->InitTriggers(triggerNodes);
|
||||
|
||||
float maxRelevance = 0.0f;
|
||||
|
||||
for (auto& triggerNode : triggerNodes)
|
||||
{
|
||||
Trigger* trigger = context->GetTrigger(triggerNode->getName());
|
||||
if (trigger)
|
||||
{
|
||||
triggerNode->setTrigger(trigger);
|
||||
|
||||
if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f)
|
||||
continue;
|
||||
|
||||
trigger = triggerNode->getTrigger();
|
||||
if (!trigger->IsActive())
|
||||
continue;
|
||||
|
||||
maxRelevance = triggerNode->getFirstRelevance();
|
||||
}
|
||||
}
|
||||
|
||||
SET_AI_VALUE(GuidPosition, "rpg target", currentRpgTarget);
|
||||
|
||||
for (std::vector<TriggerNode*>::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++)
|
||||
{
|
||||
TriggerNode* trigger = *i;
|
||||
delete trigger;
|
||||
}
|
||||
|
||||
triggerNodes.clear();
|
||||
|
||||
return (maxRelevance - 1.0) * 1000.0f;
|
||||
}
|
||||
|
||||
bool ChooseRpgTargetAction::Execute(Event event)
|
||||
{
|
||||
TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target");
|
||||
|
||||
uint32 num = 0;
|
||||
|
||||
std::unordered_map<ObjectGuid, uint32> targets;
|
||||
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||
GuidVector possibleObjects = AI_VALUE(GuidVector, "nearest game objects no los");
|
||||
GuidVector possiblePlayers = AI_VALUE(GuidVector, "nearest friendly players");
|
||||
GuidSet& ignoreList = AI_VALUE(GuidSet&, "ignore rpg target");
|
||||
|
||||
for (auto target : possibleTargets)
|
||||
targets[target] = 0.0f;
|
||||
|
||||
for (auto target : possibleObjects)
|
||||
targets[target] = 0.0f;
|
||||
|
||||
for (auto target : possiblePlayers)
|
||||
targets[target] = 0.0f;
|
||||
|
||||
if (targets.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (urand(0, 9))
|
||||
{
|
||||
for (auto target : ignoreList)
|
||||
targets.erase(target);
|
||||
}
|
||||
|
||||
SET_AI_VALUE(std::string, "next rpg action", this->getName());
|
||||
|
||||
bool hasGoodRelevance = false;
|
||||
|
||||
for (auto& target : targets)
|
||||
{
|
||||
Unit* unit = ObjectAccessor::GetUnit(*bot, target.first);
|
||||
if (!unit)
|
||||
continue;
|
||||
|
||||
GuidPosition guidP(unit);
|
||||
if (!guidP)
|
||||
continue;
|
||||
|
||||
float priority = 1;
|
||||
|
||||
if (guidP.GetWorldObject() && !isFollowValid(bot, guidP.GetWorldObject()))
|
||||
continue;
|
||||
|
||||
if (guidP.IsGameObject())
|
||||
{
|
||||
GameObject* go = guidP.GetGameObject();
|
||||
if (!go || !go->isSpawned() || go->GetGoState() != GO_STATE_READY)
|
||||
continue;
|
||||
}
|
||||
else if (guidP.IsPlayer())
|
||||
{
|
||||
Player* player = guidP.GetPlayer();
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
if (GET_PLAYERBOT_AI(player))
|
||||
{
|
||||
GuidPosition guidPP = PAI_VALUE(GuidPosition, "rpg target");
|
||||
if (guidPP.IsPlayer())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (possiblePlayers.size() > 200 || HasSameTarget(guidP, urand(5, 15), possiblePlayers))
|
||||
continue;
|
||||
|
||||
float relevance = getMaxRelevance(guidP);
|
||||
|
||||
if (!hasGoodRelevance || relevance > 1)
|
||||
target.second = relevance;
|
||||
|
||||
if (target.second > 1)
|
||||
hasGoodRelevance = true;
|
||||
}
|
||||
|
||||
SET_AI_VALUE(std::string, "next rpg action", "");
|
||||
|
||||
for (auto it = begin(targets); it != end(targets);)
|
||||
{
|
||||
if (it->second == 0 || (hasGoodRelevance && it->second <= 1.0))
|
||||
{
|
||||
it = targets.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
if (targets.empty())
|
||||
{
|
||||
LOG_INFO("playerbots", "{} can't choose RPG target: all {} are not available", bot->GetName().c_str(), possibleTargets.size());
|
||||
RESET_AI_VALUE(GuidSet&, "ignore rpg target");
|
||||
RESET_AI_VALUE(GuidPosition, "rpg target");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<GuidPosition> guidps;
|
||||
std::vector<int32> relevances;
|
||||
|
||||
for (auto& target : targets)
|
||||
{
|
||||
Unit* unit = ObjectAccessor::GetUnit(*bot, target.first);
|
||||
if (!unit)
|
||||
continue;
|
||||
|
||||
GuidPosition guidP(unit);
|
||||
if (!guidP)
|
||||
continue;
|
||||
|
||||
guidps.push_back(guidP);
|
||||
relevances.push_back(target.second);
|
||||
}
|
||||
|
||||
std::mt19937 gen(time(0));
|
||||
sTravelMgr->weighted_shuffle(guidps.begin(), guidps.end(), relevances.begin(), relevances.end(), gen);
|
||||
|
||||
GuidPosition guidP(guidps.front());
|
||||
if (!guidP)
|
||||
{
|
||||
RESET_AI_VALUE(GuidPosition, "rpg target");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (botAI->HasStrategy("debug", BOT_STATE_NON_COMBAT) && guidP.GetWorldObject())
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "found: ";
|
||||
out << chat->FormatWorldobject(guidP.GetWorldObject());
|
||||
out << " " << relevances.front();
|
||||
|
||||
botAI->TellMasterNoFacing(out);
|
||||
}
|
||||
|
||||
SET_AI_VALUE(GuidPosition, "rpg target", guidP);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChooseRpgTargetAction::isUseful()
|
||||
{
|
||||
if (!botAI->AllowActivity(RPG_ACTIVITY))
|
||||
return false;
|
||||
|
||||
if (AI_VALUE(GuidPosition, "rpg target"))
|
||||
return false;
|
||||
|
||||
TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target");
|
||||
|
||||
if (travelTarget->isTraveling() && isFollowValid(bot, *travelTarget->getPosition()))
|
||||
return false;
|
||||
|
||||
if (AI_VALUE(GuidVector, "possible rpg targets").empty())
|
||||
return false;
|
||||
|
||||
if (!AI_VALUE(bool, "can move around"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldObject* target)
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
return isFollowValid(bot, WorldPosition(target));
|
||||
}
|
||||
|
||||
bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
|
||||
{
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
Player* master = botAI->GetGroupMaster();
|
||||
Player* realMaster = botAI->GetMaster();
|
||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
||||
|
||||
bool inDungeon = false;
|
||||
|
||||
if (botAI->HasActivePlayerMaster())
|
||||
{
|
||||
if (realMaster->IsInWorld() && realMaster->GetMap()->IsDungeon() && bot->GetMapId() == realMaster->GetMapId())
|
||||
inDungeon = true;
|
||||
|
||||
if (realMaster && realMaster->IsInWorld() && realMaster->GetMap()->IsDungeon() && (realMaster->GetMapId() != pos.getMapId()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!master || bot == master)
|
||||
return true;
|
||||
|
||||
if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))
|
||||
return true;
|
||||
|
||||
if (sqrt(bot->GetDistance(master)) > sPlayerbotAIConfig->rpgDistance * 2)
|
||||
return false;
|
||||
|
||||
Formation* formation = AI_VALUE(Formation*, "formation");
|
||||
float distance = master->GetDistance2d(pos.getX(), pos.getY());
|
||||
|
||||
if (!botAI->HasActivePlayerMaster() && distance < 50.0f)
|
||||
{
|
||||
Player* player = master;
|
||||
if (!master->isMoving() || PAI_VALUE(WorldPosition, "last long move").distance(pos) < sPlayerbotAIConfig->reactDistance)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inDungeon && realMaster == master && distance > 5.0f)
|
||||
return false;
|
||||
|
||||
if (!master->isMoving() && distance < 25.0f)
|
||||
return true;
|
||||
|
||||
if (distance < formation->GetMaxDistance())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
42
src/strategy/actions/ChooseRpgTargetAction.h
Normal file
42
src/strategy/actions/ChooseRpgTargetAction.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHOOSERPGTARGETACTION_H
|
||||
#define _PLAYERBOT_CHOOSERPGTARGETACTION_H
|
||||
|
||||
#include "ObjectGuid.h"
|
||||
#include "RpgAction.h"
|
||||
|
||||
class GuidPosition;
|
||||
class Player;
|
||||
class PlayerbotAI;
|
||||
class WorldObject;
|
||||
class WorldPosition;
|
||||
|
||||
class ChooseRpgTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
ChooseRpgTargetAction(PlayerbotAI* botAI, std::string const name = "choose rpg target") : Action(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
static bool isFollowValid(Player* bot, WorldObject* target);
|
||||
static bool isFollowValid(Player* bot, WorldPosition pos);
|
||||
|
||||
private:
|
||||
float getMaxRelevance(GuidPosition guidP);
|
||||
bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids);
|
||||
};
|
||||
|
||||
class ClearRpgTargetAction : public ChooseRpgTargetAction
|
||||
{
|
||||
public:
|
||||
ClearRpgTargetAction(PlayerbotAI* botAI) : ChooseRpgTargetAction(botAI, "clear rpg target") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
141
src/strategy/actions/ChooseTargetActions.cpp
Normal file
141
src/strategy/actions/ChooseTargetActions.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "ChooseRpgTargetAction.h"
|
||||
#include "Event.h"
|
||||
#include "LootObjectStack.h"
|
||||
#include "PossibleRpgTargetsValue.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
bool AttackEnemyPlayerAction::isUseful()
|
||||
{
|
||||
// if carry flag, do not start fight
|
||||
if (bot->HasAura(23333) || bot->HasAura(23335) || bot->HasAura(34976))
|
||||
return false;
|
||||
|
||||
return !sPlayerbotAIConfig->IsInPvpProhibitedZone(bot->GetAreaId());
|
||||
}
|
||||
|
||||
bool AttackEnemyFlagCarrierAction::isUseful()
|
||||
{
|
||||
Unit* target = context->GetValue<Unit*>("enemy flag carrier")->Get();
|
||||
return target && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), 75.0f) && (bot->HasAura(23333) || bot->HasAura(23335) || bot->HasAura(34976));
|
||||
}
|
||||
|
||||
bool AttackAnythingAction::isUseful()
|
||||
{
|
||||
if (!botAI->AllowActivity(GRIND_ACTIVITY)) //Bot not allowed to be active
|
||||
return false;
|
||||
|
||||
if (!AI_VALUE(bool, "can move around"))
|
||||
return false;
|
||||
|
||||
if (context->GetValue<TravelTarget*>("travel target")->Get()->isTraveling() && ChooseRpgTargetAction::isFollowValid(bot, *context->GetValue<TravelTarget*>("travel target")->Get()->getPosition())) //Bot is traveling
|
||||
return false;
|
||||
|
||||
Unit* target = GetTarget();
|
||||
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
std::string const name = std::string(target->GetName());
|
||||
if (!name.empty() && name.find("Dummy") != std::string::npos) // Target is not a targetdummy
|
||||
return false;
|
||||
|
||||
if (!ChooseRpgTargetAction::isFollowValid(bot, target)) //Do not grind mobs far away from master.
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DropTargetAction::Execute(Event event)
|
||||
{
|
||||
Unit* target = context->GetValue<Unit*>("current target")->Get();
|
||||
if (target && target->isDead())
|
||||
{
|
||||
ObjectGuid guid = target->GetGUID();
|
||||
if (guid)
|
||||
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
|
||||
}
|
||||
|
||||
ObjectGuid pullTarget = context->GetValue<ObjectGuid>("pull target")->Get();
|
||||
GuidVector possible = botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los")->Get();
|
||||
|
||||
if (pullTarget && find(possible.begin(), possible.end(), pullTarget) == possible.end())
|
||||
{
|
||||
context->GetValue<ObjectGuid>("pull target")->Set(ObjectGuid::Empty);
|
||||
}
|
||||
|
||||
context->GetValue<Unit*>("current target")->Set(nullptr);
|
||||
|
||||
bot->SetTarget(ObjectGuid::Empty);
|
||||
botAI->ChangeEngine(BOT_STATE_NON_COMBAT);
|
||||
botAI->InterruptSpell();
|
||||
bot->AttackStop();
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
if (CreatureAI* creatureAI = ((Creature*)pet)->AI())
|
||||
{
|
||||
pet->SetReactState(REACT_PASSIVE);
|
||||
pet->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
|
||||
pet->AttackStop();
|
||||
}
|
||||
}
|
||||
|
||||
if (!urand(0, 50) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
std::vector<uint32> sounds;
|
||||
if (target && target->isDead())
|
||||
{
|
||||
sounds.push_back(TEXT_EMOTE_CHEER);
|
||||
sounds.push_back(TEXT_EMOTE_CONGRATULATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
sounds.push_back(304); // guard
|
||||
sounds.push_back(325); // stay
|
||||
}
|
||||
|
||||
if (!sounds.empty())
|
||||
botAI->PlayEmote(sounds[urand(0, sounds.size() - 1)]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttackAnythingAction::Execute(Event event)
|
||||
{
|
||||
bool result = AttackAction::Execute(event);
|
||||
if (result)
|
||||
{
|
||||
if (Unit* grindTarget = GetTarget())
|
||||
{
|
||||
if (char const* grindName = grindTarget->GetName().c_str())
|
||||
{
|
||||
context->GetValue<ObjectGuid>("pull target")->Set(grindTarget->GetGUID());
|
||||
bot->GetMotionMaster()->Clear();
|
||||
bot->StopMoving();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AttackAnythingAction::isPossible()
|
||||
{
|
||||
return AttackAction::isPossible() && GetTarget();
|
||||
}
|
||||
|
||||
bool DpsAssistAction::isUseful()
|
||||
{
|
||||
// if carry flag, do not start fight
|
||||
if (bot->HasAura(23333) || bot->HasAura(23335) || bot->HasAura(34976))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
90
src/strategy/actions/ChooseTargetActions.h
Normal file
90
src/strategy/actions/ChooseTargetActions.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHOOSETARGETACTIONS_H
|
||||
#define _PLAYERBOT_CHOOSETARGETACTIONS_H
|
||||
|
||||
#include "AttackAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class DpsAoeAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
DpsAoeAction(PlayerbotAI* botAI) : AttackAction(botAI, "dps aoe") { }
|
||||
|
||||
std::string const GetTargetName() override { return "dps aoe target"; }
|
||||
};
|
||||
|
||||
class DpsAssistAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
DpsAssistAction(PlayerbotAI* botAI) : AttackAction(botAI, "dps assist") { }
|
||||
|
||||
std::string const GetTargetName() override { return "dps target"; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class TankAssistAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
TankAssistAction(PlayerbotAI* botAI) : AttackAction(botAI, "tank assist") { }
|
||||
|
||||
std::string const GetTargetName() override { return "tank target"; }
|
||||
};
|
||||
|
||||
class AttackAnythingAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackAnythingAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack anything") { }
|
||||
|
||||
std::string const GetTargetName() override { return "grind target"; }
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
bool isPossible() override;
|
||||
};
|
||||
|
||||
class AttackLeastHpTargetAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackLeastHpTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack least hp target") { }
|
||||
|
||||
std::string const GetTargetName() override { return "least hp target"; }
|
||||
};
|
||||
|
||||
class AttackEnemyPlayerAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackEnemyPlayerAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack enemy player") { }
|
||||
|
||||
std::string const GetTargetName() override { return "enemy player target"; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class AttackRtiTargetAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackRtiTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack rti target") { }
|
||||
|
||||
std::string const GetTargetName() override { return "rti target"; }
|
||||
};
|
||||
|
||||
class AttackEnemyFlagCarrierAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackEnemyFlagCarrierAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack enemy flag carrier") { }
|
||||
|
||||
std::string const GetTargetName() override { return "enemy flag carrier"; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class DropTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
DropTargetAction(PlayerbotAI* botAI) : Action(botAI, "drop target") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
857
src/strategy/actions/ChooseTravelTargetAction.cpp
Normal file
857
src/strategy/actions/ChooseTravelTargetAction.cpp
Normal file
@@ -0,0 +1,857 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChooseTravelTargetAction.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "LootObjectStack.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool ChooseTravelTargetAction::Execute(Event event)
|
||||
{
|
||||
//Get the current travel target. This target is no longer active.
|
||||
TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get();
|
||||
|
||||
//Select a new target to travel to.
|
||||
TravelTarget newTarget = TravelTarget(botAI);
|
||||
getNewTarget(&newTarget, oldTarget);
|
||||
|
||||
//If the new target is not active we failed.
|
||||
if (!newTarget.isActive())
|
||||
return false;
|
||||
|
||||
setNewTarget(&newTarget, oldTarget);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Select a new travel target.
|
||||
//Currently this selectes mostly based on priority (current quest > new quest).
|
||||
//This works fine because destinations can be full (max 15 bots per quest giver, max 1 bot per quest mob).
|
||||
//
|
||||
//Eventually we want to rewrite this to be more intelligent.
|
||||
void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget)
|
||||
{
|
||||
bool foundTarget = false;
|
||||
|
||||
foundTarget = SetGroupTarget(newTarget); //Join groups members
|
||||
|
||||
//Enpty bags/repair
|
||||
if (!foundTarget && urand(1, 100) > 10) //90% chance
|
||||
if (AI_VALUE2(bool, "group or", "should sell,can sell,following party,near leader") || AI_VALUE2(bool, "group or", "should repair,can repair,following party,near leader"))
|
||||
foundTarget = SetRpgTarget(newTarget); //Go to town to sell items or repair
|
||||
|
||||
//Rpg in city
|
||||
if (!foundTarget && urand(1, 100) > 90) //10% chance
|
||||
foundTarget = SetNpcFlagTarget(newTarget, { UNIT_NPC_FLAG_BANKER,UNIT_NPC_FLAG_BATTLEMASTER,UNIT_NPC_FLAG_AUCTIONEER });
|
||||
|
||||
//Grind for money
|
||||
if (!foundTarget && AI_VALUE(bool, "should get money"))
|
||||
if (urand(1, 100) > 66)
|
||||
{
|
||||
foundTarget = SetQuestTarget(newTarget, true); //Turn in quests for money.
|
||||
|
||||
if (!foundTarget)
|
||||
foundTarget = SetQuestTarget(newTarget); //Do low level quests
|
||||
}
|
||||
else if (urand(1, 100) > 50)
|
||||
foundTarget = SetGrindTarget(newTarget); //Go grind mobs for money
|
||||
else
|
||||
foundTarget = SetNewQuestTarget(newTarget); //Find a low level quest to do
|
||||
|
||||
|
||||
//Continue
|
||||
if (!foundTarget && urand(1, 100) > 10) //90% chance
|
||||
foundTarget = SetCurrentTarget(newTarget, oldTarget); //Extend current target.
|
||||
|
||||
//Dungeon in group
|
||||
if (!foundTarget && urand(1, 100) > 50) //50% chance
|
||||
if (AI_VALUE(bool, "can fight boss"))
|
||||
foundTarget = SetBossTarget(newTarget); //Go fight a (dungeon boss)
|
||||
|
||||
if (!foundTarget && urand(1, 100) > 5) //95% chance
|
||||
foundTarget = SetQuestTarget(newTarget); //Do a target of an active quest.
|
||||
|
||||
if (!foundTarget && urand(1, 100) > 5)
|
||||
foundTarget = SetNewQuestTarget(newTarget); //Find a new quest to do.
|
||||
|
||||
if (!foundTarget && botAI->HasStrategy("explore", BOT_STATE_NON_COMBAT)) //Explore a unexplored sub-zone.
|
||||
foundTarget = SetExploreTarget(newTarget);
|
||||
|
||||
// if (!foundTarget)
|
||||
//foundTarget = SetRpgTarget(target);
|
||||
|
||||
if (!foundTarget)
|
||||
SetNullTarget(newTarget); //Idle a bit.
|
||||
}
|
||||
|
||||
void ChooseTravelTargetAction::setNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget)
|
||||
{
|
||||
//Tell the master where we are going.
|
||||
if (!bot->GetGroup() || (botAI->GetGroupMaster() == bot))
|
||||
ReportTravelTarget(newTarget, oldTarget);
|
||||
|
||||
//If we are heading to a creature/npc clear it from the ignore list.
|
||||
if (oldTarget && oldTarget == newTarget && newTarget->getEntry())
|
||||
{
|
||||
GuidSet& ignoreList = context->GetValue<GuidSet&>("ignore rpg target")->Get();
|
||||
|
||||
for (ObjectGuid const guid : ignoreList)
|
||||
{
|
||||
if (guid.GetEntry() == newTarget->getEntry())
|
||||
{
|
||||
ignoreList.erase(guid);
|
||||
}
|
||||
}
|
||||
|
||||
context->GetValue<GuidSet&>("ignore rpg target")->Set(ignoreList);
|
||||
}
|
||||
|
||||
//Actually apply the new target to the travel target used by the bot.
|
||||
oldTarget->copyTarget(newTarget);
|
||||
|
||||
//If we are idling but have a master. Idle only 10 seconds.
|
||||
if (botAI->GetMaster() && oldTarget->isActive() && oldTarget->getDestination()->getName() == "NullTravelDestination")
|
||||
oldTarget->setExpireIn(10 * IN_MILLISECONDS);
|
||||
else if (oldTarget->isForced()) // Make sure travel goes into cooldown after getting to the destination.
|
||||
oldTarget->setExpireIn(HOUR * IN_MILLISECONDS);
|
||||
|
||||
//Clear rpg and pull/grind target. We want to travel, not hang around some more.
|
||||
RESET_AI_VALUE(GuidPosition, "rpg target");
|
||||
RESET_AI_VALUE(ObjectGuid, "pull target");
|
||||
}
|
||||
|
||||
//Tell the master what travel target we are moving towards.
|
||||
//This should at some point be rewritten to be denser or perhaps logic moved to ->getTitle()
|
||||
void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, TravelTarget* oldTarget)
|
||||
{
|
||||
TravelDestination* destination = newTarget->getDestination();
|
||||
TravelDestination* oldDestination = oldTarget->getDestination();
|
||||
|
||||
std::ostringstream out;
|
||||
|
||||
if (newTarget->isForced())
|
||||
out << "(Forced) ";
|
||||
|
||||
if (destination->getName() == "QuestRelationTravelDestination" || destination->getName() == "QuestObjectiveTravelDestination")
|
||||
{
|
||||
QuestTravelDestination* QuestDestination = (QuestTravelDestination*)destination;
|
||||
Quest const* quest = QuestDestination->GetQuestTemplate();
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
CreatureTemplate const* cInfo = nullptr;
|
||||
GameObjectTemplate const* gInfo = nullptr;
|
||||
|
||||
if (destination->getEntry() > 0)
|
||||
cInfo = sObjectMgr->GetCreatureTemplate(destination->getEntry());
|
||||
else
|
||||
gInfo = sObjectMgr->GetGameObjectTemplate(destination->getEntry() * -1);
|
||||
|
||||
std::string Sub;
|
||||
|
||||
if (newTarget->isGroupCopy())
|
||||
out << "Following group ";
|
||||
else if (oldDestination && oldDestination == destination)
|
||||
out << "Continuing ";
|
||||
else
|
||||
out << "Traveling ";
|
||||
|
||||
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
|
||||
|
||||
out << " for " << chat->FormatQuest(quest);
|
||||
|
||||
out << " to " << QuestDestination->getTitle();
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
else if (destination->getName() == "RpgTravelDestination")
|
||||
{
|
||||
RpgTravelDestination* RpgDestination = (RpgTravelDestination*)destination;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
if (newTarget->isGroupCopy())
|
||||
out << "Following group ";
|
||||
else if (oldDestination && oldDestination == destination)
|
||||
out << "Continuing ";
|
||||
else
|
||||
out << "Traveling ";
|
||||
|
||||
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
|
||||
|
||||
out << " for ";
|
||||
|
||||
if (AI_VALUE2(bool, "group or", "should sell,can sell"))
|
||||
out << "selling items";
|
||||
else if (AI_VALUE2(bool, "group or", "should repair,can repair"))
|
||||
out << "repairing";
|
||||
else
|
||||
out << "rpg";
|
||||
|
||||
out << " to " << RpgDestination->getTitle();
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
else if (destination->getName() == "ExploreTravelDestination")
|
||||
{
|
||||
ExploreTravelDestination* ExploreDestination = (ExploreTravelDestination*)destination;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
if (newTarget->isGroupCopy())
|
||||
out << "Following group ";
|
||||
else if (oldDestination && oldDestination == destination)
|
||||
out << "Continuing ";
|
||||
else
|
||||
out << "Traveling ";
|
||||
|
||||
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
|
||||
|
||||
out << " for exploration";
|
||||
|
||||
out << " to " << ExploreDestination->getTitle();
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
else if (destination->getName() == "GrindTravelDestination")
|
||||
{
|
||||
GrindTravelDestination* GrindDestination = (GrindTravelDestination*)destination;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
if (newTarget->isGroupCopy())
|
||||
out << "Following group ";
|
||||
else if (oldDestination && oldDestination == destination)
|
||||
out << "Continuing ";
|
||||
else
|
||||
out << "Traveling ";
|
||||
|
||||
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
|
||||
|
||||
out << " for grinding money";
|
||||
|
||||
out << " to " << GrindDestination->getTitle();
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
else if (destination->getName() == "BossTravelDestination")
|
||||
{
|
||||
BossTravelDestination* BossDestination = (BossTravelDestination*)destination;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
if (newTarget->isGroupCopy())
|
||||
out << "Following group ";
|
||||
else if (oldDestination && oldDestination == destination)
|
||||
out << "Continuing ";
|
||||
else
|
||||
out << "Traveling ";
|
||||
|
||||
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
|
||||
|
||||
out << " for good loot";
|
||||
|
||||
out << " to " << BossDestination->getTitle();
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
else if (destination->getName() == "NullTravelDestination")
|
||||
{
|
||||
if (!oldTarget->getDestination() || oldTarget->getDestination()->getName() != "NullTravelDestination")
|
||||
{
|
||||
botAI->TellMaster("No where to travel. Idling a bit.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::getBestDestination(std::vector<TravelDestination*>* activeDestinations, std::vector<WorldPosition*>* activePoints)
|
||||
{
|
||||
if (activeDestinations->empty() || activePoints->empty()) //No targets or no points.
|
||||
return false;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
std::vector<WorldPosition*> availablePoints = sTravelMgr->getNextPoint(&botLocation, *activePoints); //Pick a good point.
|
||||
|
||||
if (availablePoints.empty()) //No points available.
|
||||
return false;
|
||||
|
||||
TravelDestination* targetDestination;
|
||||
|
||||
for (auto activeTarget : *activeDestinations) //Pick the destination that has this point.
|
||||
if (activeTarget->distanceTo(availablePoints.front()) == 0)
|
||||
targetDestination = activeTarget;
|
||||
|
||||
if (!targetDestination)
|
||||
return false;
|
||||
|
||||
activeDestinations->clear();
|
||||
activePoints->clear();
|
||||
|
||||
activeDestinations->push_back(targetDestination);
|
||||
activePoints->push_back(availablePoints.front());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetGroupTarget(TravelTarget* target)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
GuidList groupPlayers;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
if (ref->GetSource() != bot)
|
||||
{
|
||||
if (ref->getSubGroup() != bot->GetSubGroup())
|
||||
{
|
||||
groupPlayers.push_back(ref->GetSource()->GetGUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
groupPlayers.push_front(ref->GetSource()->GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Find targets of the group.
|
||||
for (auto& member : groupPlayers)
|
||||
{
|
||||
Player* player = ObjectAccessor::FindPlayer(member);
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
PlayerbotAI* playerBotAI = GET_PLAYERBOT_AI(player);
|
||||
if (!playerBotAI)
|
||||
continue;
|
||||
|
||||
if (!playerBotAI->GetAiObjectContext())
|
||||
continue;
|
||||
|
||||
TravelTarget* groupTarget = playerBotAI->GetAiObjectContext()->GetValue<TravelTarget*>("travel target")->Get();
|
||||
|
||||
if (groupTarget->isGroupCopy())
|
||||
continue;
|
||||
|
||||
if (!groupTarget->isActive())
|
||||
continue;
|
||||
|
||||
if (!groupTarget->getDestination()->isActive(bot) || groupTarget->getDestination()->getName() == "RpgTravelDestination")
|
||||
continue;
|
||||
|
||||
activeDestinations.push_back(groupTarget->getDestination());
|
||||
activePoints.push_back(groupTarget->getPosition());
|
||||
}
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
|
||||
target->setTarget(activeDestinations.front(), activePoints.front(), true);
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetCurrentTarget(TravelTarget* target, TravelTarget* oldTarget)
|
||||
{
|
||||
TravelDestination* oldDestination = oldTarget->getDestination();
|
||||
|
||||
if (oldTarget->isMaxRetry(false))
|
||||
return false;
|
||||
|
||||
if (!oldDestination) //Does this target have a destination?
|
||||
return false;
|
||||
|
||||
if (!oldDestination->isActive(bot)) //Is the destination still valid?
|
||||
return false;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
std::vector<WorldPosition*> availablePoints = oldDestination->nextPoint(&botLocation);
|
||||
if (availablePoints.empty())
|
||||
return false;
|
||||
|
||||
target->setTarget(oldTarget->getDestination(), availablePoints.front());
|
||||
target->setStatus(TRAVEL_STATUS_TRAVEL);
|
||||
target->setRetry(false, oldTarget->getRetryCount(false) + 1);
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCompleted)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
QuestStatusMap& questMap = bot->getQuestStatusMap();
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
//Find destinations related to the active quests.
|
||||
for (auto& quest : questMap)
|
||||
{
|
||||
if (bot->IsQuestRewarded(quest.first))
|
||||
continue;
|
||||
|
||||
uint32 questId = quest.first;
|
||||
QuestStatusData* questStatus = &quest.second;
|
||||
|
||||
if (onlyCompleted && sObjectMgr->GetQuestTemplate(questId) && !bot->CanRewardQuest(sObjectMgr->GetQuestTemplate(questId), false))
|
||||
continue;
|
||||
|
||||
std::vector<TravelDestination*> questDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, botAI->HasRealPlayerMaster(), false, 5000);
|
||||
std::vector<WorldPosition*> questPoints;
|
||||
|
||||
for (auto& questDestination : questDestinations)
|
||||
{
|
||||
std::vector<WorldPosition*> destinationPoints = questDestination->getPoints();
|
||||
if (!destinationPoints.empty())
|
||||
questPoints.insert(questPoints.end(), destinationPoints.begin(), destinationPoints.end());
|
||||
}
|
||||
|
||||
if (getBestDestination(&questDestinations, &questPoints))
|
||||
{
|
||||
activeDestinations.push_back(questDestinations.front());
|
||||
activePoints.push_back(questPoints.front());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
|
||||
target->setTarget(activeDestinations.front(), activePoints.front());
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetNewQuestTarget(TravelTarget* target)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
//Find quest givers.
|
||||
std::vector<TravelDestination*> TravelDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
//Pick one good point per destination.
|
||||
for (auto& activeTarget : activeDestinations)
|
||||
{
|
||||
std::vector<WorldPosition*> points = activeTarget->nextPoint(&botLocation);
|
||||
if (!points.empty())
|
||||
activePoints.push_back(points.front());
|
||||
}
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
|
||||
target->setTarget(activeDestinations.front(), activePoints.front());
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetRpgTarget(TravelTarget* target)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
//Find rpg npcs
|
||||
std::vector<TravelDestination*> TravelDestinations = sTravelMgr->getRpgTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
//Pick one good point per destination.
|
||||
for (auto& activeTarget : activeDestinations)
|
||||
{
|
||||
std::vector<WorldPosition*> points = activeTarget->nextPoint(&botLocation);
|
||||
if (!points.empty())
|
||||
activePoints.push_back(points.front());
|
||||
}
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
|
||||
target->setTarget(activeDestinations.front(), activePoints.front());
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetGrindTarget(TravelTarget* target)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
//Find grind mobs.
|
||||
std::vector<TravelDestination*> TravelDestinations = sTravelMgr->getGrindTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
//Pick one good point per destination.
|
||||
for (auto& activeTarget : activeDestinations)
|
||||
{
|
||||
std::vector<WorldPosition*> points = activeTarget->nextPoint(&botLocation);
|
||||
if (!points.empty())
|
||||
activePoints.push_back(points.front());
|
||||
}
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
|
||||
target->setTarget(activeDestinations.front(), activePoints.front());
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetBossTarget(TravelTarget* target)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
//Find boss mobs.
|
||||
std::vector<TravelDestination*> TravelDestinations = sTravelMgr->getBossTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
//Pick one good point per destination.
|
||||
for (auto& activeTarget : activeDestinations)
|
||||
{
|
||||
std::vector<WorldPosition*> points = activeTarget->nextPoint(&botLocation);
|
||||
if (!points.empty())
|
||||
activePoints.push_back(points.front());
|
||||
}
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
|
||||
target->setTarget(activeDestinations.front(), activePoints.front());
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetExploreTarget(TravelTarget* target)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
//Find quest givers.
|
||||
std::vector<TravelDestination*> TravelDestinations = sTravelMgr->getExploreTravelDestinations(bot, true, true);
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
/*
|
||||
//Pick one good point per destination.
|
||||
for (auto& activeTarget : activeDestinations)
|
||||
{
|
||||
//271 south shore
|
||||
//35 booty bay
|
||||
//380 The Barrens The Crossroads
|
||||
if(((ExploreTravelDestination * )activeTarget)->getAreaId() == 380)
|
||||
{
|
||||
activePoints.push_back(activeTarget->getPoints(true)[0]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (activePoints.empty())
|
||||
{
|
||||
TravelDestinations = sTravelMgr->getExploreTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
for (auto& activeTarget : activeDestinations)
|
||||
{
|
||||
std::vector<WorldPosition*> points = activeTarget->nextPoint(&botLocation);
|
||||
if (!points.empty())
|
||||
{
|
||||
activePoints.push_back(points.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
|
||||
target->setTarget(activeDestinations.front(), activePoints.front());
|
||||
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
char* strstri(char const* haystack, char const* needle);
|
||||
|
||||
bool ChooseTravelTargetAction::SetNpcFlagTarget(TravelTarget* target, std::vector<NPCFlags> flags, std::string const name, std::vector<uint32> items)
|
||||
{
|
||||
WorldPosition botPos(bot);
|
||||
|
||||
std::vector<TravelDestination*> dests;
|
||||
|
||||
for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (!d->getEntry())
|
||||
continue;
|
||||
|
||||
CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(d->getEntry());
|
||||
if (!cInfo)
|
||||
continue;
|
||||
|
||||
bool foundFlag = false;
|
||||
for (auto flag : flags)
|
||||
if (cInfo->npcflag & flag)
|
||||
{
|
||||
foundFlag = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundFlag)
|
||||
continue;
|
||||
|
||||
if (!name.empty() && !strstri(cInfo->Name.c_str(), name.c_str()) && !strstri(cInfo->SubName.c_str(), name.c_str()))
|
||||
continue;
|
||||
|
||||
if (!items.empty())
|
||||
{
|
||||
bool foundItem = false;
|
||||
VendorItemData const* vItems = sObjectMgr->GetNpcVendorItemList(d->getEntry());
|
||||
if (vItems)
|
||||
{
|
||||
for (auto item : items)
|
||||
{
|
||||
for (auto vitem : vItems->m_items)
|
||||
{
|
||||
if (vitem->item == item)
|
||||
{
|
||||
foundItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundItem)
|
||||
continue;
|
||||
}
|
||||
|
||||
FactionTemplateEntry const* factionEntry = sFactionTemplateStore.LookupEntry(cInfo->faction);
|
||||
ReputationRank reaction = Unit::GetFactionReactionTo(botAI->GetBot()->GetFactionTemplateEntry(), factionEntry);
|
||||
|
||||
if (reaction < REP_NEUTRAL)
|
||||
continue;
|
||||
|
||||
dests.push_back(d);
|
||||
}
|
||||
|
||||
if (!dests.empty())
|
||||
{
|
||||
TravelDestination* dest = *std::min_element(dests.begin(), dests.end(), [botPos](TravelDestination* i, TravelDestination* j)
|
||||
{
|
||||
return i->distanceTo(const_cast<WorldPosition*>(&botPos)) < j->distanceTo(const_cast<WorldPosition*>(&botPos));
|
||||
});
|
||||
|
||||
std::vector<WorldPosition*> points = dest->nextPoint(const_cast<WorldPosition*>(&botPos), true);
|
||||
if (points.empty())
|
||||
return false;
|
||||
|
||||
target->setTarget(dest, points.front());
|
||||
target->setForced(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<TravelDestination*> TravelMgr::getBossTravelDestinations(Player* bot, bool ignoreFull, bool ignoreInactive, float maxDistance)
|
||||
{
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
std::vector<TravelDestination*> retTravelLocations;
|
||||
|
||||
for (auto& dest : bossMobs)
|
||||
{
|
||||
if (!ignoreInactive && !dest->isActive(bot))
|
||||
continue;
|
||||
|
||||
if (dest->isFull(ignoreFull))
|
||||
continue;
|
||||
|
||||
if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance)
|
||||
continue;
|
||||
|
||||
retTravelLocations.push_back(dest);
|
||||
}
|
||||
|
||||
return retTravelLocations;
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetNullTarget(TravelTarget* target)
|
||||
{
|
||||
target->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string const s, char delim);
|
||||
char* strstri(char const* haystack, char const* needle);
|
||||
|
||||
TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name)
|
||||
{
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
|
||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
||||
|
||||
std::vector<TravelDestination*> dests;
|
||||
|
||||
//Zones
|
||||
for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
|
||||
//Npcs
|
||||
for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
|
||||
//Mobs
|
||||
for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
|
||||
//Bosses
|
||||
for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
|
||||
WorldPosition botPos(bot);
|
||||
|
||||
if (dests.empty())
|
||||
return nullptr;
|
||||
|
||||
TravelDestination* dest = *std::min_element(dests.begin(), dests.end(), [botPos](TravelDestination* i, TravelDestination* j)
|
||||
{
|
||||
return i->distanceTo(const_cast<WorldPosition*>(&botPos)) < j->distanceTo(const_cast<WorldPosition*>(&botPos));
|
||||
});
|
||||
|
||||
return dest;
|
||||
};
|
||||
|
||||
bool ChooseTravelTargetAction::isUseful()
|
||||
{
|
||||
if (!botAI->AllowActivity(TRAVEL_ACTIVITY))
|
||||
return false;
|
||||
|
||||
return !context->GetValue<TravelTarget*>("travel target")->Get()->isActive() && !context->GetValue<LootObject>("loot target")->Get().IsLootPossible(bot) && !bot->IsInCombat();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::needForQuest(Unit* target)
|
||||
{
|
||||
bool justCheck = (bot->GetGUID() == target->GetGUID());
|
||||
|
||||
QuestStatusMap& questMap = bot->getQuestStatusMap();
|
||||
for (auto& quest : questMap)
|
||||
{
|
||||
Quest const* questTemplate = sObjectMgr->GetQuestTemplate(quest.first);
|
||||
if (!questTemplate)
|
||||
continue;
|
||||
|
||||
uint32 questId = questTemplate->GetQuestId();
|
||||
|
||||
if (!questId)
|
||||
continue;
|
||||
|
||||
QuestStatus status = bot->GetQuestStatus(questId);
|
||||
|
||||
if ((status == QUEST_STATUS_COMPLETE && !bot->GetQuestRewardStatus(questId)))
|
||||
{
|
||||
if (!justCheck && !target->hasInvolvedQuest(questId))
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (status == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
QuestStatusData questStatus = quest.second;
|
||||
|
||||
if (questTemplate->GetQuestLevel() > bot->getLevel())
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
|
||||
{
|
||||
int32 entry = questTemplate->RequiredNpcOrGo[j];
|
||||
|
||||
if (entry && entry > 0)
|
||||
{
|
||||
int required = questTemplate->RequiredNpcOrGoCount[j];
|
||||
int available = questStatus.CreatureOrGOCount[j];
|
||||
|
||||
if(required && available < required && (target->GetEntry() == entry || justCheck))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (justCheck)
|
||||
{
|
||||
int32 itemId = questTemplate->RequiredItemId[j];
|
||||
|
||||
if (itemId && itemId > 0)
|
||||
{
|
||||
int required = questTemplate->RequiredItemCount[j];
|
||||
int available = questStatus.ItemCount[j];
|
||||
|
||||
if (required && available < required)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!justCheck)
|
||||
{
|
||||
if (CreatureTemplate const* data = sObjectMgr->GetCreatureTemplate(target->GetEntry()))
|
||||
{
|
||||
if (uint32 lootId = data->lootid)
|
||||
{
|
||||
if (LootTemplates_Creature.HaveQuestLootForPlayer(lootId, bot))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::needItemForQuest(uint32 itemId, const Quest* questTemplate, const QuestStatusData* questStatus)
|
||||
{
|
||||
for (uint32 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
|
||||
{
|
||||
if (questTemplate->RequiredItemId[i] != itemId)
|
||||
continue;
|
||||
|
||||
uint32 required = questTemplate->RequiredItemCount[i];
|
||||
uint32 available = questStatus->ItemCount[i];
|
||||
|
||||
if (!required)
|
||||
continue;
|
||||
|
||||
return available < required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
50
src/strategy/actions/ChooseTravelTargetAction.h
Normal file
50
src/strategy/actions/ChooseTravelTargetAction.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CHOOSETRAVELTARGETACTION_H
|
||||
#define _PLAYERBOT_CHOOSETRAVELTARGETACTION_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
#include "TravelMgr.h"
|
||||
|
||||
class Quest;
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
|
||||
struct QuestStatusData;
|
||||
|
||||
class ChooseTravelTargetAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
ChooseTravelTargetAction(PlayerbotAI* botAI, std::string const name = "choose travel target") : MovementAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
static TravelDestination* FindDestination(Player* bot, std::string const name);
|
||||
|
||||
protected:
|
||||
void getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget);
|
||||
void setNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget);
|
||||
void ReportTravelTarget(TravelTarget* newTarget, TravelTarget* oldTarget);
|
||||
|
||||
bool getBestDestination(std::vector<TravelDestination*>* activeDestinations, std::vector<WorldPosition*>* activePoints);
|
||||
|
||||
bool SetGroupTarget(TravelTarget* target);
|
||||
bool SetCurrentTarget(TravelTarget* target, TravelTarget* oldTarget);
|
||||
bool SetQuestTarget(TravelTarget* target, bool onlyCompleted = false);
|
||||
bool SetNewQuestTarget(TravelTarget* target);
|
||||
bool SetRpgTarget(TravelTarget* target);
|
||||
bool SetGrindTarget(TravelTarget* target);
|
||||
bool SetBossTarget(TravelTarget* target);
|
||||
bool SetExploreTarget(TravelTarget* target);
|
||||
bool SetNpcFlagTarget(TravelTarget* target, std::vector<NPCFlags> flags, std::string const name = "", std::vector<uint32> items = { });
|
||||
bool SetNullTarget(TravelTarget* target);
|
||||
|
||||
private:
|
||||
virtual bool needForQuest(Unit* target);
|
||||
virtual bool needItemForQuest(uint32 itemId, Quest const* questTemplate, QuestStatusData const* questStatus);
|
||||
};
|
||||
|
||||
#endif
|
||||
47
src/strategy/actions/CombatActions.cpp
Normal file
47
src/strategy/actions/CombatActions.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CombatActions.h"
|
||||
#include "Event.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
bool SwitchToMeleeAction::Execute(Event event)
|
||||
{
|
||||
//botAI->TellMasterNoFacing("Switching to melee!");
|
||||
return ChangeCombatStrategyAction::Execute(event);
|
||||
}
|
||||
|
||||
bool SwitchToMeleeAction::isUseful()
|
||||
{
|
||||
if (bot->getClass() == CLASS_HUNTER)
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
time_t lastFlee = AI_VALUE(LastMovement&, "last movement").lastFlee;
|
||||
return botAI->HasStrategy("ranged", BOT_STATE_COMBAT) && ((bot->IsInCombat() && target && (target->GetVictim() == bot && (!bot->GetGroup() || lastFlee) &&
|
||||
sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) || (!bot->IsInCombat()));
|
||||
}
|
||||
|
||||
return botAI->HasStrategy("ranged", BOT_STATE_COMBAT);
|
||||
}
|
||||
|
||||
bool SwitchToRangedAction::Execute(Event event)
|
||||
{
|
||||
//botAI->TellMasterNoFacing("Switching to ranged!");
|
||||
return ChangeCombatStrategyAction::Execute(event);
|
||||
}
|
||||
|
||||
bool SwitchToRangedAction::isUseful()
|
||||
{
|
||||
if (bot->getClass() == CLASS_HUNTER)
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
bool hasAmmo = AI_VALUE2(uint32, "item count", "ammo");
|
||||
return botAI->HasStrategy("close", BOT_STATE_COMBAT) && hasAmmo && ((bot->IsInCombat() && target && ((target->GetVictim() != bot || target->GetTarget() != bot->GetGUID()) ||
|
||||
sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) || (!bot->IsInCombat()));
|
||||
}
|
||||
|
||||
return botAI->HasStrategy("close", BOT_STATE_COMBAT);
|
||||
}
|
||||
30
src/strategy/actions/CombatActions.h
Normal file
30
src/strategy/actions/CombatActions.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_COMBATACTIONS_H
|
||||
#define _PLAYERBOT_COMBATACTIONS_H
|
||||
|
||||
#include "ChangeStrategyAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class SwitchToMeleeAction : public ChangeCombatStrategyAction
|
||||
{
|
||||
public:
|
||||
SwitchToMeleeAction(PlayerbotAI* botAI) : ChangeCombatStrategyAction(botAI, "-ranged,+close") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class SwitchToRangedAction : public ChangeCombatStrategyAction
|
||||
{
|
||||
public:
|
||||
SwitchToRangedAction(PlayerbotAI* botAI) : ChangeCombatStrategyAction(botAI, "-close,+ranged") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
141
src/strategy/actions/CustomStrategyEditAction.cpp
Normal file
141
src/strategy/actions/CustomStrategyEditAction.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CustomStrategyEditAction.h"
|
||||
#include "CustomStrategy.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool CustomStrategyEditAction::Execute(Event event)
|
||||
{
|
||||
std::string text = event.getParam();
|
||||
uint32 pos = text.find(" ");
|
||||
if (pos == std::string::npos)
|
||||
return PrintHelp();
|
||||
|
||||
std::string const name = text.substr(0, pos);
|
||||
text = text.substr(pos + 1);
|
||||
|
||||
pos = text.find(" ");
|
||||
if (pos == std::string::npos)
|
||||
pos = text.size();
|
||||
|
||||
std::string const idx = text.substr(0, pos);
|
||||
text = pos >= text.size() ? "" : text.substr(pos + 1);
|
||||
|
||||
return idx == "?" ? Print(name) : Edit(name, atoi(idx.c_str()), text);
|
||||
}
|
||||
|
||||
bool CustomStrategyEditAction::PrintHelp()
|
||||
{
|
||||
botAI->TellMaster("=== Custom strategies ===");
|
||||
|
||||
uint32 owner = botAI->GetBot()->GetGUID().GetCounter();
|
||||
|
||||
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER);
|
||||
stmt->SetData(0, owner);
|
||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
std::string const name = fields[0].Get<std::string>();
|
||||
botAI->TellMaster(name);
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
|
||||
botAI->TellMaster("Usage: cs <name> <idx> <command>");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CustomStrategyEditAction::Print(std::string const name)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "=== " << name << " ===";
|
||||
botAI->TellMaster(out.str());
|
||||
|
||||
uint32 owner = botAI->GetBot()->GetGUID().GetCounter();
|
||||
|
||||
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER_AND_NAME);
|
||||
stmt->SetData(0, owner);
|
||||
stmt->SetData(1, name);
|
||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 idx = fields[0].Get<uint32>();
|
||||
std::string const action = fields[1].Get<std::string>();
|
||||
|
||||
PrintActionLine(idx, action);
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CustomStrategyEditAction::Edit(std::string const name, uint32 idx, std::string const command)
|
||||
{
|
||||
uint32 owner = botAI->GetBot()->GetGUID().GetCounter();
|
||||
|
||||
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER_AND_NAME_AND_IDX);
|
||||
stmt->SetData(0, owner);
|
||||
stmt->SetData(1, name);
|
||||
stmt->SetData(2, idx);
|
||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
||||
{
|
||||
if (command.empty())
|
||||
{
|
||||
stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_CUSTOM_STRATEGY);
|
||||
stmt->SetData(0, name);
|
||||
stmt->SetData(1, owner);
|
||||
stmt->SetData(2, idx);
|
||||
PlayerbotsDatabase.Execute(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_UPD_CUSTOM_STRATEGY);
|
||||
stmt->SetData(0, command);
|
||||
stmt->SetData(1, name);
|
||||
stmt->SetData(2, owner);
|
||||
stmt->SetData(3, idx);
|
||||
PlayerbotsDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_INS_CUSTOM_STRATEGY);
|
||||
stmt->SetData(0, name);
|
||||
stmt->SetData(1, owner);
|
||||
stmt->SetData(2, idx);
|
||||
stmt->SetData(3, command);
|
||||
PlayerbotsDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
PrintActionLine(idx, command);
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "custom::" << name;
|
||||
|
||||
if (Strategy* strategy = botAI->GetAiObjectContext()->GetStrategy(ss.str()))
|
||||
{
|
||||
if (CustomStrategy* cs = dynamic_cast<CustomStrategy*>(strategy))
|
||||
{
|
||||
cs->Reset();
|
||||
botAI->ReInitCurrentEngine();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CustomStrategyEditAction::PrintActionLine(uint32 idx, std::string const command)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "#" << idx << " " << command;
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
26
src/strategy/actions/CustomStrategyEditAction.h
Normal file
26
src/strategy/actions/CustomStrategyEditAction.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CUSTOMSTRATEGYEDITACTION_H
|
||||
#define _PLAYERBOT_CUSTOMSTRATEGYEDITACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class CustomStrategyEditAction : public Action
|
||||
{
|
||||
public:
|
||||
CustomStrategyEditAction(PlayerbotAI* botAI) : Action(botAI, "cs") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool PrintHelp();
|
||||
bool PrintActionLine(uint32 idx, std::string const command);
|
||||
bool Print(std::string const name);
|
||||
bool Edit(std::string const name, uint32 idx, std::string const command);
|
||||
};
|
||||
|
||||
#endif
|
||||
1018
src/strategy/actions/DebugAction.cpp
Normal file
1018
src/strategy/actions/DebugAction.cpp
Normal file
File diff suppressed because it is too large
Load Diff
26
src/strategy/actions/DebugAction.h
Normal file
26
src/strategy/actions/DebugAction.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_DEBUGACTION_H
|
||||
#define _PLAYERBOT_DEBUGACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "TravelMgr.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
|
||||
class DebugAction : public Action
|
||||
{
|
||||
public:
|
||||
DebugAction(PlayerbotAI* botAI) : Action(botAI, "Debug") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
void FakeSpell(uint32 spellId, Unit* truecaster, Unit* caster, ObjectGuid target = ObjectGuid::Empty, GuidVector otherTargets = {}, GuidVector missTargets = {}, WorldPosition source = WorldPosition(), WorldPosition dest = WorldPosition(), bool forceDest = false);
|
||||
void addAura(uint32 spellId, Unit* target);
|
||||
};
|
||||
|
||||
#endif
|
||||
21
src/strategy/actions/DelayAction.cpp
Normal file
21
src/strategy/actions/DelayAction.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "DelayAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool DelayAction::Execute(Event event)
|
||||
{
|
||||
uint32 delay = sPlayerbotAIConfig->passiveDelay + sPlayerbotAIConfig->globalCoolDown;
|
||||
|
||||
botAI->SetNextCheckDelay(delay);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DelayAction::isUseful()
|
||||
{
|
||||
return !botAI->AllowActivity(ALL_ACTIVITY);
|
||||
}
|
||||
21
src/strategy/actions/DelayAction.h
Normal file
21
src/strategy/actions/DelayAction.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_DELAYACTION_H
|
||||
#define _PLAYERBOT_DELAYACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class DelayAction : public Action
|
||||
{
|
||||
public:
|
||||
DelayAction(PlayerbotAI* botAI) : Action(botAI, "delay") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
82
src/strategy/actions/DestroyItemAction.cpp
Normal file
82
src/strategy/actions/DestroyItemAction.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "DestroyItemAction.h"
|
||||
#include "Event.h"
|
||||
#include "ItemCountValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool DestroyItemAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
ItemIds ids = chat->parseItems(text);
|
||||
|
||||
for (ItemIds::iterator i = ids.begin(); i != ids.end(); i++)
|
||||
{
|
||||
FindItemByIdVisitor visitor(*i);
|
||||
DestroyItem(&visitor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DestroyItemAction::DestroyItem(FindItemVisitor* visitor)
|
||||
{
|
||||
IterateItems(visitor);
|
||||
std::vector<Item*> items = visitor->GetResult();
|
||||
for (Item* item : items)
|
||||
{
|
||||
bot->DestroyItem(item->GetBagSlot(),item->GetSlot(), true);
|
||||
|
||||
std::ostringstream out;
|
||||
out << chat->FormatItem(item->GetTemplate()) << " destroyed";
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
}
|
||||
|
||||
bool SmartDestroyItemAction::isUseful()
|
||||
{
|
||||
return !botAI->HasActivePlayerMaster();
|
||||
}
|
||||
|
||||
bool SmartDestroyItemAction::Execute(Event event)
|
||||
{
|
||||
uint8 bagSpace = AI_VALUE(uint8, "bag space");
|
||||
|
||||
if (bagSpace < 90)
|
||||
return false;
|
||||
|
||||
std::vector<uint32> bestToDestroy = { ITEM_USAGE_NONE }; //First destroy anything useless.
|
||||
|
||||
if (!AI_VALUE(bool, "can sell") && AI_VALUE(bool, "should get money")) // We need money so quest items are less important since they can't directly be sold.
|
||||
bestToDestroy.push_back(ITEM_USAGE_QUEST);
|
||||
else // We don't need money so destroy the cheapest stuff.
|
||||
{
|
||||
bestToDestroy.push_back(ITEM_USAGE_VENDOR);
|
||||
bestToDestroy.push_back(ITEM_USAGE_AH);
|
||||
}
|
||||
|
||||
// If we still need room
|
||||
bestToDestroy.push_back(ITEM_USAGE_SKILL); // Items that might help tradeskill are more important than above but still expenable.
|
||||
bestToDestroy.push_back(ITEM_USAGE_USE); // These are more likely to be usefull 'soon' but still expenable.
|
||||
|
||||
for (auto& usage : bestToDestroy)
|
||||
{
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "usage " + std::to_string(usage));
|
||||
std::reverse(items.begin(), items.end());
|
||||
|
||||
for (auto& item : items)
|
||||
{
|
||||
FindItemByIdVisitor visitor(item->GetTemplate()->ItemId);
|
||||
DestroyItem(&visitor);
|
||||
|
||||
bagSpace = AI_VALUE(uint8, "bag space");
|
||||
|
||||
if (bagSpace < 90)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
33
src/strategy/actions/DestroyItemAction.h
Normal file
33
src/strategy/actions/DestroyItemAction.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_DESTROYITEMACTION_H
|
||||
#define _PLAYERBOT_DESTROYITEMACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class FindItemVisitor;
|
||||
class PlayerbotAI;
|
||||
|
||||
class DestroyItemAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
DestroyItemAction(PlayerbotAI* botAI, std::string const name = "destroy") : InventoryAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
void DestroyItem(FindItemVisitor* visitor);
|
||||
};
|
||||
|
||||
class SmartDestroyItemAction : public DestroyItemAction
|
||||
{
|
||||
public:
|
||||
SmartDestroyItemAction(PlayerbotAI* botAI) : DestroyItemAction(botAI, "smart destroy") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
183
src/strategy/actions/DropQuestAction.cpp
Normal file
183
src/strategy/actions/DropQuestAction.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "DropQuestAction.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool DropQuestAction::Execute(Event event)
|
||||
{
|
||||
std::string const link = event.getParam();
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
PlayerbotChatHandler handler(master);
|
||||
uint32 entry = handler.extractQuestId(link);
|
||||
|
||||
// remove all quest entries for 'entry' from quest log
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 logQuest = bot->GetQuestSlotQuestId(slot);
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(logQuest);
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
if (logQuest == entry || link.find(quest->GetTitle()) != std::string::npos)
|
||||
{
|
||||
bot->SetQuestSlot(slot, 0);
|
||||
|
||||
// we ignore unequippable quest items in this case, its' still be equipped
|
||||
bot->TakeQuestSourceItem(logQuest, false);
|
||||
entry = logQuest;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
return false;
|
||||
|
||||
bot->RemoveRewardedQuest(entry);
|
||||
bot->RemoveActiveQuest(entry, false);
|
||||
|
||||
botAI->TellMaster("Quest removed");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CleanQuestLogAction::Execute(Event event)
|
||||
{
|
||||
std::string const link = event.getParam();
|
||||
if (botAI->HasActivePlayerMaster())
|
||||
return false;
|
||||
|
||||
uint8 totalQuests = 0;
|
||||
|
||||
DropQuestType(totalQuests); //Count the total quests
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 6)
|
||||
return true;
|
||||
|
||||
if (AI_VALUE(bool, "can fight equal")) // Only drop gray quests when able to fight proper lvl quests.
|
||||
{
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6); // Drop gray/red quests.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true); // Drop gray/red quests with progress.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true, true); // Drop gray/red completed quests.
|
||||
}
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 4)
|
||||
return true;
|
||||
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 4, true); //Drop quests without progress.
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 2)
|
||||
return true;
|
||||
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 2, true, true); //Drop quests with progress.
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 0)
|
||||
return true;
|
||||
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 1, true, true, true); //Drop completed quests.
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isGreen, bool hasProgress, bool isComplete)
|
||||
{
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||
if (!questId)
|
||||
continue;
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
if (quest->GetRequiredClasses() && (quest->GetRewSpellCast() || quest->GetRewSpell())) //Do not drop class specific quests that learn spells.
|
||||
continue;
|
||||
|
||||
if (quest->GetRequiredClasses() && (quest->GetRewSpellCast() || quest->GetRewSpell())) // Do not drop class specific quests that learn spells.
|
||||
continue;
|
||||
|
||||
if (wantNum == 100)
|
||||
numQuest++;
|
||||
|
||||
int32 lowLevelDiff = sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF);
|
||||
if (lowLevelDiff < 0 || bot->getLevel() <= bot->GetQuestLevel(quest) + uint32(lowLevelDiff)) // Quest is not gray
|
||||
{
|
||||
if (bot->getLevel() + 5 > bot->GetQuestLevel(quest)) // Quest is not red
|
||||
if (!isGreen)
|
||||
continue;
|
||||
}
|
||||
else // Quest is gray
|
||||
{
|
||||
if (isGreen)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HasProgress(bot, quest) && !hasProgress)
|
||||
continue;
|
||||
|
||||
if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE && !isComplete)
|
||||
continue;
|
||||
|
||||
if (numQuest <= wantNum && bot->GetQuestStatus(questId) != QUEST_STATUS_FAILED) // Always drop failed quests
|
||||
continue;
|
||||
|
||||
//Drop quest.
|
||||
bot->SetQuestSlot(slot, 0);
|
||||
|
||||
//We ignore unequippable quest items in this case, its' still be equipped
|
||||
bot->TakeQuestSourceItem(questId, false);
|
||||
|
||||
bot->SetQuestStatus(questId, QUEST_STATUS_NONE);
|
||||
bot->RemoveRewardedQuest(questId);
|
||||
|
||||
numQuest--;
|
||||
|
||||
botAI->TellMaster("Quest removed" + chat->FormatQuest(quest));
|
||||
}
|
||||
}
|
||||
|
||||
bool CleanQuestLogAction::HasProgress(Player* bot, Quest const* quest)
|
||||
{
|
||||
uint32 questId = quest->GetQuestId();
|
||||
|
||||
if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
|
||||
return true;
|
||||
|
||||
QuestStatusData questStatus = bot->getQuestStatusMap()[questId];
|
||||
|
||||
for (uint32 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
|
||||
{
|
||||
if (!quest->ObjectiveText[i].empty())
|
||||
return true;
|
||||
|
||||
if (quest->RequiredItemId[i])
|
||||
{
|
||||
int required = quest->RequiredItemCount[i];
|
||||
int available = questStatus.ItemCount[i];
|
||||
if (available > 0 && required > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (quest->RequiredNpcOrGo[i])
|
||||
{
|
||||
int required = quest->RequiredNpcOrGoCount[i];
|
||||
int available = questStatus.CreatureOrGOCount[i];
|
||||
|
||||
if (available > 0 && required > 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
34
src/strategy/actions/DropQuestAction.h
Normal file
34
src/strategy/actions/DropQuestAction.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_DROPQUESTACTION_H
|
||||
#define _PLAYERBOT_DROPQUESTACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class Player;
|
||||
class PlayerbotAI;
|
||||
class Quest;
|
||||
|
||||
class DropQuestAction : public Action
|
||||
{
|
||||
public:
|
||||
DropQuestAction(PlayerbotAI* botAI) : Action(botAI, "drop quest") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class CleanQuestLogAction : public Action
|
||||
{
|
||||
public:
|
||||
CleanQuestLogAction(PlayerbotAI* botAI) : Action(botAI, "clean quest log") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
void DropQuestType(uint8& numQuest, uint8 wantNum = 100, bool isGreen = false, bool hasProgress = false, bool isComplete = false);
|
||||
|
||||
static bool HasProgress(Player* bot, Quest const* quest);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
1433
src/strategy/actions/EmoteAction.cpp
Normal file
1433
src/strategy/actions/EmoteAction.cpp
Normal file
File diff suppressed because it is too large
Load Diff
53
src/strategy/actions/EmoteAction.h
Normal file
53
src/strategy/actions/EmoteAction.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_EMOTEACTION_H
|
||||
#define _PLAYERBOT_EMOTEACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "NamedObjectContext.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
class Player;
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
|
||||
enum TextEmotes : uint32;
|
||||
|
||||
class EmoteActionBase : public Action
|
||||
{
|
||||
public:
|
||||
EmoteActionBase(PlayerbotAI* botAI, std::string const name);
|
||||
|
||||
static uint32 GetNumberOfEmoteVariants(TextEmotes emote, uint8 race, uint8 gender);
|
||||
|
||||
protected:
|
||||
bool Emote(Unit* target, uint32 type, bool textEmote = false);
|
||||
bool ReceiveEmote(Player* source, uint32 emote, bool verbal = false);
|
||||
Unit* GetTarget();
|
||||
void InitEmotes();
|
||||
static std::map<std::string, uint32> emotes;
|
||||
static std::map<std::string, uint32> textEmotes;
|
||||
};
|
||||
|
||||
class EmoteAction : public EmoteActionBase, public Qualified
|
||||
{
|
||||
public:
|
||||
EmoteAction(PlayerbotAI* botAI);
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class TalkAction : public EmoteActionBase
|
||||
{
|
||||
public:
|
||||
TalkAction(PlayerbotAI* botAI) : EmoteActionBase(botAI, "talk") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
static uint32 GetRandomEmote(Unit* unit, bool textEmote = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
131
src/strategy/actions/EquipAction.cpp
Normal file
131
src/strategy/actions/EquipAction.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "EquipAction.h"
|
||||
#include "Event.h"
|
||||
#include "ItemCountValue.h"
|
||||
#include "ItemUsageValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool EquipAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
ItemIds ids = chat->parseItems(text);
|
||||
EquipItems(ids);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EquipAction::EquipItems(ItemIds ids)
|
||||
{
|
||||
for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++)
|
||||
{
|
||||
FindItemByIdVisitor visitor(*i);
|
||||
EquipItem(&visitor);
|
||||
}
|
||||
}
|
||||
|
||||
//Return bagslot with smalest bag.
|
||||
uint8 EquipAction::GetSmallestBagSlot()
|
||||
{
|
||||
int8 curBag = 0;
|
||||
uint32 curSlots = 0;
|
||||
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
||||
{
|
||||
const Bag* const pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag);
|
||||
if (pBag)
|
||||
{
|
||||
if (curBag > 0 && curSlots < pBag->GetBagSize())
|
||||
continue;
|
||||
|
||||
curBag = bag;
|
||||
curSlots = pBag->GetBagSize();
|
||||
}
|
||||
else
|
||||
return bag;
|
||||
}
|
||||
|
||||
return curBag;
|
||||
}
|
||||
|
||||
void EquipAction::EquipItem(FindItemVisitor* visitor)
|
||||
{
|
||||
IterateItems(visitor);
|
||||
std::vector<Item*> items = visitor->GetResult();
|
||||
if (!items.empty())
|
||||
EquipItem(*items.begin());
|
||||
}
|
||||
|
||||
void EquipAction::EquipItem(Item* item)
|
||||
{
|
||||
uint8 bagIndex = item->GetBagSlot();
|
||||
uint8 slot = item->GetSlot();
|
||||
uint32 itemId = item->GetTemplate()->ItemId;
|
||||
|
||||
if (item->GetTemplate()->InventoryType == INVTYPE_AMMO)
|
||||
{
|
||||
bot->SetAmmo(itemId);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool equipedBag = false;
|
||||
if (item->GetTemplate()->Class == ITEM_CLASS_CONTAINER)
|
||||
{
|
||||
Bag* pBag = (Bag*)&item;
|
||||
uint8 newBagSlot = GetSmallestBagSlot();
|
||||
if (newBagSlot > 0)
|
||||
{
|
||||
uint16 src = ((bagIndex << 8) | slot);
|
||||
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | newBagSlot);
|
||||
bot->SwapItem(src, dst);
|
||||
equipedBag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!equipedBag)
|
||||
{
|
||||
WorldPacket packet(CMSG_AUTOEQUIP_ITEM, 2);
|
||||
packet << bagIndex << slot;
|
||||
bot->GetSession()->HandleAutoEquipItemOpcode(packet);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream out;
|
||||
out << "equipping " << chat->FormatItem(item->GetTemplate());
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
|
||||
bool EquipUpgradesAction::Execute(Event event)
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoEquipUpgradeLoot && !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
return false;
|
||||
|
||||
if (event.GetSource() == "trade status")
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
uint32 status;
|
||||
p >> status;
|
||||
|
||||
if (status != TRADE_STATUS_TRADE_ACCEPT)
|
||||
return false;
|
||||
}
|
||||
|
||||
ListItemsVisitor visitor;
|
||||
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
||||
|
||||
ItemIds items;
|
||||
for (std::map<uint32, uint32>::iterator i = visitor.items.begin(); i != visitor.items.end(); ++i)
|
||||
{
|
||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", i->first);
|
||||
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
|
||||
{
|
||||
LOG_INFO("playerbots", "Bot {} <{}> auto equips item {} ({})", bot->GetGUID().ToString().c_str(), bot->GetName().c_str(), i->first, usage == 1 ? "no item in slot" : usage == 2 ? "replace" : usage == 3 ? "wrong item but empty slot" : "");
|
||||
items.insert(i->first);
|
||||
}
|
||||
}
|
||||
|
||||
EquipItems(items);
|
||||
return true;
|
||||
}
|
||||
|
||||
37
src/strategy/actions/EquipAction.h
Normal file
37
src/strategy/actions/EquipAction.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_EQUIPACTION_H
|
||||
#define _PLAYERBOT_EQUIPACTION_H
|
||||
|
||||
#include "ChatHelper.h"
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class FindItemVisitor;
|
||||
class Item;
|
||||
class PlayerbotAI;
|
||||
|
||||
class EquipAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
EquipAction(PlayerbotAI* botAI, std::string const name = "equip") : InventoryAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
void EquipItems(ItemIds ids);
|
||||
|
||||
private:
|
||||
void EquipItem(FindItemVisitor* visitor);
|
||||
uint8 GetSmallestBagSlot();
|
||||
void EquipItem(Item* item);
|
||||
};
|
||||
|
||||
class EquipUpgradesAction : public EquipAction
|
||||
{
|
||||
public:
|
||||
EquipUpgradesAction(PlayerbotAI* botAI, std::string const name = "equip upgrades") : EquipAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
61
src/strategy/actions/FlagAction.cpp
Normal file
61
src/strategy/actions/FlagAction.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FlagAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool FlagAction::TellUsage()
|
||||
{
|
||||
botAI->TellError("Usage: flag cloak/helm/pvp on/set/off/clear/toggle/?");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlagAction::Execute(Event event)
|
||||
{
|
||||
std::string const cmd = event.getParam();
|
||||
std::vector<std::string> ss = split(cmd, ' ');
|
||||
if (ss.size() != 2)
|
||||
return TellUsage();
|
||||
|
||||
bool setFlag = (ss[1] == "set" || ss[1] == "on");
|
||||
bool clearFlag = (ss[1] == "clear" || ss[1] == "off");
|
||||
bool toggleFlag = (ss[1] == "toggle");
|
||||
if (ss[0] == "pvp")
|
||||
{
|
||||
if (setFlag)
|
||||
bot->SetPvP(true);
|
||||
else if (clearFlag)
|
||||
bot->SetPvP(false);
|
||||
else if (toggleFlag)
|
||||
bot->SetPvP(!bot->IsPvP());
|
||||
|
||||
std::ostringstream out;
|
||||
out << ss[0] << " flag is " << chat->FormatBoolean(bot->IsPvP());
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 playerFlags;
|
||||
if (ss[0] == "cloak")
|
||||
playerFlags = PLAYER_FLAGS_HIDE_CLOAK;
|
||||
|
||||
if (ss[0] == "helm")
|
||||
playerFlags = PLAYER_FLAGS_HIDE_HELM;
|
||||
|
||||
if (clearFlag)
|
||||
bot->SetFlag(PLAYER_FLAGS, playerFlags);
|
||||
else if (setFlag)
|
||||
bot->RemoveFlag(PLAYER_FLAGS, playerFlags);
|
||||
else if (toggleFlag && bot->HasFlag(PLAYER_FLAGS, playerFlags))
|
||||
bot->RemoveFlag(PLAYER_FLAGS, playerFlags);
|
||||
else if (toggleFlag && !bot->HasFlag(PLAYER_FLAGS, playerFlags))
|
||||
bot->SetFlag(PLAYER_FLAGS, playerFlags);
|
||||
|
||||
std::ostringstream out;
|
||||
out << ss[0] << " flag is " << chat->FormatBoolean(!bot->HasFlag(PLAYER_FLAGS, playerFlags));
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
23
src/strategy/actions/FlagAction.h
Normal file
23
src/strategy/actions/FlagAction.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_FLAGACTION_H
|
||||
#define _PLAYERBOT_FLAGACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class FlagAction : public Action
|
||||
{
|
||||
public:
|
||||
FlagAction(PlayerbotAI* botAI) : Action(botAI, "flag") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool TellUsage();
|
||||
};
|
||||
|
||||
#endif
|
||||
139
src/strategy/actions/FollowActions.cpp
Normal file
139
src/strategy/actions/FollowActions.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FollowActions.h"
|
||||
#include "Event.h"
|
||||
#include "Formations.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
bool FollowAction::Execute(Event event)
|
||||
{
|
||||
Formation* formation = AI_VALUE(Formation*, "formation");
|
||||
std::string const target = formation->GetTargetName();
|
||||
|
||||
bool moved = false;
|
||||
if (!target.empty())
|
||||
{
|
||||
moved = Follow(AI_VALUE(Unit*, target));
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldLocation loc = formation->GetLocation();
|
||||
if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1)
|
||||
return false;
|
||||
|
||||
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ());
|
||||
}
|
||||
|
||||
//if (moved)
|
||||
//botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
||||
|
||||
return moved;
|
||||
}
|
||||
|
||||
bool FollowAction::isUseful()
|
||||
{
|
||||
Formation* formation = AI_VALUE(Formation*, "formation");
|
||||
std::string const target = formation->GetTargetName();
|
||||
|
||||
Unit* fTarget = nullptr;
|
||||
if (!target.empty())
|
||||
fTarget = AI_VALUE(Unit*, target);
|
||||
else
|
||||
fTarget = AI_VALUE(Unit*, "master target");
|
||||
|
||||
if (fTarget)
|
||||
{
|
||||
if (fTarget->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||
return false;
|
||||
|
||||
if (!CanDeadFollow(fTarget))
|
||||
return false;
|
||||
|
||||
if (fTarget->GetGUID() == bot->GetGUID())
|
||||
return false;
|
||||
}
|
||||
|
||||
float distance = 0.f;
|
||||
if (!target.empty())
|
||||
{
|
||||
distance = AI_VALUE2(float, "distance", target);
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldLocation loc = formation->GetLocation();
|
||||
if (Formation::IsNullLocation(loc) || bot->GetMapId() != loc.GetMapId())
|
||||
return false;
|
||||
|
||||
distance = sServerFacade->GetDistance2d(bot, loc.GetPositionX(), loc.GetPositionY());
|
||||
}
|
||||
|
||||
return sServerFacade->IsDistanceGreaterThan(distance, formation->GetMaxDistance());
|
||||
}
|
||||
|
||||
bool FollowAction::CanDeadFollow(Unit* target)
|
||||
{
|
||||
// Move to corpse when dead and player is alive or not a ghost.
|
||||
if (!bot->IsAlive() && (target->IsAlive() || !target->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FleeToMasterAction::Execute(Event event)
|
||||
{
|
||||
Unit* fTarget = AI_VALUE(Unit*, "master target");
|
||||
bool canFollow = Follow(fTarget);
|
||||
if (!canFollow)
|
||||
{
|
||||
//botAI->SetNextCheckDelay(5000);
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldPosition targetPos(fTarget);
|
||||
WorldPosition bosPos(bot);
|
||||
float distance = bosPos.fDist(targetPos);
|
||||
|
||||
if (distance < sPlayerbotAIConfig->reactDistance * 3)
|
||||
{
|
||||
if (!urand(0, 3))
|
||||
botAI->TellMaster("I am close, wait for me!");
|
||||
}
|
||||
else if (distance < 1000)
|
||||
{
|
||||
if (!urand(0, 10))
|
||||
botAI->TellMaster("I heading to your position.");
|
||||
}
|
||||
else
|
||||
if (!urand(0,20))
|
||||
botAI->TellMaster("I am traveling to your position.");
|
||||
|
||||
botAI->SetNextCheckDelay(3000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FleeToMasterAction::isUseful()
|
||||
{
|
||||
if (!botAI->GetGroupMaster())
|
||||
return false;
|
||||
|
||||
if (botAI->GetGroupMaster() == bot)
|
||||
return false;
|
||||
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (target && botAI->GetGroupMaster()->GetTarget() == target->GetGUID())
|
||||
return false;
|
||||
|
||||
if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))
|
||||
return false;
|
||||
|
||||
Unit* fTarget = AI_VALUE(Unit*, "master target");
|
||||
|
||||
if (!CanDeadFollow(fTarget))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
31
src/strategy/actions/FollowActions.h
Normal file
31
src/strategy/actions/FollowActions.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_FOLLOWACTIONS_H
|
||||
#define _PLAYERBOT_FOLLOWACTIONS_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class FollowAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
FollowAction(PlayerbotAI* botAI, std::string const name = "follow") : MovementAction(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
bool CanDeadFollow(Unit* target);
|
||||
};
|
||||
|
||||
class FleeToMasterAction : public FollowAction
|
||||
{
|
||||
public:
|
||||
FleeToMasterAction(PlayerbotAI* botAI) : FollowAction(botAI, "flee to master") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
15
src/strategy/actions/GenericActions.cpp
Normal file
15
src/strategy/actions/GenericActions.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericActions.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool MeleeAction::isUseful()
|
||||
{
|
||||
// do not allow if can't attack from vehicle
|
||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
21
src/strategy/actions/GenericActions.h
Normal file
21
src/strategy/actions/GenericActions.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GENERICACTIONS_H
|
||||
#define _PLAYERBOT_GENERICACTIONS_H
|
||||
|
||||
#include "AttackAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class MeleeAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
MeleeAction(PlayerbotAI* botAI) : AttackAction(botAI, "melee") { }
|
||||
|
||||
std::string const GetTargetName() override { return "current target"; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
267
src/strategy/actions/GenericSpellActions.cpp
Normal file
267
src/strategy/actions/GenericSpellActions.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericSpellActions.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell) : Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell)
|
||||
{
|
||||
}
|
||||
|
||||
bool CastSpellAction::Execute(Event event)
|
||||
{
|
||||
if (spell == "conjure food" || spell == "conjure water")
|
||||
{
|
||||
//uint32 id = AI_VALUE2(uint32, "spell id", spell);
|
||||
//if (!id)
|
||||
// return false;
|
||||
|
||||
uint32 castId = 0;
|
||||
|
||||
for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr)
|
||||
{
|
||||
uint32 spellId = itr->first;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
std::string const namepart = spellInfo->SpellName[0];
|
||||
std::wstring wnamepart;
|
||||
if (!Utf8toWStr(namepart, wnamepart))
|
||||
return false;
|
||||
|
||||
wstrToLower(wnamepart);
|
||||
|
||||
if (!Utf8FitTo(spell, wnamepart))
|
||||
continue;
|
||||
|
||||
if (spellInfo->Effects[0].Effect != SPELL_EFFECT_CREATE_ITEM)
|
||||
continue;
|
||||
|
||||
uint32 itemId = spellInfo->Effects[0].ItemType;
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
if (bot->CanUseItem(proto) != EQUIP_ERR_OK)
|
||||
continue;
|
||||
|
||||
if (spellInfo->Id > castId)
|
||||
castId = spellInfo->Id;
|
||||
}
|
||||
|
||||
return botAI->CastSpell(castId, bot);
|
||||
}
|
||||
|
||||
return botAI->CastSpell(spell, GetTarget());
|
||||
}
|
||||
|
||||
bool CastSpellAction::isPossible()
|
||||
{
|
||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||
return false;
|
||||
|
||||
if (spell == "mount" && !bot->IsMounted() && !bot->IsInCombat())
|
||||
return true;
|
||||
|
||||
if (spell == "mount" && bot->IsInCombat())
|
||||
{
|
||||
bot->Dismount();
|
||||
return false;
|
||||
}
|
||||
|
||||
Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
||||
return botAI->CanCastSpell(spell, GetTarget());
|
||||
}
|
||||
|
||||
bool CastSpellAction::isUseful()
|
||||
{
|
||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||
return false;
|
||||
|
||||
if (spell == "mount" && !bot->IsMounted() && !bot->IsInCombat())
|
||||
return true;
|
||||
|
||||
if (spell == "mount" && bot->IsInCombat())
|
||||
{
|
||||
bot->Dismount();
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* spellTarget = GetTarget();
|
||||
if (!spellTarget)
|
||||
return false;
|
||||
|
||||
if (!spellTarget->IsInWorld() || spellTarget->GetMapId() != bot->GetMapId())
|
||||
return false;
|
||||
|
||||
float combatReach = bot->GetCombatReach() + spellTarget->GetCombatReach();
|
||||
if (!botAI->IsRanged(bot))
|
||||
combatReach += 4.0f / 3.0f;
|
||||
|
||||
return spellTarget && AI_VALUE2(bool, "spell cast useful", spell) && sServerFacade->GetDistance2d(bot, spellTarget) <= (range + combatReach);
|
||||
}
|
||||
|
||||
CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
|
||||
{
|
||||
range = ATTACK_DISTANCE;
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (target)
|
||||
range = bot->GetMeleeRange(target);
|
||||
|
||||
// range = target->GetCombinedCombatReach();
|
||||
}
|
||||
|
||||
bool CastAuraSpellAction::isUseful()
|
||||
{
|
||||
return GetTarget() && (GetTarget() != nullptr) && (GetTarget() != nullptr) && CastSpellAction::isUseful() && !botAI->HasAura(spell, GetTarget(), true);
|
||||
}
|
||||
|
||||
CastEnchantItemAction::CastEnchantItemAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
|
||||
{
|
||||
range = botAI->GetRange("spell");
|
||||
}
|
||||
|
||||
bool CastEnchantItemAction::isPossible()
|
||||
{
|
||||
if (!CastSpellAction::isPossible())
|
||||
return false;
|
||||
|
||||
uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
|
||||
return spellId && AI_VALUE2(Item*, "item for spell", spellId);
|
||||
}
|
||||
|
||||
CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount) : CastAuraSpellAction(botAI, spell), estAmount(estAmount)
|
||||
{
|
||||
range = botAI->GetRange("spell");
|
||||
}
|
||||
|
||||
bool CastHealingSpellAction::isUseful()
|
||||
{
|
||||
return CastAuraSpellAction::isUseful();
|
||||
}
|
||||
|
||||
bool CastAoeHealSpellAction::isUseful()
|
||||
{
|
||||
return CastSpellAction::isUseful();
|
||||
}
|
||||
|
||||
CastCureSpellAction::CastCureSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
|
||||
{
|
||||
range = botAI->GetRange("spell");
|
||||
}
|
||||
|
||||
Value<Unit*>* CurePartyMemberAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("party member to dispel", dispelType);
|
||||
}
|
||||
|
||||
Value<Unit*>* BuffOnPartyAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("party member without aura", spell);
|
||||
}
|
||||
|
||||
CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shoot")
|
||||
{
|
||||
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
|
||||
{
|
||||
spell = "shoot";
|
||||
|
||||
switch (pItem->GetTemplate()->SubClass)
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_GUN:
|
||||
spell += " gun";
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
spell += " bow";
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
|
||||
spell += " crossbow";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NextAction** CastSpellAction::getPrerequisites()
|
||||
{
|
||||
if (spell == "mount")
|
||||
return nullptr;
|
||||
|
||||
if (range > botAI->GetRange("spell"))
|
||||
return nullptr;
|
||||
else if (range > ATTACK_DISTANCE)
|
||||
return NextAction::merge(NextAction::array(0, new NextAction("reach spell"), nullptr), Action::getPrerequisites());
|
||||
else
|
||||
return NextAction::merge(NextAction::array(0, new NextAction("reach melee"), nullptr), Action::getPrerequisites());
|
||||
}
|
||||
|
||||
Value<Unit*>* CastDebuffSpellOnAttackerAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("attacker without aura", spell);
|
||||
}
|
||||
|
||||
CastBuffSpellAction::CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell) : CastAuraSpellAction(botAI, spell)
|
||||
{
|
||||
range = botAI->GetRange("spell");
|
||||
}
|
||||
|
||||
Value<Unit*>* CastSpellOnEnemyHealerAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("enemy healer target", spell);
|
||||
}
|
||||
|
||||
Value<Unit*>* CastSnareSpellAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("snare target", spell);
|
||||
}
|
||||
|
||||
Value<Unit*>* CastCrowdControlSpellAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("cc target", getName());
|
||||
}
|
||||
|
||||
bool CastCrowdControlSpellAction::Execute(Event event)
|
||||
{
|
||||
return botAI->CastSpell(getName(), GetTarget());
|
||||
}
|
||||
|
||||
bool CastCrowdControlSpellAction::isPossible()
|
||||
{
|
||||
return botAI->CanCastSpell(getName(), GetTarget());
|
||||
}
|
||||
|
||||
bool CastCrowdControlSpellAction::isUseful()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string const CastProtectSpellAction::GetTargetName()
|
||||
{
|
||||
return "party member to protect";
|
||||
}
|
||||
|
||||
bool CastProtectSpellAction::isUseful()
|
||||
{
|
||||
return GetTarget() && !botAI->HasAura(spell, GetTarget());
|
||||
}
|
||||
|
||||
bool CastVehicleSpellAction::isPossible()
|
||||
{
|
||||
uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", spell);
|
||||
return botAI->CanCastVehicleSpell(spellId, GetTarget());
|
||||
}
|
||||
|
||||
bool CastVehicleSpellAction::isUseful()
|
||||
{
|
||||
return botAI->IsInVehicle(false, true);
|
||||
}
|
||||
|
||||
bool CastVehicleSpellAction::Execute(Event event)
|
||||
{
|
||||
uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", spell);
|
||||
return botAI->CastVehicleSpell(spellId, GetTarget());
|
||||
}
|
||||
322
src/strategy/actions/GenericSpellActions.h
Normal file
322
src/strategy/actions/GenericSpellActions.h
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GENERICSPELLACTIONS_H
|
||||
#define _PLAYERBOT_GENERICSPELLACTIONS_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "Value.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
class WorldObject;
|
||||
|
||||
class CastSpellAction : public Action
|
||||
{
|
||||
public:
|
||||
CastSpellAction(PlayerbotAI* botAI, std::string const spell);
|
||||
|
||||
std::string const GetTargetName() override { return "current target"; };
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
bool isUseful() override;
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Single; }
|
||||
|
||||
NextAction** getPrerequisites() override;
|
||||
|
||||
protected:
|
||||
std::string spell;
|
||||
float range;
|
||||
};
|
||||
|
||||
class CastAuraSpellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastAuraSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) { }
|
||||
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastMeleeSpellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell);
|
||||
};
|
||||
|
||||
class CastDebuffSpellAction : public CastAuraSpellAction
|
||||
{
|
||||
public:
|
||||
CastDebuffSpellAction(PlayerbotAI* botAI, std::string const spell) : CastAuraSpellAction(botAI, spell) { }
|
||||
};
|
||||
|
||||
class CastDebuffSpellOnAttackerAction : public CastAuraSpellAction
|
||||
{
|
||||
public:
|
||||
CastDebuffSpellOnAttackerAction(PlayerbotAI* botAI, std::string const spell) : CastAuraSpellAction(botAI, spell) { }
|
||||
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
std::string const getName() override { return spell + " on attacker"; }
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
};
|
||||
|
||||
class CastBuffSpellAction : public CastAuraSpellAction
|
||||
{
|
||||
public:
|
||||
CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell);
|
||||
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
};
|
||||
|
||||
class CastEnchantItemAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastEnchantItemAction(PlayerbotAI* botAI, std::string const spell);
|
||||
|
||||
bool isPossible() override;
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
};
|
||||
|
||||
class CastHealingSpellAction : public CastAuraSpellAction
|
||||
{
|
||||
public:
|
||||
CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f);
|
||||
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
bool isUseful() override;
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
|
||||
protected:
|
||||
uint8 estAmount;
|
||||
};
|
||||
|
||||
class CastAoeHealSpellAction : public CastHealingSpellAction
|
||||
{
|
||||
public:
|
||||
CastAoeHealSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f) : CastHealingSpellAction(botAI, spell, estAmount) { }
|
||||
|
||||
std::string const GetTargetName() override { return "party member to heal"; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastCureSpellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastCureSpellAction(PlayerbotAI* botAI, std::string const spell);
|
||||
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
};
|
||||
|
||||
class PartyMemberActionNameSupport
|
||||
{
|
||||
public:
|
||||
PartyMemberActionNameSupport(std::string const spell)
|
||||
{
|
||||
name = std::string(spell + " on party");
|
||||
}
|
||||
|
||||
std::string const getName() { return name; }
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class HealPartyMemberAction : public CastHealingSpellAction, public PartyMemberActionNameSupport
|
||||
{
|
||||
public:
|
||||
HealPartyMemberAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f) :
|
||||
CastHealingSpellAction(botAI, spell, estAmount), PartyMemberActionNameSupport(spell) { }
|
||||
|
||||
std::string const GetTargetName() override { return "party member to heal"; }
|
||||
std::string const getName() override { return PartyMemberActionNameSupport::getName(); }
|
||||
};
|
||||
|
||||
class ResurrectPartyMemberAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
ResurrectPartyMemberAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) { }
|
||||
|
||||
std::string const GetTargetName() override { return "party member to resurrect"; }
|
||||
};
|
||||
|
||||
class CurePartyMemberAction : public CastSpellAction, public PartyMemberActionNameSupport
|
||||
{
|
||||
public:
|
||||
CurePartyMemberAction(PlayerbotAI* botAI, std::string const spell, uint32 dispelType) :
|
||||
CastSpellAction(botAI, spell), PartyMemberActionNameSupport(spell), dispelType(dispelType) { }
|
||||
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
std::string const getName() override { return PartyMemberActionNameSupport::getName(); }
|
||||
|
||||
protected:
|
||||
uint32 dispelType;
|
||||
};
|
||||
|
||||
class BuffOnPartyAction : public CastBuffSpellAction, public PartyMemberActionNameSupport
|
||||
{
|
||||
public:
|
||||
BuffOnPartyAction(PlayerbotAI* botAI, std::string const spell) :
|
||||
CastBuffSpellAction(botAI, spell), PartyMemberActionNameSupport(spell) { }
|
||||
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
std::string const getName() override { return PartyMemberActionNameSupport::getName(); }
|
||||
};
|
||||
|
||||
class CastShootAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastShootAction(PlayerbotAI* botAI);
|
||||
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::None; }
|
||||
};
|
||||
|
||||
class CastLifeBloodAction : public CastHealingSpellAction
|
||||
{
|
||||
public:
|
||||
CastLifeBloodAction(PlayerbotAI* botAI) : CastHealingSpellAction(botAI, "lifeblood") { }
|
||||
};
|
||||
|
||||
class CastGiftOfTheNaaruAction : public CastHealingSpellAction
|
||||
{
|
||||
public:
|
||||
CastGiftOfTheNaaruAction(PlayerbotAI* botAI) : CastHealingSpellAction(botAI, "gift of the naaru") { }
|
||||
};
|
||||
|
||||
class CastArcaneTorrentAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastArcaneTorrentAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "arcane torrent") { }
|
||||
};
|
||||
|
||||
class CastManaTapAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastManaTapAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mana tap") { }
|
||||
};
|
||||
|
||||
class CastWarStompAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastWarStompAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "war stomp") { }
|
||||
};
|
||||
|
||||
class CastSpellOnEnemyHealerAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastSpellOnEnemyHealerAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) { }
|
||||
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
std::string const getName() override { return spell + " on enemy healer"; }
|
||||
};
|
||||
|
||||
class CastSnareSpellAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastSnareSpellAction(PlayerbotAI* botAI, std::string const spell) : CastDebuffSpellAction(botAI, spell) { }
|
||||
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
std::string const getName() override { return spell + " on snare target"; }
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::None; }
|
||||
};
|
||||
|
||||
class CastCrowdControlSpellAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastCrowdControlSpellAction(PlayerbotAI* botAI, std::string const spell) : CastBuffSpellAction(botAI, spell) { }
|
||||
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
bool isUseful() override;
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::None; }
|
||||
};
|
||||
|
||||
class CastProtectSpellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastProtectSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) { }
|
||||
|
||||
std::string const GetTargetName() override;
|
||||
bool isUseful() override;
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::None; }
|
||||
};
|
||||
|
||||
class CastVehicleSpellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastVehicleSpellAction(PlayerbotAI* botAI, std::string const& spell) : CastSpellAction(botAI, spell)
|
||||
{
|
||||
range = 120.0f;
|
||||
}
|
||||
|
||||
std::string const GetTargetName() override { return "current target"; }
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
bool isPossible() override;
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::None; }
|
||||
|
||||
protected:
|
||||
WorldObject* spellTarget;
|
||||
};
|
||||
|
||||
class CastHurlBoulderAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastHurlBoulderAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "hurl boulder") { }
|
||||
};
|
||||
|
||||
class CastSteamRushAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastSteamRushAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "steam rush") { }
|
||||
};
|
||||
|
||||
class CastRamAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastRamAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "ram") { }
|
||||
};
|
||||
|
||||
class CastNapalmAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastNapalmAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "napalm") { }
|
||||
};
|
||||
|
||||
class CastFireCannonAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastFireCannonAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "fire cannon") { }
|
||||
};
|
||||
|
||||
class CastSteamBlastAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastSteamBlastAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "steam blast") { }
|
||||
};
|
||||
|
||||
class CastIncendiaryRocketAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastIncendiaryRocketAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "incendiary rocket") { }
|
||||
};
|
||||
|
||||
class CastRocketBlastAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastRocketBlastAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "rocket blast") { }
|
||||
};
|
||||
|
||||
class CastGlaiveThrowAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastGlaiveThrowAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "glaive throw") { }
|
||||
};
|
||||
|
||||
class CastBladeSalvoAction : public CastVehicleSpellAction
|
||||
{
|
||||
public:
|
||||
CastBladeSalvoAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "blade salvo") { }
|
||||
};
|
||||
|
||||
#endif
|
||||
78
src/strategy/actions/GiveItemAction.cpp
Normal file
78
src/strategy/actions/GiveItemAction.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GiveItemAction.h"
|
||||
#include "Event.h"
|
||||
#include "ItemCountValue.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
std::vector<std::string> split(std::string const s, char delim);
|
||||
|
||||
bool GiveItemAction::Execute(Event event)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
Player* receiver = dynamic_cast<Player*>(target);
|
||||
if (!receiver)
|
||||
return false;
|
||||
|
||||
PlayerbotAI* receiverAi = GET_PLAYERBOT_AI(receiver);
|
||||
if (!receiverAi)
|
||||
return false;
|
||||
|
||||
if (receiverAi->GetAiObjectContext()->GetValue<uint32>("item count", item)->Get())
|
||||
return true;
|
||||
|
||||
bool moved = false;
|
||||
std::vector<Item*> items = InventoryAction::parseItems(item, ITERATE_ITEMS_IN_BAGS);
|
||||
for (Item* item : items)
|
||||
{
|
||||
if (receiver->CanUseItem(item->GetTemplate()) != EQUIP_ERR_OK)
|
||||
continue;
|
||||
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = receiver->CanStoreItem(NULL_BAG, NULL_SLOT, dest, item, false);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
bot->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
|
||||
item->SetOwnerGUID(target->GetGUID());
|
||||
receiver->MoveItemToInventory(dest, item, true);
|
||||
moved = true;
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Got " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " from " << bot->GetName();
|
||||
receiverAi->TellMasterNoFacing(out.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Cannot get " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " from " << bot->GetName() << "- my bags are full";
|
||||
receiverAi->TellError(out.str());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* GiveItemAction::GetTarget()
|
||||
{
|
||||
return AI_VALUE2(Unit*, "party member without item", item);
|
||||
}
|
||||
|
||||
bool GiveItemAction::isUseful()
|
||||
{
|
||||
return GetTarget() && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->lowMana;
|
||||
}
|
||||
|
||||
Unit* GiveFoodAction::GetTarget()
|
||||
{
|
||||
return AI_VALUE(Unit*, "party member without food");
|
||||
}
|
||||
|
||||
Unit* GiveWaterAction::GetTarget()
|
||||
{
|
||||
return AI_VALUE(Unit*, "party member without water");
|
||||
}
|
||||
41
src/strategy/actions/GiveItemAction.h
Normal file
41
src/strategy/actions/GiveItemAction.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GIVEITEMACTION_H
|
||||
#define _PLAYERBOT_GIVEITEMACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class GiveItemAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
GiveItemAction(PlayerbotAI* botAI, std::string const name, std::string const item) : InventoryAction(botAI, name), item(item) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
Unit* GetTarget() override;
|
||||
|
||||
protected:
|
||||
std::string const item;
|
||||
};
|
||||
|
||||
class GiveFoodAction : public GiveItemAction
|
||||
{
|
||||
public:
|
||||
GiveFoodAction(PlayerbotAI* botAI) : GiveItemAction(botAI, "give food", "conjured food") { }
|
||||
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
|
||||
class GiveWaterAction : public GiveItemAction
|
||||
{
|
||||
public:
|
||||
GiveWaterAction(PlayerbotAI* botAI) : GiveItemAction(botAI, "give water", "conjured water") { }
|
||||
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
221
src/strategy/actions/GoAction.cpp
Normal file
221
src/strategy/actions/GoAction.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GoAction.h"
|
||||
#include "ChooseTravelTargetAction.h"
|
||||
#include "Event.h"
|
||||
#include "Formations.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "PositionValue.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
std::vector<std::string> split(std::string const s, char delim);
|
||||
char* strstri(char const* haystack, char const* needle);
|
||||
|
||||
bool GoAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
std::string const param = event.getParam();
|
||||
if (param == "?")
|
||||
{
|
||||
float x = bot->GetPositionX();
|
||||
float y = bot->GetPositionY();
|
||||
Map2ZoneCoordinates(x, y, bot->GetZoneId());
|
||||
|
||||
std::ostringstream out;
|
||||
out << "I am at " << x << "," << y;
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (param.find("travel") != std::string::npos && param.size() > 7)
|
||||
{
|
||||
WorldPosition botPos(bot);
|
||||
|
||||
std::string const destination = param.substr(7);
|
||||
|
||||
TravelTarget* target = context->GetValue<TravelTarget*>("travel target")->Get();
|
||||
|
||||
if (TravelDestination* dest = ChooseTravelTargetAction::FindDestination(bot, destination))
|
||||
{
|
||||
std::vector<WorldPosition*> points = dest->nextPoint(const_cast<WorldPosition*>(&botPos), true);
|
||||
if (points.empty())
|
||||
return false;
|
||||
|
||||
target->setTarget(dest, points.front());
|
||||
target->setForced(true);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Traveling to " << dest->getTitle();
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
botAI->TellMasterNoFacing("Clearing travel target");
|
||||
target->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition);
|
||||
target->setForced(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
GuidVector gos = ChatHelper::parseGameobjects(param);
|
||||
if (!gos.empty())
|
||||
{
|
||||
for (ObjectGuid const guid : gos)
|
||||
{
|
||||
if (GameObject* go = botAI->GetGameObject(guid))
|
||||
if (go->isSpawned())
|
||||
{
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, go), sPlayerbotAIConfig->reactDistance))
|
||||
{
|
||||
botAI->TellError("It is too far away");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Moving to " << ChatHelper::FormatGameobject(go);
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return MoveNear(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ() + 0.5f, sPlayerbotAIConfig->followDistance);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
GuidVector units;
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||
units.insert(units.end(), npcs.begin(), npcs.end());
|
||||
GuidVector players = AI_VALUE(GuidVector, "nearest friendly players");
|
||||
units.insert(units.end(), players.begin(), players.end());
|
||||
for (ObjectGuid const guid : units)
|
||||
{
|
||||
if (Unit* unit = botAI->GetUnit(guid))
|
||||
if (strstri(unit->GetName().c_str(), param.c_str()))
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Moving to " << unit->GetName();
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return MoveNear(bot->GetMapId(), unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ() + 0.5f, sPlayerbotAIConfig->followDistance);
|
||||
}
|
||||
}
|
||||
|
||||
if (param.find(";") != std::string::npos)
|
||||
{
|
||||
std::vector<std::string> coords = split(param, ';');
|
||||
float x = atof(coords[0].c_str());
|
||||
float y = atof(coords[1].c_str());
|
||||
float z;
|
||||
if (coords.size() > 2)
|
||||
z = atof(coords[2].c_str());
|
||||
else
|
||||
z = bot->GetPositionZ();
|
||||
|
||||
if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
PathGenerator path(bot);
|
||||
|
||||
path.CalculatePath(x, y, z, false);
|
||||
|
||||
Movement::Vector3 end = path.GetEndPosition();
|
||||
Movement::Vector3 aend = path.GetActualEndPosition();
|
||||
|
||||
Movement::PointsArray const& points = path.GetPath();
|
||||
PathType type = path.GetPathType();
|
||||
|
||||
std::ostringstream out;
|
||||
|
||||
out << x << ";" << y << ";" << z << " =";
|
||||
|
||||
out << "path is: ";
|
||||
|
||||
out << type;
|
||||
|
||||
out << " of length ";
|
||||
|
||||
out << points.size();
|
||||
|
||||
out << " with offset ";
|
||||
|
||||
out << (end - aend).length();
|
||||
|
||||
|
||||
for (auto i : points)
|
||||
{
|
||||
CreateWp(bot, i.x, i.y, i.z, 0.f, 11144);
|
||||
}
|
||||
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
|
||||
if (bot->IsWithinLOS(x, y, z))
|
||||
return MoveNear(bot->GetMapId(), x, y, z, 0);
|
||||
else
|
||||
return MoveTo(bot->GetMapId(), x, y, z, false, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (param.find(",") != std::string::npos)
|
||||
{
|
||||
std::vector<std::string> coords = split(param, ',');
|
||||
float x = atof(coords[0].c_str());
|
||||
float y = atof(coords[1].c_str());
|
||||
Zone2MapCoordinates(x, y, bot->GetZoneId());
|
||||
|
||||
Map* map = bot->GetMap();
|
||||
float z = bot->GetPositionZ();
|
||||
bot->UpdateAllowedPositionZ(x, y, z);
|
||||
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, x, y), sPlayerbotAIConfig->reactDistance))
|
||||
{
|
||||
botAI->TellMaster("It is too far away");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight()))
|
||||
{
|
||||
botAI->TellError("It is in water");
|
||||
return false;
|
||||
}
|
||||
|
||||
float ground = map->GetHeight(x, y, z + 0.5f);
|
||||
if (ground <= INVALID_HEIGHT)
|
||||
{
|
||||
botAI->TellError("I can't go there");
|
||||
return false;
|
||||
}
|
||||
|
||||
float x1 = x, y1 = y;
|
||||
Map2ZoneCoordinates(x1, y1, bot->GetZoneId());
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Moving to " << x1 << "," << y1;
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
|
||||
return MoveNear(bot->GetMapId(), x, y, z + 0.5f, sPlayerbotAIConfig->followDistance);
|
||||
}
|
||||
|
||||
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()[param];
|
||||
if (pos.isSet())
|
||||
{
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, pos.x, pos.y), sPlayerbotAIConfig->reactDistance))
|
||||
{
|
||||
botAI->TellError("It is too far away");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Moving to position " << param;
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z + 0.5f, sPlayerbotAIConfig->followDistance);
|
||||
}
|
||||
|
||||
botAI->TellMaster("Whisper 'go x,y', 'go [game object]', 'go unit' or 'go position' and I will go there");
|
||||
return false;
|
||||
}
|
||||
20
src/strategy/actions/GoAction.h
Normal file
20
src/strategy/actions/GoAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GOACTION_H
|
||||
#define _PLAYERBOT_GOACTION_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class GoAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
GoAction(PlayerbotAI* botAI) : MovementAction(botAI, "Go") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
137
src/strategy/actions/GossipHelloAction.cpp
Normal file
137
src/strategy/actions/GossipHelloAction.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GossipHelloAction.h"
|
||||
#include "GossipDef.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool GossipHelloAction::Execute(Event event)
|
||||
{
|
||||
ObjectGuid guid;
|
||||
|
||||
WorldPacket &p = event.getPacket();
|
||||
if (p.empty())
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (master)
|
||||
guid = master->GetTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
p.rpos(0);
|
||||
p >> guid;
|
||||
}
|
||||
|
||||
if (!guid)
|
||||
return false;
|
||||
|
||||
Creature* pCreature = bot->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
|
||||
if (!pCreature)
|
||||
{
|
||||
LOG_DEBUG("playerbots", "[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_GOSSIP_HELLO {} not found or you can't interact with him.", guid.ToString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
GossipMenuItemsMapBounds pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(pCreature->GetCreatureTemplate()->GossipMenuId);
|
||||
if (pMenuItemBounds.first == pMenuItemBounds.second)
|
||||
return false;
|
||||
|
||||
std::string const text = event.getParam();
|
||||
int32 menuToSelect = -1;
|
||||
if (text.empty())
|
||||
{
|
||||
WorldPacket p1;
|
||||
p1 << guid;
|
||||
bot->GetSession()->HandleGossipHelloOpcode(p1);
|
||||
bot->SetFacingToObject(pCreature);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "--- " << pCreature->GetName() << " ---";
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
|
||||
TellGossipMenus();
|
||||
}
|
||||
else if (!bot->PlayerTalkClass)
|
||||
{
|
||||
botAI->TellError("I need to talk first");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
menuToSelect = atoi(text.c_str());
|
||||
if (menuToSelect > 0)
|
||||
menuToSelect--;
|
||||
|
||||
ProcessGossip(menuToSelect);
|
||||
}
|
||||
|
||||
bot->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
void GossipHelloAction::TellGossipText(uint32 textId)
|
||||
{
|
||||
if (!textId)
|
||||
return;
|
||||
|
||||
if (GossipText const* text = sObjectMgr->GetGossipText(textId))
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; i++)
|
||||
{
|
||||
std::string const text0 = text->Options[i].Text_0;
|
||||
if (!text0.empty())
|
||||
botAI->TellMasterNoFacing(text0);
|
||||
|
||||
std::string const text1 = text->Options[i].Text_1;
|
||||
if (!text1.empty())
|
||||
botAI->TellMasterNoFacing(text1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GossipHelloAction::TellGossipMenus()
|
||||
{
|
||||
if (!bot->PlayerTalkClass)
|
||||
return;
|
||||
|
||||
Creature* pCreature = bot->GetNPCIfCanInteractWith(GetMaster()->GetTarget(), UNIT_NPC_FLAG_NONE);
|
||||
GossipMenu& menu = bot->PlayerTalkClass->GetGossipMenu();
|
||||
if (pCreature)
|
||||
{
|
||||
uint32 textId = bot->GetGossipTextId(menu.GetMenuId(), pCreature);
|
||||
TellGossipText(textId);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < menu.GetMenuItemCount(); i++)
|
||||
{
|
||||
GossipMenuItem const* item = menu.GetItem(i);
|
||||
std::ostringstream out;
|
||||
out << "[" << (i+1) << "] " << item->Message;
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool GossipHelloAction::ProcessGossip(int32 menuToSelect)
|
||||
{
|
||||
GossipMenu& menu = bot->PlayerTalkClass->GetGossipMenu();
|
||||
if (menuToSelect != -1 && menuToSelect >= menu.GetMenuItemCount())
|
||||
{
|
||||
botAI->TellError("Unknown gossip option");
|
||||
return false;
|
||||
}
|
||||
|
||||
GossipMenuItem const* item = menu.GetItem(menuToSelect);
|
||||
WorldPacket p;
|
||||
std::string code;
|
||||
p << GetMaster()->GetTarget();
|
||||
p << menu.GetMenuId() << menuToSelect;
|
||||
p << code;
|
||||
bot->GetSession()->HandleGossipSelectOptionOpcode(p);
|
||||
|
||||
TellGossipMenus();
|
||||
|
||||
return true;
|
||||
}
|
||||
25
src/strategy/actions/GossipHelloAction.h
Normal file
25
src/strategy/actions/GossipHelloAction.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GOSSIPHELLOACTION_H
|
||||
#define _PLAYERBOT_GOSSIPHELLOACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class GossipHelloAction : public Action
|
||||
{
|
||||
public:
|
||||
GossipHelloAction(PlayerbotAI* botAI) : Action(botAI, "gossip hello") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
void TellGossipMenus();
|
||||
bool ProcessGossip(int32 menuToSelect);
|
||||
void TellGossipText(uint32 textId);
|
||||
};
|
||||
|
||||
#endif
|
||||
42
src/strategy/actions/GreetAction.cpp
Normal file
42
src/strategy/actions/GreetAction.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GreetAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
GreetAction::GreetAction(PlayerbotAI* botAI) : Action(botAI, "greet")
|
||||
{
|
||||
}
|
||||
|
||||
bool GreetAction::Execute(Event event)
|
||||
{
|
||||
ObjectGuid guid = AI_VALUE(ObjectGuid, "new player nearby");
|
||||
if (!guid || !guid.IsPlayer())
|
||||
return false;
|
||||
|
||||
Player* player = dynamic_cast<Player*>(botAI->GetUnit(guid));
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, player, sPlayerbotAIConfig->sightDistance))
|
||||
bot->SetFacingToObject(player);
|
||||
|
||||
ObjectGuid oldSel = bot->GetTarget();
|
||||
bot->SetTarget(guid);
|
||||
//bot->HandleEmote(EMOTE_ONESHOT_WAVE);
|
||||
botAI->PlayEmote(TEXT_EMOTE_HELLO);
|
||||
bot->SetTarget(oldSel);
|
||||
|
||||
GuidSet& alreadySeenPlayers = botAI->GetAiObjectContext()->GetValue<GuidSet&>("already seen players")->Get();
|
||||
alreadySeenPlayers.insert(guid);
|
||||
|
||||
GuidVector nearestPlayers = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest friendly players")->Get();
|
||||
for (ObjectGuid const guid : nearestPlayers)
|
||||
{
|
||||
alreadySeenPlayers.insert(guid);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/GreetAction.h
Normal file
20
src/strategy/actions/GreetAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GREETACTION_H
|
||||
#define _PLAYERBOT_GREETACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class GreetAction : public Action
|
||||
{
|
||||
public:
|
||||
GreetAction(PlayerbotAI* botAI);
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
55
src/strategy/actions/GuildAcceptAction.cpp
Normal file
55
src/strategy/actions/GuildAcceptAction.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GuildAcceptAction.h"
|
||||
#include "Event.h"
|
||||
#include "GuildPackets.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotSecurity.h"
|
||||
|
||||
bool GuildAcceptAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
Player* inviter = nullptr;
|
||||
std::string Invitedname;
|
||||
p >> Invitedname;
|
||||
|
||||
if (normalizePlayerName(Invitedname))
|
||||
inviter = ObjectAccessor::FindPlayerByName(Invitedname.c_str());
|
||||
|
||||
if (!inviter)
|
||||
return false;
|
||||
|
||||
bool accept = true;
|
||||
uint32 guildId = inviter->GetGuildId();
|
||||
if (!guildId)
|
||||
{
|
||||
botAI->TellError("You are not in a guild!");
|
||||
accept = false;
|
||||
}
|
||||
else if (bot->GetGuildId())
|
||||
{
|
||||
botAI->TellError("Sorry, I am in a guild already");
|
||||
accept = false;
|
||||
}
|
||||
else if (!botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, inviter, true))
|
||||
{
|
||||
botAI->TellError("Sorry, I don't want to join your guild :(");
|
||||
accept = false;
|
||||
}
|
||||
|
||||
if (accept)
|
||||
{
|
||||
WorldPackets::Guild::AcceptGuildInvite data = WorldPacket(CMSG_GUILD_ACCEPT);
|
||||
bot->GetSession()->HandleGuildAcceptOpcode(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldPackets::Guild::GuildDeclineInvitation data = WorldPacket(CMSG_GUILD_DECLINE);
|
||||
bot->GetSession()->HandleGuildDeclineOpcode(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/GuildAcceptAction.h
Normal file
20
src/strategy/actions/GuildAcceptAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GUILDACCEPTACTION_H
|
||||
#define _PLAYERBOT_GUILDACCEPTACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class GuildAcceptAction : public Action
|
||||
{
|
||||
public:
|
||||
GuildAcceptAction(PlayerbotAI* botAI) : Action(botAI, "guild accept") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
75
src/strategy/actions/GuildBankAction.cpp
Normal file
75
src/strategy/actions/GuildBankAction.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GuildBankAction.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool GuildBankAction::Execute(Event event)
|
||||
{
|
||||
std::string const text = event.getParam();
|
||||
if (text.empty())
|
||||
return false;
|
||||
|
||||
if (!bot->GetGuildId() || (GetMaster() && GetMaster()->GetGuildId() != bot->GetGuildId()))
|
||||
{
|
||||
botAI->TellMaster("I'm not in your guild!");
|
||||
return false;
|
||||
}
|
||||
|
||||
GuidVector gos = *botAI->GetAiObjectContext()->GetValue<GuidVector >("nearest game objects");
|
||||
for (GuidVector::iterator i = gos.begin(); i != gos.end(); ++i)
|
||||
{
|
||||
GameObject* go = botAI->GetGameObject(*i);
|
||||
if (!go || !bot->GetGameObjectIfCanInteractWith(go->GetGUID(), GAMEOBJECT_TYPE_GUILD_BANK))
|
||||
continue;
|
||||
|
||||
return Execute(text, go);
|
||||
}
|
||||
|
||||
botAI->TellMaster("Cannot find the guild bank nearby");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GuildBankAction::Execute(std::string const text, GameObject* bank)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
std::vector<Item*> found = parseItems(text);
|
||||
if (found.empty())
|
||||
return false;
|
||||
|
||||
for (std::vector<Item*>::iterator i = found.begin(); i != found.end(); i++)
|
||||
{
|
||||
Item* item = *i;
|
||||
if (item)
|
||||
result &= MoveFromCharToBank(item, bank);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* bank)
|
||||
{
|
||||
uint32 playerSlot = item->GetSlot();
|
||||
uint32 playerBag = item->GetBagSlot();
|
||||
|
||||
std::ostringstream out;
|
||||
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
//guild->SwapItems(bot, 0, playerSlot, 0, INVENTORY_SLOT_BAG_0, 0);
|
||||
|
||||
// check source pos rights (item moved to bank)
|
||||
if (!guild->MemberHasTabRights(bot->GetGUID(), 0, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
|
||||
out << "I can't put " << chat->FormatItem(item->GetTemplate()) << " to guild bank. I have no rights to put items in the first guild bank tab";
|
||||
else
|
||||
{
|
||||
out << chat->FormatItem(item->GetTemplate()) << " put to guild bank";
|
||||
guild->SwapItemsWithInventory(bot, false, 0, 255, playerBag, playerSlot, 0);
|
||||
}
|
||||
|
||||
botAI->TellMaster(out);
|
||||
|
||||
return true;
|
||||
}
|
||||
26
src/strategy/actions/GuildBankAction.h
Normal file
26
src/strategy/actions/GuildBankAction.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GUILDBANKACTION_H
|
||||
#define _PLAYERBOT_GUILDBANKACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class GameObject;
|
||||
class Item;
|
||||
class PlayerbotAI;
|
||||
|
||||
class GuildBankAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
GuildBankAction(PlayerbotAI* botAI) : InventoryAction(botAI, "guild bank") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool Execute(std::string const text, GameObject* bank);
|
||||
bool MoveFromCharToBank(Item* item, GameObject* bank);
|
||||
};
|
||||
|
||||
#endif
|
||||
324
src/strategy/actions/GuildCreateActions.cpp
Normal file
324
src/strategy/actions/GuildCreateActions.cpp
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GuildCreateActions.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "BudgetValues.h"
|
||||
#include "Event.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RandomPlayerbotFactory.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
bool BuyPetitionAction::Execute(Event event)
|
||||
{
|
||||
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector >("nearest npcs")->Get();
|
||||
bool vendored = false, result = false;
|
||||
for (GuidVector::iterator i = vendors.begin(); i != vendors.end(); ++i)
|
||||
{
|
||||
ObjectGuid vendorguid = *i;
|
||||
Creature* pCreature = bot->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_PETITIONER);
|
||||
if (!pCreature)
|
||||
continue;
|
||||
|
||||
std::string const guildName = RandomPlayerbotFactory::CreateRandomGuildName();
|
||||
if (guildName.empty())
|
||||
continue;
|
||||
|
||||
WorldPacket data(CMSG_PETITION_BUY);
|
||||
|
||||
data << pCreature->GetGUID();
|
||||
data << uint32(0);
|
||||
data << uint64(0);
|
||||
data << guildName.c_str();
|
||||
data << std::string("");
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint16(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
|
||||
for (uint8 i = 0; i < 10; ++i)
|
||||
data << std::string("");
|
||||
|
||||
data << uint32(0); // index
|
||||
data << uint32(0);
|
||||
|
||||
bot->GetSession()->HandlePetitionBuyOpcode(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BuyPetitionAction::isUseful()
|
||||
{
|
||||
return canBuyPetition(bot);
|
||||
};
|
||||
|
||||
bool BuyPetitionAction::canBuyPetition(Player* bot)
|
||||
{
|
||||
if (bot->GetGuildId())
|
||||
return false;
|
||||
|
||||
if (bot->GetGuildIdInvited())
|
||||
return false;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
||||
|
||||
if (AI_VALUE2(uint32, "item count", "Hitem:5863:"))
|
||||
return false;
|
||||
|
||||
if (botAI->GetGuilderType() == GuilderType::SOLO)
|
||||
return false;
|
||||
|
||||
if (botAI->GetGrouperType() == GrouperType::SOLO)
|
||||
return false;
|
||||
|
||||
if (!botAI->HasStrategy("guild", BOT_STATE_NON_COMBAT))
|
||||
return false;
|
||||
|
||||
uint32 cost = 1000; //GUILD_CHARTER_COST;
|
||||
|
||||
if (AI_VALUE2(uint32, "free money for", uint32(NeedMoneyFor::guild)) < cost)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PetitionOfferAction::Execute(Event event)
|
||||
{
|
||||
uint32 petitionEntry = 5863; //GUILD_CHARTER
|
||||
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
|
||||
|
||||
if (petitions.empty())
|
||||
return false;
|
||||
|
||||
ObjectGuid guid = event.getObject();
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
{
|
||||
if (!guid)
|
||||
guid = bot->GetTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!guid)
|
||||
guid = master->GetTarget();
|
||||
}
|
||||
|
||||
if (!guid)
|
||||
return false;
|
||||
|
||||
Player* player = ObjectAccessor::FindPlayer(guid);
|
||||
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
WorldPacket data(CMSG_OFFER_PETITION);
|
||||
|
||||
data << uint32(0);
|
||||
data << petitions.front()->GetGUID();
|
||||
data << guid;
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT playerguid FROM petition_sign WHERE player_account = {} AND petitionguid = {}'",
|
||||
player->GetSession()->GetAccountId(), petitions.front()->GetGUID().GetCounter());
|
||||
if (result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bot->GetSession()->HandleOfferPetitionOpcode(data);
|
||||
|
||||
result = CharacterDatabase.Query("SELECT playerguid FROM petition_sign WHERE petitionguid = {}", petitions.front()->GetGUID().GetCounter());
|
||||
uint8 signs = result ? (uint8)result->GetRowCount() : 0;
|
||||
|
||||
context->GetValue<uint8>("petition signs")->Set(signs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PetitionOfferAction::isUseful()
|
||||
{
|
||||
return !bot->GetGuildId();
|
||||
}
|
||||
|
||||
bool PetitionOfferNearbyAction::Execute(Event event)
|
||||
{
|
||||
uint32 found = 0;
|
||||
|
||||
GuidVector nearGuids = botAI->GetAiObjectContext()->GetValue<GuidVector >("nearest friendly players")->Get();
|
||||
for (auto& i : nearGuids)
|
||||
{
|
||||
Player* player = ObjectAccessor::FindPlayer(i);
|
||||
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
if (player->GetGuildId())
|
||||
continue;
|
||||
|
||||
if (player->GetGuildIdInvited())
|
||||
continue;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||
|
||||
if (botAI)
|
||||
{
|
||||
/*
|
||||
if (botAI->GetGrouperType() == SOLO && !botAI->HasRealPlayerMaster()) //Do not invite solo players.
|
||||
continue;
|
||||
|
||||
*/
|
||||
if (botAI->HasActivePlayerMaster()) //Do not invite alts of active players.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sPlayerbotAIConfig->randomBotGroupNearby)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
|
||||
continue;
|
||||
|
||||
//Parse rpg target to quest action.
|
||||
WorldPacket p(CMSG_QUESTGIVER_ACCEPT_QUEST);
|
||||
p << i;
|
||||
p.rpos(0);
|
||||
|
||||
if (PetitionOfferAction::Execute(Event("petition offer nearby", p)))
|
||||
found++;
|
||||
}
|
||||
|
||||
return found > 0;
|
||||
}
|
||||
|
||||
bool PetitionOfferNearbyAction::isUseful()
|
||||
{
|
||||
return !bot->GetGuildId() && AI_VALUE2(uint32, "item count", chat->FormatQItem(5863)) && AI_VALUE(uint8, "petition signs") < sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS);
|
||||
}
|
||||
|
||||
bool PetitionTurnInAction::Execute(Event event)
|
||||
{
|
||||
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector >("nearest npcs")->Get();
|
||||
bool vendored = false, result = false;
|
||||
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
|
||||
|
||||
if (petitions.empty())
|
||||
return false;
|
||||
|
||||
for (GuidVector::iterator i = vendors.begin(); i != vendors.end(); ++i)
|
||||
{
|
||||
ObjectGuid vendorguid = *i;
|
||||
Creature* pCreature = bot->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_PETITIONER);
|
||||
if (!pCreature)
|
||||
continue;
|
||||
|
||||
WorldPacket data(CMSG_TURN_IN_PETITION, 8);
|
||||
|
||||
Item* petition = petitions.front();
|
||||
|
||||
if (!petition)
|
||||
return false;
|
||||
|
||||
data << petition->GetGUID();
|
||||
|
||||
bot->GetSession()->HandleTurnInPetitionOpcode(data);
|
||||
|
||||
if (bot->GetGuildId())
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
|
||||
uint32 st, cl, br, bc, bg;
|
||||
bg = urand(0, 51);
|
||||
bc = urand(0, 17);
|
||||
cl = urand(0, 17);
|
||||
br = urand(0, 7);
|
||||
st = urand(0, 180);
|
||||
EmblemInfo emblemInfo(st, cl, br, bc, bg);
|
||||
|
||||
guild->HandleSetEmblem(emblemInfo);
|
||||
|
||||
//LANG_GUILD_VETERAN -> can invite
|
||||
guild->HandleSetRankInfo(2, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK | GR_RIGHT_INVITE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get();
|
||||
|
||||
//Select a new target to travel to.
|
||||
TravelTarget newTarget = TravelTarget(botAI);
|
||||
|
||||
bool foundTarget = SetNpcFlagTarget(&newTarget, { UNIT_NPC_FLAG_PETITIONER });
|
||||
|
||||
if (!foundTarget || !newTarget.isActive())
|
||||
return false;
|
||||
|
||||
newTarget.setRadius(INTERACTION_DISTANCE);
|
||||
|
||||
setNewTarget(&newTarget, oldTarget);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PetitionTurnInAction::isUseful()
|
||||
{
|
||||
bool inCity = false;
|
||||
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetZoneId()))
|
||||
{
|
||||
if (zone->flags & AREA_FLAG_CAPITAL)
|
||||
inCity = true;
|
||||
}
|
||||
|
||||
return inCity && !bot->GetGuildId() && AI_VALUE2(uint32, "item count", chat->FormatQItem(5863)) &&
|
||||
AI_VALUE(uint8, "petition signs") >= sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS) && !context->GetValue<TravelTarget*>("travel target")->Get()->isTraveling();
|
||||
}
|
||||
|
||||
bool BuyTabardAction::Execute(Event event)
|
||||
{
|
||||
bool canBuy = botAI->DoSpecificAction("buy", Event("buy tabard", "Hitem:5976:"));
|
||||
if (canBuy && AI_VALUE2(uint32, "item count", chat->FormatQItem(5976)))
|
||||
return true;
|
||||
|
||||
TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get();
|
||||
|
||||
//Select a new target to travel to.
|
||||
TravelTarget newTarget = TravelTarget(botAI);
|
||||
|
||||
bool foundTarget = SetNpcFlagTarget(&newTarget, { UNIT_NPC_FLAG_TABARDDESIGNER }, "Tabard Vendor", { 5976 });
|
||||
|
||||
if (!foundTarget || !newTarget.isActive())
|
||||
return false;
|
||||
|
||||
newTarget.setRadius(INTERACTION_DISTANCE);
|
||||
|
||||
setNewTarget(&newTarget, oldTarget);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool BuyTabardAction::isUseful()
|
||||
{
|
||||
bool inCity = false;
|
||||
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetZoneId()))
|
||||
{
|
||||
if (zone->flags & AREA_FLAG_CAPITAL)
|
||||
inCity = true;
|
||||
}
|
||||
|
||||
return inCity && bot->GetGuildId() && !AI_VALUE2(uint32, "item count", chat->FormatQItem(5976)) &&
|
||||
AI_VALUE2(uint32, "free money for", uint32(NeedMoneyFor::guild)) >= 10000 && !context->GetValue<TravelTarget*>("travel target")->Get()->isTraveling();
|
||||
}
|
||||
60
src/strategy/actions/GuildCreateActions.h
Normal file
60
src/strategy/actions/GuildCreateActions.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GUILDCREATEACTION_H
|
||||
#define _PLAYERBOT_GUILDCREATEACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
#include "ChooseTravelTargetAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class BuyPetitionAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
BuyPetitionAction(PlayerbotAI* botAI) : InventoryAction(botAI, "buy petition") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
static bool canBuyPetition(Player* bot);
|
||||
};
|
||||
|
||||
class PetitionOfferAction : public Action
|
||||
{
|
||||
public:
|
||||
PetitionOfferAction(PlayerbotAI* botAI, std::string const name = "petition offer") : Action(botAI, name) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class PetitionOfferNearbyAction : public PetitionOfferAction
|
||||
{
|
||||
public:
|
||||
PetitionOfferNearbyAction(PlayerbotAI* botAI) : PetitionOfferAction(botAI, "petition offer nearby") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class PetitionTurnInAction : public ChooseTravelTargetAction
|
||||
{
|
||||
public:
|
||||
PetitionTurnInAction(PlayerbotAI* botAI) : ChooseTravelTargetAction(botAI, "turn in petitn") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class BuyTabardAction : public ChooseTravelTargetAction
|
||||
{
|
||||
public:
|
||||
BuyTabardAction(PlayerbotAI* botAI) : ChooseTravelTargetAction(botAI, "buy tabard") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
254
src/strategy/actions/GuildManagementActions.cpp
Normal file
254
src/strategy/actions/GuildManagementActions.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GuildManagementActions.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "GuildPackets.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
Player* GuidManageAction::GetPlayer(Event event)
|
||||
{
|
||||
Player* player = nullptr;
|
||||
ObjectGuid guid = event.getObject();
|
||||
|
||||
if (guid)
|
||||
{
|
||||
player = ObjectAccessor::FindPlayer(guid);
|
||||
|
||||
if (player)
|
||||
return player;
|
||||
}
|
||||
|
||||
std::string text = event.getParam();
|
||||
|
||||
if (!text.empty())
|
||||
{
|
||||
if (normalizePlayerName(text))
|
||||
{
|
||||
player = ObjectAccessor::FindPlayerByName(text.c_str());
|
||||
|
||||
if (player)
|
||||
return player;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
guid = bot->GetTarget();
|
||||
else
|
||||
guid = master->GetTarget();
|
||||
|
||||
player = ObjectAccessor::FindPlayer(guid);
|
||||
|
||||
if (player)
|
||||
return player;
|
||||
|
||||
player = event.getOwner();
|
||||
|
||||
if (player)
|
||||
return player;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GuidManageAction::Execute(Event event)
|
||||
{
|
||||
Player* player = GetPlayer(event);
|
||||
|
||||
if (!player || !PlayerIsValid(player) || player == bot)
|
||||
return false;
|
||||
|
||||
WorldPacket data(opcode);
|
||||
data << player->GetName();
|
||||
SendPacket(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuidManageAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return !member->GetGuildId();
|
||||
}
|
||||
|
||||
uint8 GuidManageAction::GetRankId(Player* member)
|
||||
{
|
||||
return sGuildMgr->GetGuildById(member->GetGuildId())->GetMember(member->GetGUID())->GetRankId();
|
||||
}
|
||||
|
||||
bool GuildInviteAction::isUseful()
|
||||
{
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_INVITE);
|
||||
}
|
||||
|
||||
void GuildInviteAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildInviteByName data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildInviteOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildInviteAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return !member->GetGuildId();
|
||||
}
|
||||
|
||||
bool GuildPromoteAction::isUseful()
|
||||
{
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_PROMOTE);
|
||||
}
|
||||
|
||||
void GuildPromoteAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildPromoteMember data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildPromoteOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildPromoteAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return member->GetGuildId() == bot->GetGuildId() && GetRankId(bot) < GetRankId(member) - 1;
|
||||
}
|
||||
|
||||
bool GuildDemoteAction::isUseful()
|
||||
{
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_DEMOTE);
|
||||
}
|
||||
|
||||
void GuildDemoteAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildDemoteMember data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildDemoteOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildDemoteAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return member->GetGuildId() == bot->GetGuildId() && GetRankId(bot) < GetRankId(member);
|
||||
}
|
||||
|
||||
bool GuildRemoveAction::isUseful()
|
||||
{
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_REMOVE);
|
||||
}
|
||||
|
||||
void GuildRemoveAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildOfficerRemoveMember data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildRemoveOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildRemoveAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return member->GetGuildId() == bot->GetGuildId() && GetRankId(bot) < GetRankId(member);
|
||||
};
|
||||
|
||||
bool GuildManageNearbyAction::Execute(Event event)
|
||||
{
|
||||
uint32 found = 0;
|
||||
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
Guild::Member* botMember = guild->GetMember(bot->GetGUID());
|
||||
|
||||
GuidVector nearGuids = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest friendly players")->Get();
|
||||
for (auto& guid : nearGuids)
|
||||
{
|
||||
Player* player = ObjectAccessor::FindPlayer(guid);
|
||||
|
||||
if (!player || bot == player)
|
||||
continue;
|
||||
|
||||
if (player->GetGuildId() != bot->GetGuildId())
|
||||
continue;
|
||||
|
||||
if (player->GetGuildId()) //Promote or demote nearby members based on chance.
|
||||
{
|
||||
Guild::Member* member = guild->GetMember(player->GetGUID());
|
||||
uint32 dCount = AI_VALUE(uint32, "death count");
|
||||
|
||||
if (dCount < 2 || !urand(0, 10))
|
||||
{
|
||||
if (!urand(0, 10))
|
||||
{
|
||||
botAI->DoSpecificAction("guild promote", Event("guild management", guid), true);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (dCount > 3 || !urand(0, 10))
|
||||
{
|
||||
if (!urand(0, 10))
|
||||
{
|
||||
botAI->DoSpecificAction("guild demote", Event("guild management", guid), true);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_INVITE))
|
||||
continue;
|
||||
|
||||
if (player->GetGuildIdInvited())
|
||||
continue;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||
|
||||
if (botAI)
|
||||
{
|
||||
|
||||
if (botAI->GetGuilderType() == GuilderType::SOLO && !botAI->HasRealPlayerMaster()) //Do not invite solo players.
|
||||
continue;
|
||||
|
||||
|
||||
if (botAI->HasActivePlayerMaster()) //Do not invite alts of active players.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sPlayerbotAIConfig->randomBotGroupNearby)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
|
||||
continue;
|
||||
|
||||
if (botAI->DoSpecificAction("ginvite", Event("guild management", guid)))
|
||||
found++;
|
||||
}
|
||||
|
||||
return found > 0;
|
||||
}
|
||||
|
||||
bool GuildManageNearbyAction::isUseful()
|
||||
{
|
||||
if (!bot->GetGuildId())
|
||||
return false;
|
||||
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
Guild::Member* botMember = guild->GetMember(bot->GetGUID());
|
||||
|
||||
return guild->GetRankRights(botMember->GetRankId()) & (GR_RIGHT_DEMOTE | GR_RIGHT_PROMOTE | GR_RIGHT_INVITE);
|
||||
}
|
||||
|
||||
bool GuildLeaveAction::Execute(Event event)
|
||||
{
|
||||
Player* owner = event.getOwner();
|
||||
if (owner && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, owner, true))
|
||||
{
|
||||
botAI->TellError("Sorry, I am happy in my guild :)");
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldPackets::Guild::GuildLeave data = WorldPacket(CMSG_GUILD_LEAVE);
|
||||
bot->GetSession()->HandleGuildLeaveOpcode(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuildLeaveAction::isUseful()
|
||||
{
|
||||
return bot->GetGuildId();
|
||||
}
|
||||
98
src/strategy/actions/GuildManagementActions.h
Normal file
98
src/strategy/actions/GuildManagementActions.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GUILDMAMANEGEMENTACTION_H
|
||||
#define _PLAYERBOT_GUILDMAMANEGEMENTACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "Opcodes.h"
|
||||
|
||||
class Player;
|
||||
class PlayerbotAI;
|
||||
class WorldPacket;
|
||||
|
||||
class GuidManageAction : public Action
|
||||
{
|
||||
public:
|
||||
GuidManageAction(PlayerbotAI* botAI, std::string const name = "guild manage", uint16 opcode = CMSG_GUILD_INVITE) : Action(botAI, name), opcode(opcode) { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override { return false; }
|
||||
|
||||
protected:
|
||||
virtual void SendPacket(WorldPacket data) { };
|
||||
virtual Player* GetPlayer(Event event);
|
||||
virtual bool PlayerIsValid(Player* member);
|
||||
virtual uint8 GetRankId(Player* member);
|
||||
|
||||
uint16 opcode;
|
||||
};
|
||||
|
||||
class GuildInviteAction : public GuidManageAction
|
||||
{
|
||||
public:
|
||||
GuildInviteAction(PlayerbotAI* botAI, std::string const name = "guild invite", uint16 opcode = CMSG_GUILD_INVITE) : GuidManageAction(botAI, name, opcode) { }
|
||||
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
void SendPacket(WorldPacket data) override;
|
||||
bool PlayerIsValid(Player* member) override;
|
||||
};
|
||||
|
||||
class GuildPromoteAction : public GuidManageAction
|
||||
{
|
||||
public:
|
||||
GuildPromoteAction(PlayerbotAI* botAI, std::string const name = "guild promote", uint16 opcode = CMSG_GUILD_PROMOTE) : GuidManageAction(botAI, name, opcode) { }
|
||||
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
void SendPacket(WorldPacket data) override;
|
||||
bool PlayerIsValid(Player* member) override;
|
||||
};
|
||||
|
||||
class GuildDemoteAction : public GuidManageAction
|
||||
{
|
||||
public:
|
||||
GuildDemoteAction(PlayerbotAI* botAI, std::string const name = "guild demote", uint16 opcode = CMSG_GUILD_DEMOTE) : GuidManageAction(botAI, name, opcode) { }
|
||||
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
void SendPacket(WorldPacket data) override;
|
||||
bool PlayerIsValid(Player* member) override;
|
||||
};
|
||||
|
||||
class GuildRemoveAction : public GuidManageAction
|
||||
{
|
||||
public:
|
||||
GuildRemoveAction(PlayerbotAI* botAI, std::string const name = "guild remove", uint16 opcode = CMSG_GUILD_REMOVE) : GuidManageAction(botAI, name, opcode) { }
|
||||
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
void SendPacket(WorldPacket data) override;
|
||||
bool PlayerIsValid(Player* member) override;
|
||||
};
|
||||
|
||||
class GuildManageNearbyAction : public Action
|
||||
{
|
||||
public:
|
||||
GuildManageNearbyAction(PlayerbotAI* botAI) : Action(botAI, "guild manage nearby") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class GuildLeaveAction : public Action
|
||||
{
|
||||
public:
|
||||
GuildLeaveAction(PlayerbotAI* botAI) : Action(botAI, "guild leave") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
56
src/strategy/actions/HelpAction.cpp
Normal file
56
src/strategy/actions/HelpAction.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "HelpAction.h"
|
||||
#include "ChatActionContext.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
HelpAction::HelpAction(PlayerbotAI* botAI) : Action(botAI, "help")
|
||||
{
|
||||
chatContext = new ChatActionContext();
|
||||
}
|
||||
|
||||
HelpAction::~HelpAction()
|
||||
{
|
||||
delete chatContext;
|
||||
}
|
||||
|
||||
bool HelpAction::Execute(Event event)
|
||||
{
|
||||
TellChatCommands();
|
||||
TellStrategies();
|
||||
return true;
|
||||
}
|
||||
|
||||
void HelpAction::TellChatCommands()
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Whisper any of: ";
|
||||
out << CombineSupported(chatContext->supports());
|
||||
out << ", [item], [quest] or [object] link";
|
||||
botAI->TellError(out.str());
|
||||
}
|
||||
|
||||
void HelpAction::TellStrategies()
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Possible strategies (co/nc/dead commands): ";
|
||||
out << CombineSupported(botAI->GetAiObjectContext()->GetSupportedStrategies());
|
||||
botAI->TellError(out.str());
|
||||
}
|
||||
|
||||
std::string const HelpAction::CombineSupported(std::set<std::string> commands)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
for (std::set<std::string>::iterator i = commands.begin(); i != commands.end(); )
|
||||
{
|
||||
out << *i;
|
||||
if (++i != commands.end())
|
||||
out << ", ";
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
29
src/strategy/actions/HelpAction.h
Normal file
29
src/strategy/actions/HelpAction.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_HELPACTION_H
|
||||
#define _PLAYERBOT_HELPACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "NamedObjectContext.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class HelpAction : public Action
|
||||
{
|
||||
public:
|
||||
HelpAction(PlayerbotAI* botAI);
|
||||
|
||||
virtual ~HelpAction();
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
void TellChatCommands();
|
||||
void TellStrategies();
|
||||
std::string const CombineSupported(std::set<std::string> commands);
|
||||
|
||||
NamedObjectContext<Action>* chatContext;
|
||||
};
|
||||
|
||||
#endif
|
||||
58
src/strategy/actions/HireAction.cpp
Normal file
58
src/strategy/actions/HireAction.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "HireAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool HireAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
if (!sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
return false;
|
||||
|
||||
uint32 account = master->GetSession()->GetAccountId();
|
||||
QueryResult results = CharacterDatabase.Query("SELECT COUNT(*) FROM characters WHERE account = {}", account);
|
||||
|
||||
uint32 charCount = 10;
|
||||
if (results)
|
||||
{
|
||||
Field* fields = results->Fetch();
|
||||
charCount = uint32(fields[0].Get<uint64>());
|
||||
}
|
||||
|
||||
if (charCount >= 10)
|
||||
{
|
||||
botAI->TellMaster("You already have the maximum number of characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->getLevel() > master->getLevel())
|
||||
{
|
||||
botAI->TellMaster("You cannot hire higher level characters than you");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 discount = sRandomPlayerbotMgr->GetTradeDiscount(bot, master);
|
||||
uint32 m = 1 + (bot->getLevel() / 10);
|
||||
uint32 moneyReq = m * 5000 * bot->getLevel();
|
||||
if (discount < moneyReq)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "You cannot hire me - I barely know you. Make sure you have at least " << chat->formatMoney(moneyReq) << " as a trade discount";
|
||||
botAI->TellMaster(out.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
botAI->TellMaster("I will join you at your next relogin");
|
||||
|
||||
bot->SetMoney(moneyReq);
|
||||
sRandomPlayerbotMgr->Remove(bot);
|
||||
CharacterDatabase.Execute("UPDATE characters SET account = {} WHERE guid = {}", account, bot->GetGUID().GetCounter());
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/strategy/actions/HireAction.h
Normal file
20
src/strategy/actions/HireAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_HIREACTION_H
|
||||
#define _PLAYERBOT_HIREACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class HireAction : public Action
|
||||
{
|
||||
public:
|
||||
HireAction(PlayerbotAI* botAI) : Action(botAI, "hire") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user