From 47f8eb3e4a133f8691a4c444745e4c46a28f9d9f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 19 Aug 2024 19:30:04 +0800 Subject: [PATCH 1/5] Ulduar flame leviathan (normal mode) --- src/strategy/AiObjectContext.cpp | 4 + src/strategy/actions/ListSpellsAction.cpp | 3 + src/strategy/actions/MovementActions.cpp | 14 +- .../actions/UseMeetingStoneAction.cpp | 7 + src/strategy/actions/VehicleActions.cpp | 62 ++- src/strategy/actions/VehicleActions.h | 2 + .../generic/ChatCommandHandlerStrategy.cpp | 4 + src/strategy/raids/RaidStrategyContext.h | 7 +- .../raids/ulduar/RaidUlduarActionContext.h | 8 +- .../raids/ulduar/RaidUlduarActions.cpp | 369 +++++++++++++++++- src/strategy/raids/ulduar/RaidUlduarActions.h | 40 +- .../raids/ulduar/RaidUlduarBossHelper.h | 123 +++--- .../raids/ulduar/RaidUlduarMultipliers.cpp | 7 + .../raids/ulduar/RaidUlduarMultipliers.h | 9 + src/strategy/raids/ulduar/RaidUlduarScripts.h | 1 + .../raids/ulduar/RaidUlduarStrategy.cpp | 18 +- .../raids/ulduar/RaidUlduarStrategy.h | 3 +- .../raids/ulduar/RaidUlduarTriggerContext.h | 10 +- .../raids/ulduar/RaidUlduarTriggers.cpp | 39 ++ .../raids/ulduar/RaidUlduarTriggers.h | 16 +- src/strategy/triggers/ChatTriggerContext.h | 4 + src/strategy/values/ValueContext.h | 2 + 22 files changed, 639 insertions(+), 113 deletions(-) diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index c844bb51..5c4237d7 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -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()); diff --git a/src/strategy/actions/ListSpellsAction.cpp b/src/strategy/actions/ListSpellsAction.cpp index 652d22b7..75d25ac9 100644 --- a/src/strategy/actions/ListSpellsAction.cpp +++ b/src/strategy/actions/ListSpellsAction.cpp @@ -139,6 +139,9 @@ std::vector> 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) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 641b9cfc..cf51e144 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -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�) // 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; } diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index f0df16b8..0c0b7285 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -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; } diff --git a/src/strategy/actions/VehicleActions.cpp b/src/strategy/actions/VehicleActions.cpp index 4683ba7a..13612a07 100644 --- a/src/strategy/actions/VehicleActions.cpp +++ b/src/strategy/actions/VehicleActions.cpp @@ -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 @@ -20,6 +23,21 @@ bool EnterVehicleAction::Execute(Event event) // do not switch vehicles yet 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++) @@ -27,6 +45,9 @@ bool EnterVehicleAction::Execute(Event event) Unit* vehicleBase = botAI->GetUnit(*i); 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 @@ -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(); diff --git a/src/strategy/actions/VehicleActions.h b/src/strategy/actions/VehicleActions.h index b48054c5..fbda01b8 100644 --- a/src/strategy/actions/VehicleActions.h +++ b/src/strategy/actions/VehicleActions.h @@ -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 diff --git a/src/strategy/generic/ChatCommandHandlerStrategy.cpp b/src/strategy/generic/ChatCommandHandlerStrategy.cpp index 58ee9549..c86e774b 100644 --- a/src/strategy/generic/ChatCommandHandlerStrategy.cpp +++ b/src/strategy/generic/ChatCommandHandlerStrategy.cpp @@ -60,6 +60,10 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector& 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( diff --git a/src/strategy/raids/RaidStrategyContext.h b/src/strategy/raids/RaidStrategyContext.h index 2d610000..f0092302 100644 --- a/src/strategy/raids/RaidStrategyContext.h +++ b/src/strategy/raids/RaidStrategyContext.h @@ -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 { @@ -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 \ No newline at end of file diff --git a/src/strategy/raids/ulduar/RaidUlduarActionContext.h b/src/strategy/raids/ulduar/RaidUlduarActionContext.h index 591e8fbd..ddcac039 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActionContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarActionContext.h @@ -13,9 +13,15 @@ class RaidUlduarActionContext : public NamedObjectContext { 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 \ No newline at end of file diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.cpp b/src/strategy/raids/ulduar/RaidUlduarActions.cpp index 66828cae..2a230ca6 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarActions.cpp @@ -1,27 +1,376 @@ #include "RaidUlduarActions.h" +#include + +#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 availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER, + NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE, + NPC_SALVAGED_SIEGE_ENGINE_TURRET}; + +const std::vector 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("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; } \ No newline at end of file diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.h b/src/strategy/raids/ulduar/RaidUlduarActions.h index c2fec2d8..0019ff8a 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.h +++ b/src/strategy/raids/ulduar/RaidUlduarActions.h @@ -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 \ No newline at end of file diff --git a/src/strategy/raids/ulduar/RaidUlduarBossHelper.h b/src/strategy/raids/ulduar/RaidUlduarBossHelper.h index a1585ade..3580444d 100644 --- a/src/strategy/raids/ulduar/RaidUlduarBossHelper.h +++ b/src/strategy/raids/ulduar/RaidUlduarBossHelper.h @@ -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 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(_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 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(_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 diff --git a/src/strategy/raids/ulduar/RaidUlduarMultipliers.cpp b/src/strategy/raids/ulduar/RaidUlduarMultipliers.cpp index 760e3547..16df9c9a 100644 --- a/src/strategy/raids/ulduar/RaidUlduarMultipliers.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarMultipliers.cpp @@ -19,3 +19,10 @@ #include "ShamanActions.h" #include "UseMeetingStoneAction.h" #include "WarriorActions.h" + +float FlameLeviathanMultiplier::GetValue(Action* action) +{ + // if (dynamic_cast(action)) + // return 0.0f; + return 1.0f; +} \ No newline at end of file diff --git a/src/strategy/raids/ulduar/RaidUlduarMultipliers.h b/src/strategy/raids/ulduar/RaidUlduarMultipliers.h index 76ed53c3..aef41be5 100644 --- a/src/strategy/raids/ulduar/RaidUlduarMultipliers.h +++ b/src/strategy/raids/ulduar/RaidUlduarMultipliers.h @@ -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 \ No newline at end of file diff --git a/src/strategy/raids/ulduar/RaidUlduarScripts.h b/src/strategy/raids/ulduar/RaidUlduarScripts.h index a5085309..404b0dbd 100644 --- a/src/strategy/raids/ulduar/RaidUlduarScripts.h +++ b/src/strategy/raids/ulduar/RaidUlduarScripts.h @@ -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 diff --git a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp index c0693cdc..0c6ed182 100644 --- a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp @@ -2,6 +2,20 @@ #include "RaidUlduarMultipliers.h" -void RaidUlduarStrategy::InitTriggers(std::vector& triggers) {} +void RaidUlduarStrategy::InitTriggers(std::vector& 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& 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& multipliers) +{ + multipliers.push_back(new FlameLeviathanMultiplier(botAI)); +} diff --git a/src/strategy/raids/ulduar/RaidUlduarStrategy.h b/src/strategy/raids/ulduar/RaidUlduarStrategy.h index e523d4b6..6538845c 100644 --- a/src/strategy/raids/ulduar/RaidUlduarStrategy.h +++ b/src/strategy/raids/ulduar/RaidUlduarStrategy.h @@ -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& triggers) override; virtual void InitMultipliers(std::vector& multipliers) override; }; diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h index aed35cf8..22c0f044 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h @@ -13,9 +13,15 @@ class RaidUlduarTriggerContext : public NamedObjectContext { 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 \ No newline at end of file +#endif diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp index 8ee3d799..b231f716 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp @@ -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 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; +} diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.h b/src/strategy/raids/ulduar/RaidUlduarTriggers.h index 7337706a..89b784cf 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.h @@ -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 \ No newline at end of file diff --git a/src/strategy/triggers/ChatTriggerContext.h b/src/strategy/triggers/ChatTriggerContext.h index 7def8b14..f146e08f 100644 --- a/src/strategy/triggers/ChatTriggerContext.h +++ b/src/strategy/triggers/ChatTriggerContext.h @@ -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"); } diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 3f3e4f3a..6fb93fdf 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -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) { From e983f9be00b375a5a615978e8bc156805783dc05 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 19 Aug 2024 23:31:32 +0800 Subject: [PATCH 2/5] [Crash fix] Duplicate loading bot --- src/PlayerbotMgr.cpp | 26 ++++++++++---------------- src/PlayerbotMgr.h | 2 ++ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 7d71e88a..097e0bf1 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -48,6 +48,10 @@ public: void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId) { + // bot is loading + if (botLoading.find(playerGuid) != botLoading.end()) + return; + // has bot already been added? Player* bot = ObjectAccessor::FindConnectedPlayer(playerGuid); if (bot && bot->IsInWorld()) @@ -64,6 +68,8 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId return; } + botLoading.insert(playerGuid); + if (WorldSession* masterSession = sWorld->FindSession(masterAccountId)) { masterSession->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)) @@ -80,13 +86,6 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder) { - // has bot already been added? - Player* loginBot = ObjectAccessor::FindConnectedPlayer(holder.GetGuid()); - if (loginBot && loginBot->IsInWorld()) - { - return; - } - uint32 botAccountId = holder.GetAccountId(); // At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this @@ -101,8 +100,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con { botSession->LogoutPlayer(true); delete botSession; - // LOG_ERROR("playerbots", "Error logging in bot {}, please try to reset all random bots", - // holder.GetGuid().ToString().c_str()); + botLoading.erase(holder.GetGuid()); return; } @@ -159,12 +157,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con } botSession->LogoutPlayer(true); delete botSession; - // OnBotLogin(bot); - // LogoutPlayerBot(bot->GetGUID()); - - // LOG_ERROR("playerbots", "Attempt to add not allowed bot {}, please try to reset all random bots", - // bot->GetName()); } + botLoading.erase(holder.GetGuid()); } void PlayerbotHolder::UpdateSessions() @@ -387,7 +381,7 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid) LOG_DEBUG("playerbots", "Bot {} logged out", bot->GetName().c_str()); - bot->SaveToDB(false, false); + // bot->SaveToDB(false, false); if (botAI->GetAiObjectContext()) // Maybe some day re-write to delate all pointer values. { @@ -540,7 +534,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) bot->RemovePlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); } - bot->SaveToDB(false, false); + // bot->SaveToDB(false, false); if (master && isRandomAccount && master->GetLevel() < bot->GetLevel()) { // PlayerbotFactory factory(bot, master->GetLevel()); diff --git a/src/PlayerbotMgr.h b/src/PlayerbotMgr.h index ce746e07..d67d36ef 100644 --- a/src/PlayerbotMgr.h +++ b/src/PlayerbotMgr.h @@ -7,6 +7,7 @@ #define _PLAYERBOT_PLAYERBOTMGR_H #include "Common.h" +#include "ObjectGuid.h" #include "Player.h" #include "PlayerbotAIBase.h" #include "QueryHolder.h" @@ -57,6 +58,7 @@ protected: virtual void OnBotLoginInternal(Player* const bot) = 0; PlayerBotMap playerBots; + std::unordered_set botLoading; }; class PlayerbotMgr : public PlayerbotHolder From 5a576cd9a53f4227d95ede297a1a44f9f08ea406 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 19 Aug 2024 23:55:37 +0800 Subject: [PATCH 3/5] Config option ApplyInstanceStrategies --- conf/playerbots.conf.dist | 7 ++- src/PlayerbotAI.cpp | 37 ++++++++++- src/PlayerbotAI.h | 62 +++++++++++-------- src/PlayerbotAIConfig.cpp | 3 +- src/PlayerbotAIConfig.h | 1 + src/RandomItemMgr.cpp | 46 +++++++------- src/RandomItemMgr.h | 3 +- src/factory/PlayerbotFactory.cpp | 36 ++++++----- src/factory/StatsWeightCalculator.cpp | 3 +- src/strategy/actions/MovementActions.cpp | 15 ++--- .../actions/ReviveFromCorpseAction.cpp | 1 - 11 files changed, 133 insertions(+), 81 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 09969ccb..57f5548d 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -369,8 +369,8 @@ AiPlayerbot.SyncQuestForPlayer = 0 # # -# Bot can flee for enemy -AiPlayerbot.FleeingEnabled = 1 +# Auto add dungeon/raid strategies when entering the instance if implemented +AiPlayerbot.ApplyInstanceStrategies = 1 # Enable auto avoid aoe (experimental) # Default: 1 (enable) @@ -388,6 +388,9 @@ AiPlayerbot.AutoSaveMana = 1 # Default: 60 (60%) AiPlayerbot.SaveManaThreshold = 60 +# Bot can flee for enemy +AiPlayerbot.FleeingEnabled = 1 + # # # diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index d319b05f..4fb38ed9 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -136,6 +136,8 @@ PlayerbotAI::PlayerbotAI(Player* bot) engines[BOT_STATE_COMBAT] = AiFactory::createCombatEngine(bot, this, aiObjectContext); engines[BOT_STATE_NON_COMBAT] = AiFactory::createNonCombatEngine(bot, this, aiObjectContext); engines[BOT_STATE_DEAD] = AiFactory::createDeadEngine(bot, this, aiObjectContext); + if (sPlayerbotAIConfig->applyInstanceStrategies) + ApplyInstanceStrategies(bot->GetMapId()); currentEngine = engines[BOT_STATE_NON_COMBAT]; currentState = BOT_STATE_NON_COMBAT; @@ -650,10 +652,11 @@ void PlayerbotAI::HandleTeleportAck() bot->GetSession()->HandleMoveWorldportAck(); } SetNextCheckDelay(urand(2000, 5000)); + if (sPlayerbotAIConfig->applyInstanceStrategies) + ApplyInstanceStrategies(bot->GetMapId(), true); } SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); - Reset(); } @@ -1487,6 +1490,34 @@ std::vector PlayerbotAI::GetStrategies(BotState type) return e->GetStrategies(); } +void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster) +{ + std::string strategyName; + switch (mapId) + { + case 533: + strategyName = "naxx"; + break; + case 603: + strategyName = "uld"; + break; + case 469: + strategyName = "bwl"; + break; + default: + break; + } + + engines[BOT_STATE_COMBAT]->addStrategy(strategyName); + engines[BOT_STATE_NON_COMBAT]->addStrategy(strategyName); + if (tellMaster && !strategyName.empty()) + { + std::ostringstream out; + out << "Add " << strategyName << " instance strategy"; + TellMaster(out.str()); + } +} + bool PlayerbotAI::DoSpecificAction(std::string const name, Event event, bool silent, std::string const qualifier) { std::ostringstream out; @@ -1584,6 +1615,8 @@ void PlayerbotAI::ResetStrategies(bool load) AiFactory::AddDefaultCombatStrategies(bot, this, engines[BOT_STATE_COMBAT]); AiFactory::AddDefaultNonCombatStrategies(bot, this, engines[BOT_STATE_NON_COMBAT]); AiFactory::AddDefaultDeadStrategies(bot, this, engines[BOT_STATE_DEAD]); + if (sPlayerbotAIConfig->applyInstanceStrategies) + ApplyInstanceStrategies(bot->GetMapId()); for (uint8 i = 0; i < BOT_STATE_MAX; i++) engines[i]->Init(); @@ -5736,7 +5769,7 @@ uint32 PlayerbotAI::GetReactDelay() bool isResting = bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); if (!isResting) { - multiplier = urand(5, 20); + multiplier = urand(10, 30); return base * multiplier; } diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index fb76b5cc..61242629 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -129,26 +129,25 @@ enum ChatChannelSource SRC_UNDEFINED }; static std::map ChatChannelSourceStr = { - { SRC_GUILD, "SRC_GUILD"}, - { SRC_WORLD, "SRC_WORLD"}, - { SRC_GENERAL, "SRC_GENERAL"}, - { SRC_TRADE, "SRC_TRADE"}, - { SRC_LOOKING_FOR_GROUP, "SRC_LOOKING_FOR_GROUP"}, - { SRC_LOCAL_DEFENSE, "SRC_LOCAL_DEFENSE"}, - { SRC_WORLD_DEFENSE, "SRC_WORLD_DEFENSE"}, - { SRC_GUILD_RECRUITMENT, "SRC_GUILD_RECRUITMENT"}, + {SRC_GUILD, "SRC_GUILD"}, + {SRC_WORLD, "SRC_WORLD"}, + {SRC_GENERAL, "SRC_GENERAL"}, + {SRC_TRADE, "SRC_TRADE"}, + {SRC_LOOKING_FOR_GROUP, "SRC_LOOKING_FOR_GROUP"}, + {SRC_LOCAL_DEFENSE, "SRC_LOCAL_DEFENSE"}, + {SRC_WORLD_DEFENSE, "SRC_WORLD_DEFENSE"}, + {SRC_GUILD_RECRUITMENT, "SRC_GUILD_RECRUITMENT"}, - { SRC_SAY, "SRC_SAY"}, - { SRC_WHISPER, "SRC_WHISPER"}, - { SRC_EMOTE, "SRC_EMOTE"}, - { SRC_TEXT_EMOTE, "SRC_TEXT_EMOTE"}, - { SRC_YELL, "SRC_YELL"}, + {SRC_SAY, "SRC_SAY"}, + {SRC_WHISPER, "SRC_WHISPER"}, + {SRC_EMOTE, "SRC_EMOTE"}, + {SRC_TEXT_EMOTE, "SRC_TEXT_EMOTE"}, + {SRC_YELL, "SRC_YELL"}, - { SRC_PARTY, "SRC_PARTY"}, - { SRC_RAID, "SRC_RAID"}, + {SRC_PARTY, "SRC_PARTY"}, + {SRC_RAID, "SRC_RAID"}, - { SRC_UNDEFINED, "SRC_UNDEFINED"} -}; + {SRC_UNDEFINED, "SRC_UNDEFINED"}}; enum ChatChannelId { GENERAL = 1, @@ -384,16 +383,18 @@ public: std::string const HandleRemoteCommand(std::string const command); void HandleCommand(uint32 type, std::string const text, Player* fromPlayer); void QueueChatResponse(const ChatQueuedReply reply); - void HandleBotOutgoingPacket(WorldPacket const& packet); + void HandleBotOutgoingPacket(WorldPacket const& packet); void HandleMasterIncomingPacket(WorldPacket const& packet); void HandleMasterOutgoingPacket(WorldPacket const& packet); void HandleTeleportAck(); void ChangeEngine(BotState type); void DoNextAction(bool minimal = false); - virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false, std::string const qualifier = ""); + virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false, + std::string const qualifier = ""); void ChangeStrategy(std::string const name, BotState type); void ClearStrategies(BotState type); std::vector GetStrategies(BotState type); + void ApplyInstanceStrategies(uint32 mapId, bool tellMaster = false); bool ContainsStrategy(StrategyType type); bool HasStrategy(std::string const name, BotState type); BotState GetState() { return currentState; }; @@ -434,8 +435,10 @@ public: bool TellMaster(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); bool TellMaster(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); - bool TellMasterNoFacing(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); - bool TellMasterNoFacing(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + bool TellMasterNoFacing(std::ostringstream& stream, + PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + bool TellMasterNoFacing(std::string const text, + PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); bool TellError(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); bool SayToGuild(const std::string& msg); bool SayToWorld(const std::string& msg); @@ -523,12 +526,16 @@ public: bool AllowActive(ActivityType activityType); bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false); - //Check if player is safe to use. + // Check if player is safe to use. bool IsSafe(Player* player); bool IsSafe(WorldObject* obj); ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName); - bool HasCheat(BotCheatMask mask) { return ((uint32)mask & (uint32)cheatMask) != 0 || ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; } + bool HasCheat(BotCheatMask mask) + { + return ((uint32)mask & (uint32)cheatMask) != 0 || + ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; + } BotCheatMask GetCheat() { return cheatMask; } void SetCheat(BotCheatMask mask) { cheatMask = mask; } @@ -561,9 +568,10 @@ public: std::set GetAllCurrentQuestIds(); std::set GetCurrentIncompleteQuestIds(); void PetFollow(); - + private: - static void _fillGearScoreData(Player* player, Item* item, std::vector* gearScore, uint32& twoHandScore, bool mixed = false); + static void _fillGearScoreData(Player* player, Item* item, std::vector* gearScore, uint32& twoHandScore, + bool mixed = false); bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); void HandleCommands(); @@ -571,8 +579,8 @@ private: protected: Player* bot; - Player* master; - uint32 accountId; + Player* master; + uint32 accountId; AiObjectContext* aiObjectContext; Engine* currentEngine; Engine* engines[BOT_STATE_MAX]; diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 7803fafb..41c0360c 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -286,6 +286,7 @@ bool PlayerbotAIConfig::Initialize() randomBotNonCombatStrategies = sConfigMgr->GetOption("AiPlayerbot.RandomBotNonCombatStrategies", ""); combatStrategies = sConfigMgr->GetOption("AiPlayerbot.CombatStrategies", "+custom::say"); nonCombatStrategies = sConfigMgr->GetOption("AiPlayerbot.NonCombatStrategies", "+custom::say,+return"); + applyInstanceStrategies = sConfigMgr->GetOption("AiPlayerbot.ApplyInstanceStrategies", true); commandPrefix = sConfigMgr->GetOption("AiPlayerbot.CommandPrefix", ""); commandSeparator = sConfigMgr->GetOption("AiPlayerbot.CommandSeparator", "\\\\"); @@ -477,11 +478,11 @@ bool PlayerbotAIConfig::Initialize() { return true; } - PlayerbotFactory::Init(); sRandomItemMgr->Init(); sRandomItemMgr->InitAfterAhBot(); sPlayerbotTextMgr->LoadBotTexts(); sPlayerbotTextMgr->LoadBotTextChance(); + PlayerbotFactory::Init(); if (!sPlayerbotAIConfig->autoDoQuests) { diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index e7fd94cd..21dbee67 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -184,6 +184,7 @@ public: bool summonAtInnkeepersEnabled; std::string combatStrategies, nonCombatStrategies; std::string randomBotCombatStrategies, randomBotNonCombatStrategies; + bool applyInstanceStrategies; uint32 randomBotMinLevel, randomBotMaxLevel; float randomChangeMultiplier; diff --git a/src/RandomItemMgr.cpp b/src/RandomItemMgr.cpp index 7a62891a..2d9f3d5b 100644 --- a/src/RandomItemMgr.cpp +++ b/src/RandomItemMgr.cpp @@ -949,7 +949,6 @@ void RandomItemMgr::BuildItemInfoCache() PlayerbotsDatabaseTransaction trans = PlayerbotsDatabase.BeginTransaction(); - // generate stat weights for classes/specs for (auto const& itr : *itemTemplate) { ItemTemplate const* proto = &itr.second; @@ -958,11 +957,12 @@ void RandomItemMgr::BuildItemInfoCache() // skip non armor/weapon if (proto->Class != ITEM_CLASS_WEAPON && proto->Class != ITEM_CLASS_ARMOR && - proto->Class != ITEM_CLASS_CONTAINER && proto->Class != ITEM_CLASS_PROJECTILE) + proto->Class != ITEM_CLASS_CONTAINER && proto->Class != ITEM_CLASS_PROJECTILE && + proto->Class != ITEM_CLASS_GEM) continue; - if (!CanEquipItemNew(proto)) - continue; + // if (!CanEquipItemNew(proto)) + // continue; // skip test items if (strstr(proto->Name1.c_str(), "(Test)") || strstr(proto->Name1.c_str(), "(TEST)") || @@ -990,29 +990,29 @@ void RandomItemMgr::BuildItemInfoCache() proto->RequiredReputationRank > 0) continue;*/ - if (proto->RequiredHonorRank > 0 || proto->RequiredSkillRank > 0 || proto->RequiredCityRank > 0) - continue; + // if (proto->RequiredHonorRank > 0 || proto->RequiredSkillRank > 0 || proto->RequiredCityRank > 0) + // continue; - // skip random enchant items - if (proto->RandomProperty) - continue; + // // skip random enchant items + // if (proto->RandomProperty) + // continue; - // skip heirloom items - if (proto->Quality == ITEM_QUALITY_HEIRLOOM) - continue; + // // skip heirloom items + // if (proto->Quality == ITEM_QUALITY_HEIRLOOM) + // continue; - // check possible equip slots - EquipmentSlots slot = EQUIPMENT_SLOT_START; - for (std::map >::iterator i = viableSlots.begin(); - i != viableSlots.end(); ++i) - { - std::set slots = viableSlots[(EquipmentSlots)i->first]; - if (slots.find((InventoryType)proto->InventoryType) != slots.end()) - slot = i->first; - } + // // check possible equip slots + // EquipmentSlots slot = EQUIPMENT_SLOT_START; + // for (std::map >::iterator i = viableSlots.begin(); + // i != viableSlots.end(); ++i) + // { + // std::set slots = viableSlots[(EquipmentSlots)i->first]; + // if (slots.find((InventoryType)proto->InventoryType) != slots.end()) + // slot = i->first; + // } - if (slot == EQUIPMENT_SLOT_START) - continue; + // if (slot == EQUIPMENT_SLOT_START) + // continue; // Init Item cache // ItemInfoEntry cacheInfo; diff --git a/src/RandomItemMgr.h b/src/RandomItemMgr.h index 8ce7dc88..110074f1 100644 --- a/src/RandomItemMgr.h +++ b/src/RandomItemMgr.h @@ -8,6 +8,7 @@ #include #include +#include #include #include "AiFactory.h" @@ -203,7 +204,7 @@ private: std::map weightStatLink; std::map weightRatingLink; std::map itemInfoCache; - std::set itemForTest; + std::unordered_set itemForTest; static std::set itemCache; // equipCacheNew[RequiredLevel][InventoryType] std::map>> equipCacheNew; diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 7c969b95..dfe4e757 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -135,15 +135,17 @@ void PlayerbotFactory::Init() { continue; } - if (gemId == 49110) - { // unique gem - continue; - } ItemTemplate const* proto = sObjectMgr->GetItemTemplate(gemId); + + if (proto->ItemLevel < 60) + continue; + if (proto->Flags & ITEM_FLAG_UNIQUE_EQUIPPABLE) - { // unique gem + { continue; } + if (sRandomItemMgr->IsTestItem(gemId)) + continue; if (!proto || !sGemPropertiesStore.LookupEntry(proto->GemProperties)) { continue; @@ -403,7 +405,7 @@ void PlayerbotFactory::Randomize(bool incremental) bot->SetMoney(urand(level * 100000, level * 5 * 100000)); bot->SetHealth(bot->GetMaxHealth()); bot->SetPower(POWER_MANA, bot->GetMaxPower(POWER_MANA)); - bot->SaveToDB(false, false); + // bot->SaveToDB(false, false); LOG_INFO("playerbots", "Initialization Done."); if (pmo) pmo->finish(); @@ -438,7 +440,7 @@ void PlayerbotFactory::Refresh() uint32 money = urand(level * 1000, level * 5 * 1000); if (bot->GetMoney() < money) bot->SetMoney(money); - bot->SaveToDB(false, false); + // bot->SaveToDB(false, false); } void PlayerbotFactory::AddConsumables() @@ -805,17 +807,13 @@ void PlayerbotFactory::ClearSkills() void PlayerbotFactory::ClearEverything() { - bot->SaveToDB(false, false); bot->GiveLevel(bot->getClass() == CLASS_DEATH_KNIGHT ? sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) : sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)); bot->SetUInt32Value(PLAYER_XP, 0); LOG_INFO("playerbots", "Resetting player..."); bot->resetTalents(true); - bot->SaveToDB(false, false); ClearSkills(); - // bot->SaveToDB(false, false); ClearSpells(); - bot->SaveToDB(false, false); ClearInventory(); ResetQuests(); bot->SaveToDB(false, false); @@ -2027,6 +2025,7 @@ void PlayerbotFactory::InitSkills() SetRandomSkill(SKILL_THROWN); bot->SetSkill(SKILL_DUAL_WIELD, 0, dualWieldLevel, dualWieldLevel); bot->SetSkill(SKILL_PLATE_MAIL, 0, skillLevel, skillLevel); + bot->SetCanDualWield(dualWieldLevel); break; case CLASS_PALADIN: SetRandomSkill(SKILL_SWORDS); @@ -2079,8 +2078,9 @@ void PlayerbotFactory::InitSkills() SetRandomSkill(SKILL_POLEARMS); SetRandomSkill(SKILL_FIST_WEAPONS); SetRandomSkill(SKILL_THROWN); - bot->SetSkill(SKILL_MAIL, 0, skillLevel, skillLevel); bot->SetSkill(SKILL_DUAL_WIELD, 0, dualWieldLevel, dualWieldLevel); + bot->SetSkill(SKILL_MAIL, 0, skillLevel, skillLevel); + bot->SetCanDualWield(dualWieldLevel); break; case CLASS_ROGUE: SetRandomSkill(SKILL_SWORDS); @@ -2093,6 +2093,7 @@ void PlayerbotFactory::InitSkills() SetRandomSkill(SKILL_FIST_WEAPONS); SetRandomSkill(SKILL_THROWN); bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1); + bot->SetCanDualWield(true); break; case CLASS_DEATH_KNIGHT: SetRandomSkill(SKILL_SWORDS); @@ -2103,6 +2104,7 @@ void PlayerbotFactory::InitSkills() SetRandomSkill(SKILL_2H_AXES); SetRandomSkill(SKILL_POLEARMS); bot->SetSkill(SKILL_DUAL_WIELD, 0, dualWieldLevel, dualWieldLevel); + bot->SetCanDualWield(dualWieldLevel); break; default: break; @@ -2572,7 +2574,6 @@ void PlayerbotFactory::InitInstanceQuests() ClearInventory(); bot->SetUInt32Value(PLAYER_XP, currentXP); - bot->SaveToDB(false, false); } void PlayerbotFactory::ClearInventory() @@ -3329,7 +3330,7 @@ void PlayerbotFactory::InitGuild() if (bot->GetGuildId()) return; - bot->SaveToDB(false, false); + // bot->SaveToDB(false, false); // add guild tabard if (bot->GetGuildId() && !bot->HasItemCount(5976, 1)) @@ -3365,7 +3366,7 @@ void PlayerbotFactory::InitGuild() if (bot->GetGuildId() && bot->GetLevel() > 9 && urand(0, 4) && !bot->HasItemCount(5976, 1)) StoreItem(5976, 1); - bot->SaveToDB(false, false); + // bot->SaveToDB(false, false); } void PlayerbotFactory::InitImmersive() @@ -3554,7 +3555,7 @@ void PlayerbotFactory::InitArenaTeam() arenateams.erase(arenateams.begin() + index); } - bot->SaveToDB(false, false); + // bot->SaveToDB(false, false); } void PlayerbotFactory::ApplyEnchantTemplate() @@ -3670,6 +3671,9 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) if (!gemProperties) continue; + if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 70 && enchantGem >= 39900) + continue; + uint32 requiredLevel = gemTemplate->ItemLevel; if (requiredLevel > bot->GetLevel()) diff --git a/src/factory/StatsWeightCalculator.cpp b/src/factory/StatsWeightCalculator.cpp index 6f6166e1..543de321 100644 --- a/src/factory/StatsWeightCalculator.cpp +++ b/src/factory/StatsWeightCalculator.cpp @@ -431,7 +431,8 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto) // spec with double hand // fury without duel wield, arms, bear, retribution, blood dk if (isDoubleHand && - ((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) || + ((cls == CLASS_HUNTER && !player_->CanDualWield()) || + (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) || (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) || (cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) || (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) || diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index cf51e144..8c5eccb1 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -197,6 +197,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, { VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot); Unit* vehicleBase = vehicle->GetBase(); + generatePath = vehicleBase->CanFly(); if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway return false; @@ -815,7 +816,6 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance) if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD)) // target is moving forward, predict the position { - float needToGo = bot->GetExactDist(target) - distance; float timeToGo = MoveDelay(abs(needToGo)) + sPlayerbotAIConfig->reactDelay / 1000.0f; float targetMoveDist = timeToGo * target->GetSpeed(MOVE_RUN); @@ -848,7 +848,8 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance) return false; path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), distance); G3D::Vector3 endPos = path.GetPath().back(); - return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); } float MovementAction::GetFollowAngle() @@ -893,7 +894,7 @@ bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z) // removed sqrt as means distance limit was effectively 22500 (ReactDistance�) // leaving it commented incase we find ReactDistance limit causes problems // float distance = sqrt(bot->GetDistance(x, y, z)); - + // Remove react distance limit // if (!bot->InBattleground()) // return false; @@ -924,7 +925,6 @@ bool MovementAction::IsWaitingForLastMove(MovementPriority priority) if (lastMove.lastdelayTime + lastMove.msTime > getMSTime()) return true; - return false; } @@ -1516,7 +1516,7 @@ bool MovementAction::MoveAway(Unit* target) float dz = bot->GetPositionZ(); bool exact = true; if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), dx, dy, dz)) + bot->GetPositionZ(), dx, dy, dz)) { // disable prediction if position is invalid dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance; @@ -1538,7 +1538,7 @@ bool MovementAction::MoveAway(Unit* target) dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance; dz = bot->GetPositionZ(); if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), dx, dy, dz)) + bot->GetPositionZ(), dx, dy, dz)) { // disable prediction if position is invalid dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance; @@ -2403,7 +2403,8 @@ bool MoveInsideAction::Execute(Event event) { return MoveInside(bot->GetMapId(), bool RotateAroundTheCenterPointAction::Execute(Event event) { uint32 next_point = GetCurrWaypoint(); - if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), false, + false, false, false, MovementPriority::MOVEMENT_COMBAT)) { call_counters += 1; return true; diff --git a/src/strategy/actions/ReviveFromCorpseAction.cpp b/src/strategy/actions/ReviveFromCorpseAction.cpp index 1022beb5..4f522104 100644 --- a/src/strategy/actions/ReviveFromCorpseAction.cpp +++ b/src/strategy/actions/ReviveFromCorpseAction.cpp @@ -319,7 +319,6 @@ bool SpiritHealerAction::Execute(Event event) PlayerbotChatHandler ch(bot); bot->ResurrectPlayer(0.5f); bot->SpawnCorpseBones(); - bot->SaveToDB(false, false); context->GetValue("current target")->Set(nullptr); bot->SetTarget(); botAI->TellMaster("Hello"); From 6d9aba406694617a040169b2257636ba72761dca Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 20 Aug 2024 00:19:50 +0800 Subject: [PATCH 4/5] SaveToDB in randomize --- src/PlayerbotMgr.cpp | 4 ++-- src/factory/PlayerbotFactory.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 097e0bf1..46f884f8 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -381,7 +381,7 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid) LOG_DEBUG("playerbots", "Bot {} logged out", bot->GetName().c_str()); - // bot->SaveToDB(false, false); + bot->SaveToDB(false, false); if (botAI->GetAiObjectContext()) // Maybe some day re-write to delate all pointer values. { @@ -534,7 +534,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) bot->RemovePlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); } - // bot->SaveToDB(false, false); + bot->SaveToDB(false, false); if (master && isRandomAccount && master->GetLevel() < bot->GetLevel()) { // PlayerbotFactory factory(bot, master->GetLevel()); diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index dfe4e757..511d92a0 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -405,7 +405,7 @@ void PlayerbotFactory::Randomize(bool incremental) bot->SetMoney(urand(level * 100000, level * 5 * 100000)); bot->SetHealth(bot->GetMaxHealth()); bot->SetPower(POWER_MANA, bot->GetMaxPower(POWER_MANA)); - // bot->SaveToDB(false, false); + bot->SaveToDB(false, false); LOG_INFO("playerbots", "Initialization Done."); if (pmo) pmo->finish(); From 84d65cc136d513bc00324336693fde609ad05e6b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 20 Aug 2024 00:40:52 +0800 Subject: [PATCH 5/5] Fix flame leviathan chasing --- src/strategy/raids/ulduar/RaidUlduarActions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.cpp b/src/strategy/raids/ulduar/RaidUlduarActions.cpp index 2a230ca6..bef3e3ef 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarActions.cpp @@ -46,7 +46,7 @@ bool FlameLeviathanVehicleAction::Execute(Event event) continue; if (unit->GetEntry() == 33142) // Leviathan Defense Turret continue; - if (unit->GetEntry() == 33133) // Flame Leviathan + if (unit->GetEntry() == 33113) // Flame Leviathan flame = unit; if (!target || bot->GetExactDist(target) > bot->GetExactDist(unit)) { @@ -58,7 +58,7 @@ bool FlameLeviathanVehicleAction::Execute(Event event) // Flame Leviathan is chasing me if (flame && flame->GetVictim() == vehicleBase_) - if (MoveAvoidChasing(target)) + if (MoveAvoidChasing(flame)) return true; uint32 entry = vehicleBase_->GetEntry(); @@ -69,7 +69,7 @@ bool FlameLeviathanVehicleAction::Execute(Event event) case NPC_SALVAGED_DEMOLISHER_TURRET: return DemolisherTurretAction(target); case NPC_SALVAGED_SIEGE_ENGINE: - return SiegeEngineAction(target); + return SiegeEngineAction(flame ? flame : target); case NPC_SALVAGED_SIEGE_ENGINE_TURRET: return SiegeEngineTurretAction(target); case NPC_VEHICLE_CHOPPER: