Ulduar flame leviathan (normal mode)

This commit is contained in:
Yunfan Li
2024-08-19 19:30:04 +08:00
parent 2c7cef0dc2
commit 47f8eb3e4a
22 changed files with 639 additions and 113 deletions

View File

@@ -9,6 +9,8 @@
#include "ChatActionContext.h"
#include "ChatTriggerContext.h"
#include "Playerbots.h"
#include "RaidUlduarTriggerContext.h"
#include "RaidUlduarActionContext.h"
#include "SharedValueContext.h"
#include "StrategyContext.h"
#include "TriggerContext.h"
@@ -34,12 +36,14 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
actionContexts.Add(new WorldPacketActionContext());
actionContexts.Add(new RaidActionContext());
actionContexts.Add(new RaidNaxxActionContext());
actionContexts.Add(new RaidUlduarActionContext());
triggerContexts.Add(new TriggerContext());
triggerContexts.Add(new ChatTriggerContext());
triggerContexts.Add(new WorldPacketTriggerContext());
triggerContexts.Add(new RaidTriggerContext());
triggerContexts.Add(new RaidNaxxTriggerContext());
triggerContexts.Add(new RaidUlduarTriggerContext());
valueContexts.Add(new ValueContext());

View File

@@ -140,6 +140,9 @@ std::vector<std::pair<uint32, std::string>> ListSpellsAction::GetSpellList(std::
if (itr->second->State == PLAYERSPELL_REMOVED || !itr->second->Active)
continue;
if (!(itr->second->specMask & bot->GetActiveSpecMask()))
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
if (!spellInfo)
continue;

View File

@@ -881,9 +881,9 @@ bool MovementAction::IsMovingAllowed(Unit* target)
if (bot->GetMapId() != target->GetMapId())
return false;
float distance = sServerFacade->GetDistance2d(bot, target);
if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance)
return false;
// float distance = sServerFacade->GetDistance2d(bot, target);
// if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance)
// return false;
return IsMovingAllowed();
}
@@ -893,9 +893,10 @@ bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z)
// removed sqrt as means distance limit was effectively 22500 (ReactDistance<63>)
// leaving it commented incase we find ReactDistance limit causes problems
// float distance = sqrt(bot->GetDistance(x, y, z));
float distance = bot->GetDistance(x, y, z);
if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance)
return false;
// Remove react distance limit
// if (!bot->InBattleground())
// return false;
return IsMovingAllowed();
}
@@ -923,6 +924,7 @@ bool MovementAction::IsWaitingForLastMove(MovementPriority priority)
if (lastMove.lastdelayTime + lastMove.msTime > getMSTime())
return true;
return false;
}

View File

@@ -175,6 +175,12 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
// }
// }
// }
if (player->GetVehicle())
{
botAI->TellError("You cannot summon me while I'm on a vehicle");
return false;
}
if (!summoner->IsBeingTeleported() && !player->IsBeingTeleported())
{
float followAngle = GetFollowAngle();
@@ -222,6 +228,7 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
}
player->GetMotionMaster()->Clear();
AI_VALUE(LastMovement&, "last movement").clear();
player->TeleportTo(mapId, x, y, z, 0);
return true;
}

View File

