Improve combat reach and dps target, allowing spell interruption

This commit is contained in:
Yunfan Li
2024-09-06 12:33:54 +08:00
parent 73f699fe89
commit 927d893945
5 changed files with 60 additions and 73 deletions

View File

@@ -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);
SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
}
return; 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();

View File

@@ -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)
{ {

View File

@@ -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);

View File

@@ -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 ---");

View File

@@ -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,16 +119,16 @@ 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:
float dps_; float dps_;
@@ -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)
{ {