mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Improve combat reach and dps target, allowing spell interruption
This commit is contained in:
@@ -310,24 +310,22 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
bot->SetPower(bot->getPowerType(), bot->GetMaxPower(bot->getPowerType()));
|
bot->SetPower(bot->getPowerType(), bot->GetMaxPower(bot->getPowerType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CanUpdateAI())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// check activity
|
|
||||||
AllowActivity();
|
AllowActivity();
|
||||||
|
|
||||||
// if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
||||||
if (currentSpell && currentSpell->getState() == SPELL_STATE_CASTING && currentSpell->GetCastTime())
|
if (currentSpell && currentSpell->getState() == SPELL_STATE_PREPARING)
|
||||||
{
|
{
|
||||||
nextAICheckDelay = currentSpell->GetCastTime() + sPlayerbotAIConfig->reactDelay;
|
if (currentSpell->m_targets.GetUnitTarget() && !currentSpell->m_targets.GetUnitTarget()->IsAlive())
|
||||||
SetNextCheckDelay(nextAICheckDelay);
|
{
|
||||||
if (!CanUpdateAI())
|
bot->InterruptSpell(CURRENT_GENERIC_SPELL);
|
||||||
return;
|
SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!CanUpdateAI())
|
||||||
|
return;
|
||||||
|
|
||||||
if (!bot->InBattleground() && !bot->inRandomLfgDungeon() && bot->GetGroup())
|
if (!bot->InBattleground() && !bot->inRandomLfgDungeon() && bot->GetGroup())
|
||||||
{
|
{
|
||||||
Player* leader = bot->GetGroup()->GetLeader();
|
Player* leader = bot->GetGroup()->GetLeader();
|
||||||
@@ -898,9 +896,9 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
|||||||
p >> casterGuid.ReadAsPacked();
|
p >> casterGuid.ReadAsPacked();
|
||||||
if (casterGuid != bot->GetGUID())
|
if (casterGuid != bot->GetGUID())
|
||||||
return;
|
return;
|
||||||
|
uint8 count, result;
|
||||||
uint32 spellId;
|
uint32 spellId;
|
||||||
p >> spellId;
|
p >> count >> spellId >> result;
|
||||||
SpellInterrupted(spellId);
|
SpellInterrupted(spellId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1135,21 +1133,15 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
|||||||
|
|
||||||
void PlayerbotAI::SpellInterrupted(uint32 spellid)
|
void PlayerbotAI::SpellInterrupted(uint32 spellid)
|
||||||
{
|
{
|
||||||
|
for (uint8 type = CURRENT_MELEE_SPELL; type < CURRENT_CHANNELED_SPELL; type++)
|
||||||
|
{
|
||||||
|
Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type);
|
||||||
|
if (!spell)
|
||||||
|
continue;
|
||||||
|
if (spell->GetSpellInfo()->Id == spellid)
|
||||||
|
bot->InterruptSpell((CurrentSpellTypes)type);
|
||||||
|
}
|
||||||
LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
|
LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
|
||||||
if (!spellid || lastSpell.id != spellid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
time_t now = time(nullptr);
|
|
||||||
if (now <= lastSpell.timer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32 castTimeSpent = 1000 * (now - lastSpell.timer);
|
|
||||||
int32 globalCooldown = CalculateGlobalCooldown(lastSpell.id);
|
|
||||||
if (static_cast<int32>(castTimeSpent) < globalCooldown)
|
|
||||||
SetNextCheckDelay(globalCooldown - castTimeSpent);
|
|
||||||
else
|
|
||||||
SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
|
||||||
|
|
||||||
lastSpell.id = 0;
|
lastSpell.id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1513,14 +1505,15 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (strategyName.empty())
|
||||||
|
return;
|
||||||
engines[BOT_STATE_COMBAT]->addStrategy(strategyName);
|
engines[BOT_STATE_COMBAT]->addStrategy(strategyName);
|
||||||
engines[BOT_STATE_NON_COMBAT]->addStrategy(strategyName);
|
engines[BOT_STATE_NON_COMBAT]->addStrategy(strategyName);
|
||||||
if (tellMaster && !strategyName.empty())
|
if (tellMaster && !strategyName.empty())
|
||||||
{
|
{
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "Add " << strategyName << " instance strategy";
|
out << "Add " << strategyName << " instance strategy";
|
||||||
TellMaster(out.str());
|
TellMasterNoFacing(out.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3617,6 +3610,7 @@ bool PlayerbotAI::IsInVehicle(bool canControl, bool canCast, bool canAttack, boo
|
|||||||
|
|
||||||
void PlayerbotAI::WaitForSpellCast(Spell* spell)
|
void PlayerbotAI::WaitForSpellCast(Spell* spell)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||||
uint32 castTime = spell->GetCastTime();
|
uint32 castTime = spell->GetCastTime();
|
||||||
// float castTime = spell->GetCastTime();
|
// float castTime = spell->GetCastTime();
|
||||||
|
|||||||
@@ -3880,7 +3880,7 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld)
|
|||||||
}
|
}
|
||||||
availableGems.push_back(enchantGem);
|
availableGems.push_back(enchantGem);
|
||||||
}
|
}
|
||||||
|
StatsWeightCalculator calculator(bot);
|
||||||
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot)
|
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot)
|
||||||
{
|
{
|
||||||
if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY)
|
if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY)
|
||||||
@@ -3940,7 +3940,6 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld)
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
StatsWeightCalculator calculator(bot);
|
|
||||||
float score = calculator.CalculateEnchant(enchant_id);
|
float score = calculator.CalculateEnchant(enchant_id);
|
||||||
if (score >= bestScore)
|
if (score >= bestScore)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -814,39 +814,25 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
|||||||
float combatDistance = bot->GetCombatReach() + target->GetCombatReach();
|
float combatDistance = bot->GetCombatReach() + target->GetCombatReach();
|
||||||
distance += combatDistance;
|
distance += combatDistance;
|
||||||
|
|
||||||
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);
|
|
||||||
targetMoveDist = std::min(5.0f, targetMoveDist);
|
|
||||||
tx += targetMoveDist * cos(target->GetOrientation());
|
|
||||||
ty += targetMoveDist * sin(target->GetOrientation());
|
|
||||||
if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(),
|
|
||||||
target->GetPositionZ(), tx, ty, tz))
|
|
||||||
{
|
|
||||||
// disable prediction if position is invalid
|
|
||||||
tx = target->GetPositionX();
|
|
||||||
ty = target->GetPositionY();
|
|
||||||
tz = target->GetPositionZ();
|
|
||||||
}
|
|
||||||
// Prediction may cause this, which makes ShortenPathUntilDist fail
|
|
||||||
if (bot->GetExactDist(tx, ty, tz) <= distance)
|
|
||||||
{
|
|
||||||
tx = target->GetPositionX();
|
|
||||||
ty = target->GetPositionY();
|
|
||||||
tz = target->GetPositionZ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (bot->GetExactDist(tx, ty, tz) <= distance)
|
if (bot->GetExactDist(tx, ty, tz) <= distance)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PathGenerator path(bot);
|
PathGenerator path(bot);
|
||||||
path.CalculatePath(tx, ty, tz, false);
|
path.CalculatePath(tx, ty, tz, false);
|
||||||
PathType type = path.GetPathType();
|
PathType type = path.GetPathType();
|
||||||
int typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE;
|
int typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE;
|
||||||
if (!(type & typeOk))
|
if (!(type & typeOk))
|
||||||
return false;
|
return false;
|
||||||
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), distance);
|
float shortenTo = distance;
|
||||||
|
|
||||||
|
// Avoid walking too far when moving towards each other
|
||||||
|
if (bot->GetDistance(tx, ty, tz) >= 10.0f)
|
||||||
|
shortenTo = std::max(distance, bot->GetDistance(tx, ty, tz) / 2);
|
||||||
|
|
||||||
|
if (bot->GetExactDist(tx, ty, tz) <= shortenTo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), shortenTo);
|
||||||
G3D::Vector3 endPos = path.GetPath().back();
|
G3D::Vector3 endPos = path.GetPath().back();
|
||||||
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false,
|
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT);
|
MovementPriority::MOVEMENT_COMBAT);
|
||||||
|
|||||||
@@ -29,13 +29,14 @@ bool TellAttackersAction::Execute(Event event)
|
|||||||
botAI->TellMaster("--- Attackers ---");
|
botAI->TellMaster("--- Attackers ---");
|
||||||
|
|
||||||
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
|
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
|
||||||
|
int32 count = 0;
|
||||||
for (ObjectGuid const guid : attackers)
|
for (ObjectGuid const guid : attackers)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(guid);
|
Unit* unit = botAI->GetUnit(guid);
|
||||||
if (!unit || !unit->IsAlive())
|
if (!unit || !unit->IsAlive())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
botAI->TellMaster(unit->GetName());
|
botAI->TellMaster(std::to_string(++count) + std::string(".") + unit->GetName());
|
||||||
}
|
}
|
||||||
|
|
||||||
botAI->TellMaster("--- Threat ---");
|
botAI->TellMaster("--- Threat ---");
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public:
|
|||||||
CasterFindTargetSmartStrategy(PlayerbotAI* botAI, float dps)
|
CasterFindTargetSmartStrategy(PlayerbotAI* botAI, float dps)
|
||||||
: FindTargetStrategy(botAI), dps_(dps), targetExpectedLifeTime(1000000)
|
: FindTargetStrategy(botAI), dps_(dps), targetExpectedLifeTime(1000000)
|
||||||
{
|
{
|
||||||
|
result = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
|
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
|
||||||
@@ -86,13 +87,15 @@ public:
|
|||||||
{
|
{
|
||||||
float new_time = new_unit->GetHealth() / dps_;
|
float new_time = new_unit->GetHealth() / dps_;
|
||||||
float old_time = old_unit->GetHealth() / dps_;
|
float old_time = old_unit->GetHealth() / dps_;
|
||||||
// [5-20] > (5-0] > (20-inf)
|
// [5-30] > (5-0] > (20-inf)
|
||||||
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit))
|
int new_level = GetIntervalLevel(new_unit);
|
||||||
|
int old_level = GetIntervalLevel(old_unit);
|
||||||
|
if (new_level != old_level)
|
||||||
{
|
{
|
||||||
return true;
|
return new_level > old_level;
|
||||||
}
|
}
|
||||||
int32_t level = GetIntervalLevel(new_unit);
|
int32_t level = new_level;
|
||||||
if (level % 10 == 2 || level % 10 == 1)
|
if (level % 10 == 2 || level % 10 == 0)
|
||||||
{
|
{
|
||||||
return new_time < old_time;
|
return new_time < old_time;
|
||||||
}
|
}
|
||||||
@@ -116,15 +119,15 @@ public:
|
|||||||
botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance;
|
botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance;
|
||||||
attackRange += 5.0f;
|
attackRange += 5.0f;
|
||||||
int level = dis < attackRange ? 10 : 0;
|
int level = dis < attackRange ? 10 : 0;
|
||||||
if (time >= 3 && time <= 20)
|
if (time >= 5 && time <= 30)
|
||||||
{
|
{
|
||||||
return level + 2;
|
return level + 2;
|
||||||
}
|
}
|
||||||
if (time > 20)
|
if (time > 30)
|
||||||
{
|
{
|
||||||
return level + 1;
|
return level;
|
||||||
}
|
}
|
||||||
return level;
|
return level + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -176,12 +179,14 @@ public:
|
|||||||
float new_time = new_unit->GetHealth() / dps_;
|
float new_time = new_unit->GetHealth() / dps_;
|
||||||
float old_time = old_unit->GetHealth() / dps_;
|
float old_time = old_unit->GetHealth() / dps_;
|
||||||
// [5-20] > (5-0] > (20-inf)
|
// [5-20] > (5-0] > (20-inf)
|
||||||
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit))
|
int new_level = GetIntervalLevel(new_unit);
|
||||||
|
int old_level = GetIntervalLevel(old_unit);
|
||||||
|
if (new_level != old_level)
|
||||||
{
|
{
|
||||||
return true;
|
return new_level > old_level;
|
||||||
}
|
}
|
||||||
// attack enemy in range and with lowest health
|
// attack enemy in range and with lowest health
|
||||||
int level = GetIntervalLevel(new_unit);
|
int level = new_level;
|
||||||
if (level == 10)
|
if (level == 10)
|
||||||
{
|
{
|
||||||
return new_time < old_time;
|
return new_time < old_time;
|
||||||
@@ -249,12 +254,14 @@ public:
|
|||||||
float new_time = new_unit->GetHealth() / dps_;
|
float new_time = new_unit->GetHealth() / dps_;
|
||||||
float old_time = old_unit->GetHealth() / dps_;
|
float old_time = old_unit->GetHealth() / dps_;
|
||||||
// [5-20] > (5-0] > (20-inf)
|
// [5-20] > (5-0] > (20-inf)
|
||||||
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit))
|
int new_level = GetIntervalLevel(new_unit);
|
||||||
|
int old_level = GetIntervalLevel(old_unit);
|
||||||
|
if (new_level != old_level)
|
||||||
{
|
{
|
||||||
return true;
|
return new_level > old_level;
|
||||||
}
|
}
|
||||||
// attack enemy in range and with lowest health
|
// attack enemy in range and with lowest health
|
||||||
int level = GetIntervalLevel(new_unit);
|
int level = new_level;
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (level == 10)
|
if (level == 10)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user