@@ -7,8 +7,11 @@
#include "BattlegroundIC.h"
#include "ItemVisitors.h"
#include "ObjectDefines.h"
#include "Playerbots.h"
#include "QuestValues.h"
#include "ServerFacade.h"
#include "Unit.h"
#include "Vehicle.h"
// TODO methods to enter/exit vehicle should be added to BGTactics or MovementAction (so that we can better control
@@ -21,6 +24,21 @@ bool EnterVehicleAction::Execute(Event event)
if (bot->GetVehicle())
return false;
Player* master = botAI->GetMaster();
// Triggered by a chat command
if (event.getOwner() && master && master->GetTarget())
{
Unit* vehicleBase = botAI->GetUnit(master->GetTarget());
if (!vehicleBase)
return false;
Vehicle* veh = vehicleBase->GetVehicleKit();
if (vehicleBase->IsVehicle() && veh && veh->GetAvailableSeatCount())
{
return EnterVehicle(vehicleBase, false);
}
return false;
}
GuidVector npcs = AI_VALUE(GuidVector, "nearest vehicles");
for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++)
{
@@ -28,6 +46,9 @@ bool EnterVehicleAction::Execute(Event event)
if (!vehicleBase)
continue;
if (vehicleBase->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
continue;
// dont let them get in the cannons as they'll stay forever and do nothing useful
// dont let them in catapult they cant use them at all
if (NPC_KEEP_CANNON == vehicleBase->GetEntry() || NPC_CATAPULT == vehicleBase->GetEntry())
@@ -44,27 +65,36 @@ bool EnterVehicleAction::Execute(Event event)
if (vehicleBase->GetVehicleKit()->IsVehicleInUse())
continue;
float dist = sServerFacade->GetDistance2d(bot, vehicleBase);
if (dist > 40.0f)
continue;
if (dist > INTERACTION_DISTANCE)
return MoveTo(vehicleBase);
bot->EnterVehicle(vehicleBase);
if (!bot->IsOnVehicle(vehicleBase))
return false;
// dismount because bots can enter vehicle on mount
WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
return true;
if (EnterVehicle(vehicleBase, true))
return true;
}
return false;
}
bool EnterVehicleAction::EnterVehicle(Unit* vehicleBase, bool moveIfFar)
{
float dist = sServerFacade->GetDistance2d(bot, vehicleBase);
if (dist > 40.0f)
return false;
if (dist > INTERACTION_DISTANCE && !moveIfFar)
return false;
if (dist > INTERACTION_DISTANCE)
return MoveTo(vehicleBase);
// Use HandleSpellClick instead of Unit::EnterVehicle to handle special vehicle script (ulduar)
vehicleBase->HandleSpellClick(bot);
if (!bot->IsOnVehicle(vehicleBase))
return false;
// dismount because bots can enter vehicle on mount
WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
return true;
}
bool LeaveVehicleAction::Execute(Event event)
{
Vehicle* myVehicle = bot->GetVehicle();

View File

@@ -17,6 +17,8 @@ public:
EnterVehicleAction(PlayerbotAI* botAI, std::string const& name = "enter vehicle") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
protected:
bool EnterVehicle(Unit* vehicleBase, bool moveIfFar);
};
class LeaveVehicleAction : public MovementAction

View File

@@ -60,6 +60,10 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
triggers.push_back(
new TriggerNode("talk", NextAction::array(0, new NextAction("gossip hello", relevance),
new NextAction("talk to quest giver", relevance), nullptr)));
triggers.push_back(
new TriggerNode("enter vehicle", NextAction::array(0, new NextAction("enter vehicle", relevance), nullptr)));
triggers.push_back(
new TriggerNode("leave vehicle", NextAction::array(0, new NextAction("leave vehicle", relevance), nullptr)));
triggers.push_back(
new TriggerNode("cast", NextAction::array(0, new NextAction("cast custom spell", relevance), nullptr)));
triggers.push_back(

View File

@@ -1,9 +1,10 @@
#ifndef _PLAYERBOT_RAIDSTRATEGYCONTEXT_H_
#define _PLAYERBOT_RAIDSTRATEGYCONTEXT_H_
#include "RaidUlduarStrategy.h"
#include "Strategy.h"
#include "raids/blackwinglair/RaidBwlStrategy.h"
#include "raids/naxxramas/RaidNaxxStrategy.h"
#include "RaidBwlStrategy.h"
#include "RaidNaxxStrategy.h"
class RaidStrategyContext : public NamedObjectContext<Strategy>
{
@@ -12,11 +13,13 @@ public:
{
creators["naxx"] = &RaidStrategyContext::naxx;
creators["bwl"] = &RaidStrategyContext::bwl;
creators["uld"] = &RaidStrategyContext::uld;
}
private:
static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); }
static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); }
static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); }
};
#endif

View File

@@ -13,9 +13,15 @@
class RaidUlduarActionContext : public NamedObjectContext<Action>
{
public:
RaidUlduarActionContext() {}
RaidUlduarActionContext()
{
creators["flame leviathan vehicle"] = &RaidUlduarActionContext::flame_leviathan_vehicle;
creators["flame leviathan enter vehicle"] = &RaidUlduarActionContext::flame_leviathan_enter_vehicle;
}
private:
static Action* flame_leviathan_vehicle(PlayerbotAI* ai) { return new FlameLeviathanVehicleAction(ai); }
static Action* flame_leviathan_enter_vehicle(PlayerbotAI* ai) { return new FlameLeviathanEnterVehicleAction(ai); }
};
#endif

