Found the problem with the ^attack command. The routine to check for LOS actually checks for a lot more than that, and then clears the HateList if any of those conditions are met. So the ^attack command is setting the HateList only to have it cleared on the next pass through the AI routine.
Here is the relevant section of code from zone/bot.cpp.
Code:
// Let's check if we have a los with our target.
// If we don't, our hate_list is wiped.
// Else, it was causing the bot to aggro behind wall etc... causing massive trains.
if (guard_mode ||
!tar->IsNPC() ||
tar->IsMezzed() ||
(!tar->GetHateAmount(this) && !tar->GetHateAmount(leash_owner) && !leash_owner->AutoAttackEnabled()) ||
lo_distance > BOT_LEASH_DISTANCE ||
tar_distance > BOT_LEASH_DISTANCE ||
(!CheckLosFN(tar) && !leash_owner->CheckLosFN(tar)) ||
!IsAttackAllowed(tar))
{
if (HasPet()) {
GetPet()->RemoveFromHateList(tar);
GetPet()->SetTarget(nullptr);
}
RemoveFromHateList(tar);
SetTarget(nullptr);
if (IsMoving())
StopMoving();
return;
}
Let's look at those top 4 conditions in the IF statement that leads to the hatelist being wiped...
1. GUARDMODE - This is why bots turn into mannequins in guard mode. I suppose you might not want them to move, but clearing their hatelist here is causing them to not fight at all.
2. !tar->IsNPC() - The target is not an NPC. This is the only one that I would leave in here.
3. tar->IsMezzed() - The target is mezzed. I want to be able to tell my bots to attack a mezzed creature. When you first cast mez on something, you might want to clear it from the bots HateList then so they will stop attacking when the mez is cast during combat, but I wouldn't do it in this AI routine.
4. (!tar->GetHateAmount(this) && !tar->GetHateAmount(leash_owner) && !leash_owner->AutoAttackEnabled()) - This one is the big problem. If the target does not already have hate against us AND the bot owners autoattack isn't on, then it wipes the bot's HateList. This is the condition that is undoing what the ^attack command does.
I commented out conditions 1,3 & 4 and the ^attack command starting working as intended. For anyone who wants to do this in your own environment, you can cut and paste the whole thing or just add the comment brackets that are highlighted in blue.
Working code:
Code:
// Let's check if we have a los with our target.
// If we don't, our hate_list is wiped.
// Else, it was causing the bot to aggro behind wall etc... causing massive trains.
if ( /*guard_mode || */
!tar->IsNPC() ||
/* tar->IsMezzed() || */
/* (!tar->GetHateAmount(this) && !tar->GetHateAmount(leash_owner) && !leash_owner->AutoAttackEnabled()) || */
lo_distance > BOT_LEASH_DISTANCE ||
tar_distance > BOT_LEASH_DISTANCE ||
(!CheckLosFN(tar) && !leash_owner->CheckLosFN(tar)) ||
!IsAttackAllowed(tar))
{
if (HasPet()) {
GetPet()->RemoveFromHateList(tar);
GetPet()->SetTarget(nullptr);
}
RemoveFromHateList(tar);
SetTarget(nullptr);
if (IsMoving())
StopMoving();
return;
}