View File

@@ -1,27 +1,376 @@
#include "RaidUlduarActions.h"
#include <cmath>
#include "DBCEnums.h"
#include "GameObject.h"
#include "LastMovementValue.h"
#include "ObjectDefines.h"
#include "ObjectGuid.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
#include "Position.h"
#include "RaidUlduarBossHelper.h"
#include "RaidUlduarScripts.h"
#include "RaidUlduarStrategy.h"
#include "ScriptedCreature.h"
#include "ServerFacade.h"
#include "SharedDefines.h"
#include "Unit.h"
#include "Vehicle.h"
uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint()
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
NPC_SALVAGED_SIEGE_ENGINE_TURRET};
const std::vector<Position> corners = {
{183.53f, 66.53f, 409.80f}, {383.03f, 75.10f, 411.71f}, {379.74f, -133.05f, 410.88f}, {158.67f, -137.54f, 409.80f}};
bool FlameLeviathanVehicleAction::Execute(Event event)
{
float minDistance = 0;
int ret = -1;
for (int i = 0; i < intervals; i++)
vehicleBase_ = bot->GetVehicleBase();
vehicle_ = bot->GetVehicle();
if (!vehicleBase_ || !vehicle_)
return false;
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
Unit* target = nullptr;
Unit* flame = nullptr;
for (auto i = attackers.begin(); i != attackers.end(); ++i)
{
float w_x = waypoints[i].first, w_y = waypoints[i].second;
float dis = bot->GetDistance2d(w_x, w_y);
if (ret == -1 || dis < minDistance)
Unit* unit = botAI->GetUnit(*i);
if (!unit)
continue;
if (unit->GetEntry() == 33139) // Flame Leviathan Turret
continue;
if (unit->GetEntry() == 33142) // Leviathan Defense Turret
continue;
if (unit->GetEntry() == 33133) // Flame Leviathan
flame = unit;
if (!target || bot->GetExactDist(target) > bot->GetExactDist(unit))
{
ret = i;
minDistance = dis;
target = unit;
}
}
return ret;
if (!target)
return false;
// Flame Leviathan is chasing me
if (flame && flame->GetVictim() == vehicleBase_)
if (MoveAvoidChasing(target))
return true;
uint32 entry = vehicleBase_->GetEntry();
switch (entry)
{
case NPC_SALVAGED_DEMOLISHER:
return DemolisherAction(target);
case NPC_SALVAGED_DEMOLISHER_TURRET:
return DemolisherTurretAction(target);
case NPC_SALVAGED_SIEGE_ENGINE:
return SiegeEngineAction(target);
case NPC_SALVAGED_SIEGE_ENGINE_TURRET:
return SiegeEngineTurretAction(target);
case NPC_VEHICLE_CHOPPER:
return ChopperAction(target);
default:
break;
}
return false;
}
bool FlameLeviathanVehicleAction::MoveAvoidChasing(Unit* target)
{
if (avoidChaseIdx == -1)
{
for (int i = 0; i < corners.size(); i++)
{
if (bot->GetExactDist(corners[i]) > target->GetExactDist(corners[i]))
continue;
if (avoidChaseIdx == -1 || bot->GetExactDist(corners[i]) > bot->GetExactDist(corners[avoidChaseIdx]))
avoidChaseIdx = i;
}
if (avoidChaseIdx == -1)
avoidChaseIdx = 0;
}
else
{
if (bot->GetExactDist(corners[avoidChaseIdx]) < 5.0f && target->GetExactDist(bot) < 50.0f)
avoidChaseIdx = (avoidChaseIdx + 1) % corners.size();
}
const Position& to = corners[avoidChaseIdx];
return MoveTo(bot->GetMap()->GetId(), to.GetPositionX(), to.GetPositionY(), to.GetPositionZ(), false, false, false,
false, MovementPriority::MOVEMENT_COMBAT);
}
bool FlameLeviathanVehicleAction::DemolisherAction(Unit* target)
{
Aura* bluePyrite = target->GetAura(68605);
if (!bluePyrite || (bluePyrite->GetStackAmount() <= 6 && vehicleBase_->GetPower(POWER_ENERGY) > 25) || bluePyrite->GetDuration() <= 5000)
{
uint32 spellId = 62490;
if (botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
}
uint32 spellId = 62306;
if (botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
return false;
}
bool FlameLeviathanVehicleAction::DemolisherTurretAction(Unit* target)
{
{
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
for (auto i = npcs.begin(); i != npcs.end(); i++)
{
Unit* unit = botAI->GetUnit(*i);
if (!unit)
continue;
if (unit->GetEntry() == 33189 && vehicleBase_->GetPower(POWER_ENERGY) <= 25) // Liquid Pyrite
{
uint32 spellId = 62479;
if (botAI->CanCastVehicleSpell(spellId, unit))
if (botAI->CastVehicleSpell(spellId, unit))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
}
}
}
{
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
for (auto i = targets.begin(); i != targets.end(); i++)
{
Unit* unit = botAI->GetUnit(*i);
if (!unit)
continue;
if (unit->GetEntry() == 33214) // Mechanolift 304-A
{
uint32 spellId = 64979;
if (botAI->CanCastVehicleSpell(spellId, unit))
if (botAI->CastVehicleSpell(spellId, unit))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
}
}
}
uint32 spellId = 62634;
if (botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
return false;
}
bool FlameLeviathanVehicleAction::SiegeEngineAction(Unit* target)
{
if (target->GetCurrentSpell(CURRENT_CHANNELED_SPELL) || target->HasAura(62396))
{
uint32 spellId = 62522;
if (botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 10000);
return true;
}
}
uint32 spellId = 62345;
if (vehicleBase_->GetPower(POWER_ENERGY) >= 80 && botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
return false;
}
bool FlameLeviathanVehicleAction::SiegeEngineTurretAction(Unit* target)
{
uint32 spellId = 62358;
if (botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
return false;
}
bool FlameLeviathanVehicleAction::ChopperAction(Unit* target)
{
uint32 spellId = 62286;
if (botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 15000);
return true;
}
spellId = 62974;
if (botAI->CanCastVehicleSpell(spellId, target))
if (botAI->CastVehicleSpell(spellId, target))
{
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
return true;
}
return false;
}
bool FlameLeviathanEnterVehicleAction::Execute(Event event)
{
// do not switch vehicles yet
if (bot->GetVehicle())
return false;
Unit* vehicleToEnter = nullptr;
GuidVector npcs = AI_VALUE(GuidVector, "nearest vehicles far");
for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++)
{
Unit* vehicleBase = botAI->GetUnit(*i);
if (!vehicleBase)
continue;
if (vehicleBase->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
continue;
if (!ShouldEnter(vehicleBase))
continue;
if (!vehicleToEnter || bot->GetExactDist(vehicleToEnter) > bot->GetExactDist(vehicleBase))
vehicleToEnter = vehicleBase;
}
if (!vehicleToEnter)
return false;
if (EnterVehicle(vehicleToEnter, true))
return true;
return false;
}
bool FlameLeviathanEnterVehicleAction::EnterVehicle(Unit* vehicleBase, bool moveIfFar)
{
float dist = bot->GetDistance(vehicleBase);
if (dist > INTERACTION_DISTANCE && !moveIfFar)
return false;
if (dist > INTERACTION_DISTANCE)
return MoveTo(vehicleBase);
botAI->RemoveShapeshift();
// Use HandleSpellClick instead of Unit::EnterVehicle to handle special vehicle script (ulduar)
vehicleBase->HandleSpellClick(bot);
if (!bot->IsOnVehicle(vehicleBase))
return false;
// dismount because bots can enter vehicle on mount
WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
return true;
}
bool FlameLeviathanEnterVehicleAction::ShouldEnter(Unit* target)
{
Vehicle* vehicleKit = target->GetVehicleKit();
if (!vehicleKit)
return false;
bool isMelee = botAI->IsMelee(bot);
bool allMain = AllMainVehiclesOnUse();
bool inUse = vehicleKit->IsVehicleInUse();
int32 entry = target->GetEntry();
if (entry != NPC_SALVAGED_DEMOLISHER && entry != NPC_SALVAGED_SIEGE_ENGINE && entry != NPC_VEHICLE_CHOPPER)
return false;
// two phase enter (make all main vehicles in use -> next player enter)
if (!allMain)
{
if (inUse)
return false;
if (entry != NPC_SALVAGED_DEMOLISHER && entry != NPC_SALVAGED_SIEGE_ENGINE)
return false;
if (entry == NPC_SALVAGED_DEMOLISHER && isMelee)
return false;
if (entry == NPC_SALVAGED_SIEGE_ENGINE && !isMelee)
return false;
return true;
}
if (!vehicleKit->GetAvailableSeatCount())
return false;
// do not enter useless seat
if (entry == NPC_SALVAGED_SIEGE_ENGINE)
{
Unit* turret = vehicleKit->GetPassenger(7);
if (!turret)
return false;
Vehicle* turretVehicle = turret->GetVehicleKit();
if (!turretVehicle)
return false;
if (turretVehicle->IsVehicleInUse())
return false;
return true;
}
if (entry == NPC_SALVAGED_DEMOLISHER)
{
if (vehicleKit->GetPassenger(0))
{
Unit* target2 = vehicleKit->GetPassenger(1);
if (!target2)
return false;
Vehicle* vehicle2 = target2->GetVehicleKit();
if (!vehicle2)
return false;
if (vehicle2->GetPassenger(0))
return false;
}
return true;
}
if (entry == NPC_VEHICLE_CHOPPER && vehicleKit->GetAvailableSeatCount() <= 1)
return false;
return true;
}
bool FlameLeviathanEnterVehicleAction::AllMainVehiclesOnUse()
{
Group* group = bot->GetGroup();
if (!group)
return false;
int demolisher = 0;
int siege = 0;
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (!player)
continue;
Unit* vehicleBase = player->GetVehicleBase();
if (!vehicleBase)
continue;
if (vehicleBase->GetEntry() == NPC_SALVAGED_DEMOLISHER)
++demolisher;
else if (vehicleBase->GetEntry() == NPC_SALVAGED_SIEGE_ENGINE)
++siege;
}
Difficulty diff = bot->GetRaidDifficulty();
int maxC = (diff == RAID_DIFFICULTY_10MAN_NORMAL || diff == RAID_DIFFICULTY_10MAN_HEROIC) ? 2 : 5;
return demolisher >= maxC && siege >= maxC;
}

View File

@@ -4,20 +4,42 @@
#include "Action.h"
#include "AttackAction.h"
#include "GenericActions.h"
#include "GenericSpellActions.h"
#include "MovementActions.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "RaidUlduarBossHelper.h"
#include "RaidUlduarScripts.h"
#include "Vehicle.h"
// just for test
// class TryToGetBossAIAction : public Action
// {
// public:
// TryToGetBossAIAction(PlayerbotAI* ai) : Action(ai, "try to get boss ai") {}
class FlameLeviathanVehicleAction : public MovementAction
{
public:
FlameLeviathanVehicleAction(PlayerbotAI* botAI) : MovementAction(botAI, "flame leviathan vehicle") {}
bool Execute(Event event) override;
// public:
// virtual bool Execute(Event event);
// };
protected:
bool MoveAvoidChasing(Unit* target);
bool DemolisherAction(Unit* target);
bool DemolisherTurretAction(Unit* target);
bool SiegeEngineAction(Unit* target);
bool SiegeEngineTurretAction(Unit* target);
bool ChopperAction(Unit* target);
Unit* GetAttacker();
Unit* vehicleBase_;
Vehicle* vehicle_;
int avoidChaseIdx = -1;
};
class FlameLeviathanEnterVehicleAction : public MovementAction
{
public:
FlameLeviathanEnterVehicleAction(PlayerbotAI* botAI) : MovementAction(botAI, "flame leviathan enter vehicle") {}
bool Execute(Event event);
protected:
bool EnterVehicle(Unit* vehicleBase, bool moveIfFar);
bool ShouldEnter(Unit* vehicleBase);
bool AllMainVehiclesOnUse();
};
#endif

View File

@@ -11,73 +11,72 @@
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "RaidUlduarScripts.h"
#include "ScriptedCreature.h"
#include "SharedDefines.h"
const uint32 ULDUAR_MAP_ID = 603;
template <class BossAiType>
class GenericBossHelper : public AiObject
{
public:
GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {}
virtual bool UpdateBossAI()
{
if (!bot->IsInCombat())
{
_unit = nullptr;
}
if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive()))
{
_unit = nullptr;
}
if (!_unit)
{
_unit = AI_VALUE2(Unit*, "find target", _name);
if (!_unit)
{
return false;
}
_target = _unit->ToCreature();
if (!_target)
{
return false;
}
_ai = dynamic_cast<BossAiType*>(_target->GetAI());
if (!_ai)
{
return false;
}
_event_map = &_ai->events;
if (!_event_map)
{
return false;
}
}
if (!_event_map)
{
return false;
}
_timer = _event_map->GetTimer();
return true;
}
virtual void Reset()
{
_unit = nullptr;
_target = nullptr;
_ai = nullptr;
_event_map = nullptr;
_timer = 0;
}
// template <class BossAiType>
// class GenericBossHelper : public AiObject
// {
// public:
// GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {}
// virtual bool UpdateBossAI()
// {
// if (!bot->IsInCombat())
// {
// _unit = nullptr;
// }
// if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive()))
// {
// _unit = nullptr;
// }
// if (!_unit)
// {
// _unit = AI_VALUE2(Unit*, "find target", _name);
// if (!_unit)
// {
// return false;
// }
// _target = _unit->ToCreature();
// if (!_target)
// {
// return false;
// }
// _ai = dynamic_cast<BossAiType*>(_target->GetAI());
// if (!_ai)
// {
// return false;
// }
// _event_map = &_ai->events;
// if (!_event_map)
// {
// return false;
// }
// }
// if (!_event_map)
// {
// return false;
// }
// _timer = _event_map->GetTimer();
// return true;
// }
// virtual void Reset()
// {
// _unit = nullptr;
// _target = nullptr;
// _ai = nullptr;
// _event_map = nullptr;
// _timer = 0;
// }
protected:
std::string _name;
Unit* _unit = nullptr;
Creature* _target = nullptr;
BossAiType* _ai = nullptr;
EventMap* _event_map = nullptr;
uint32 _timer = 0;
};
// protected:
// std::string _name;
// Unit* _unit = nullptr;
// Creature* _target = nullptr;
// BossAiType* _ai = nullptr;
// EventMap* _event_map = nullptr;
// uint32 _timer = 0;
// };
#endif

View File

@@ -19,3 +19,10 @@
#include "ShamanActions.h"
#include "UseMeetingStoneAction.h"
#include "WarriorActions.h"
float FlameLeviathanMultiplier::GetValue(Action* action)
{
// if (dynamic_cast<FleeAction*>(action))
// return 0.0f;
return 1.0f;
}

View File

@@ -5,4 +5,13 @@
#include "Multiplier.h"
#include "raids/ulduar/RaidUlduarBossHelper.h"
class FlameLeviathanMultiplier : public Multiplier
{
public:
FlameLeviathanMultiplier(PlayerbotAI* ai) : Multiplier(ai, "flame leviathan") {}
public:
virtual float GetValue(Action* action);
};
#endif

View File

@@ -3,5 +3,6 @@
// There are no header files for bosses in Ulduar directory
//#include "../../../../src/server/scripts/Northrend/Ulduar/Ulduar/"
#include "../../../../src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h"
#endif

View File

@@ -2,6 +2,20 @@
#include "RaidUlduarMultipliers.h"
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// Flame Leviathan
triggers.push_back(new TriggerNode(
"flame leviathan vehicle near",
NextAction::array(0, new NextAction("flame leviathan enter vehicle", ACTION_RAID + 2), nullptr)));
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers) {}
triggers.push_back(new TriggerNode(
"flame leviathan on vehicle",
NextAction::array(0, new NextAction("flame leviathan vehicle", ACTION_RAID + 1), nullptr)));
}
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
{
multipliers.push_back(new FlameLeviathanMultiplier(botAI));
}

View File

@@ -4,14 +4,13 @@
#include "AiObjectContext.h"
#include "Multiplier.h"
#include "RaidUlduarScripts.h"
#include "Strategy.h"
class RaidUlduarStrategy : public Strategy
{
public:
RaidUlduarStrategy(PlayerbotAI* ai) : Strategy(ai) {}
virtual std::string const getName() override { return "ulduar"; }
virtual std::string const getName() override { return "uld"; }
virtual void InitTriggers(std::vector<TriggerNode*>& triggers) override;
virtual void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
};

View File

@@ -13,9 +13,15 @@
class RaidUlduarTriggerContext : public NamedObjectContext<Trigger>
{
public:
RaidUlduarTriggerContext() {}
RaidUlduarTriggerContext()
{
creators["flame leviathan on vehicle"] = &RaidUlduarTriggerContext::flame_leviathan_on_vehicle;
creators["flame leviathan vehicle near"] = &RaidUlduarTriggerContext::flame_leviathan_vehicle_near;
}
private:
static Trigger* flame_leviathan_on_vehicle(PlayerbotAI* ai) { return new FlameLeviathanOnVehicleTrigger(ai); }
static Trigger* flame_leviathan_vehicle_near(PlayerbotAI* ai) { return new FlameLeviathanVehicleNearTrigger(ai); }
};
#endif

View File

@@ -1,6 +1,45 @@
#include "RaidUlduarTriggers.h"
#include "EventMap.h"
#include "Object.h"
#include "Playerbots.h"
#include "RaidUlduarScripts.h"
#include "ScriptedCreature.h"
#include "SharedDefines.h"
#include "Trigger.h"
#include "Vehicle.h"
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
NPC_SALVAGED_SIEGE_ENGINE_TURRET};
bool FlameLeviathanOnVehicleTrigger::IsActive()
{
Unit* vehicleBase = bot->GetVehicleBase();
Vehicle* vehicle = bot->GetVehicle();
if (!vehicleBase || !vehicle)
return false;
uint32 entry = vehicleBase->GetEntry();
for (uint32 comp : availableVehicles)
{
if (entry == comp)
return true;
}
return false;
}
bool FlameLeviathanVehicleNearTrigger::IsActive()
{
if (bot->GetVehicle())
return false;
Player* master = botAI->GetMaster();
if (!master)
return false;
if (!master->GetVehicle())
return false;
return true;
}

View File

@@ -5,7 +5,21 @@
#include "GenericTriggers.h"
#include "PlayerbotAIConfig.h"
#include "RaidUlduarBossHelper.h"
#include "RaidUlduarScripts.h"
#include "Trigger.h"
class FlameLeviathanOnVehicleTrigger : public Trigger
{
public:
FlameLeviathanOnVehicleTrigger(PlayerbotAI* ai) : Trigger(ai, "flame leviathan on vehicle") {}
bool IsActive() override;
};
class FlameLeviathanVehicleNearTrigger : public Trigger
{
public:
FlameLeviathanVehicleNearTrigger(PlayerbotAI* ai) : Trigger(ai, "flame leviathan vehicle near") {}
bool IsActive() override;
};
#endif

View File

@@ -77,6 +77,8 @@ public:
creators["grind"] = &ChatTriggerContext::grind;
creators["tank attack"] = &ChatTriggerContext::tank_attack;
creators["talk"] = &ChatTriggerContext::talk;
creators["enter vehicle"] = &ChatTriggerContext::enter_vehicle;
creators["leave vehicle"] = &ChatTriggerContext::leave_vehicle;
creators["cast"] = &ChatTriggerContext::cast;
creators["castnc"] = &ChatTriggerContext::castnc;
creators["invite"] = &ChatTriggerContext::invite;
@@ -155,6 +157,8 @@ private:
static Trigger* cast(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cast"); }
static Trigger* castnc(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "castnc"); }
static Trigger* talk(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "talk"); }
static Trigger* enter_vehicle(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "enter vehicle"); }
static Trigger* leave_vehicle(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "leave vehicle"); }
static Trigger* flee(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "flee"); }
static Trigger* grind(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "grind"); }
static Trigger* tank_attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "tank attack"); }

View File

@@ -106,6 +106,7 @@ public:
creators["nearest npcs"] = &ValueContext::nearest_npcs;
creators["nearest totems"] = &ValueContext::nearest_totems;
creators["nearest vehicles"] = &ValueContext::nearest_vehicles;
creators["nearest vehicles far"] = &ValueContext::nearest_vehicles_far;
creators["nearest friendly players"] = &ValueContext::nearest_friendly_players;
creators["closest friendly players"] = &ValueContext::closest_friendly_players;
creators["nearest enemy players"] = &ValueContext::nearest_enemy_players;
@@ -394,6 +395,7 @@ private:
static UntypedValue* nearest_npcs(PlayerbotAI* botAI) { return new NearestNpcsValue(botAI); }
static UntypedValue* nearest_totems(PlayerbotAI* botAI) { return new NearestTotemsValue(botAI); }
static UntypedValue* nearest_vehicles(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI); }
static UntypedValue* nearest_vehicles_far(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI, 200.0f); }
static UntypedValue* nearest_friendly_players(PlayerbotAI* botAI) { return new NearestFriendlyPlayersValue(botAI); }
static UntypedValue* closest_friendly_players(PlayerbotAI* botAI)
{