mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 00:58:33 +00:00
Fix: Stop pets from fighting in PVP prohibited zones (#1829)
Stripped down version of #1818. No new features. Refactors IsPossibleTarget in AttackersValue.cpp to a better style and makes sure pets don't attack in prohibited zones. Testing: Confirmed that aggro pets no longer attack in PVP prohibited areas, but still do outside them. Zim'Torga in Zul'Drak is a good example to test this (ID 4323). Lookout for death knights with a Risen Ally (uncontrolled and naturally aggro) now they respect PVP prohibition like their master. Note: If you manually teleport a bot that is in mid combat to a PVP prohibited area, its aggro pet might still attack, because its master is still in combat strategy. Otherwise the pet will not attack if its master has switched to non-combat.
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
DELETE FROM ai_playerbot_texts WHERE name IN (
|
||||
'pet_usage_error',
|
||||
'pet_no_pet_error',
|
||||
'pet_stance_report',
|
||||
'pet_no_target_error',
|
||||
'pet_target_dead_error',
|
||||
'pet_invalid_target_error',
|
||||
'pet_pvp_prohibited_error',
|
||||
'pet_attack_success',
|
||||
'pet_attack_failed',
|
||||
'pet_follow_success',
|
||||
'pet_stay_success',
|
||||
'pet_unknown_command_error',
|
||||
'pet_stance_set_success',
|
||||
'pet_type_pet',
|
||||
'pet_type_guardian',
|
||||
'pet_stance_aggressive',
|
||||
'pet_stance_defensive',
|
||||
'pet_stance_passive',
|
||||
'pet_stance_unknown'
|
||||
);
|
||||
|
||||
DELETE FROM ai_playerbot_texts_chance WHERE name IN (
|
||||
'pet_usage_error',
|
||||
'pet_no_pet_error',
|
||||
'pet_stance_report',
|
||||
'pet_no_target_error',
|
||||
'pet_target_dead_error',
|
||||
'pet_invalid_target_error',
|
||||
'pet_pvp_prohibited_error',
|
||||
'pet_attack_success',
|
||||
'pet_attack_failed',
|
||||
'pet_follow_success',
|
||||
'pet_stay_success',
|
||||
'pet_unknown_command_error',
|
||||
'pet_stance_set_success',
|
||||
'pet_type_pet',
|
||||
'pet_type_guardian',
|
||||
'pet_stance_aggressive',
|
||||
'pet_stance_defensive',
|
||||
'pet_stance_passive',
|
||||
'pet_stance_unknown'
|
||||
);
|
||||
|
||||
INSERT INTO ai_playerbot_texts (id, name, text, say_type, reply_type, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8) VALUES
|
||||
(1717, 'pet_usage_error', "Usage: pet <aggressive|defensive|passive|stance|attack|follow|stay>", 0, 0,
|
||||
"사용법: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Utilisation: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Verwendung: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Использование: pet <aggressive|defensive|passive|stance|attack|follow|stay>"),
|
||||
|
||||
(1718, 'pet_no_pet_error', "You have no pet or guardian pet.", 0, 0,
|
||||
"펫이나 수호자 펫이 없습니다.",
|
||||
"Vous n'avez pas de familier ou gardien.",
|
||||
"Du hast kein Tier oder Wächter.",
|
||||
"你没有宠物或守护者宠物。",
|
||||
"你沒有寵物或守護者寵物。",
|
||||
"No tienes mascota o mascota guardián.",
|
||||
"No tienes mascota o mascota guardián.",
|
||||
"У вас нет питомца или защитника."),
|
||||
|
||||
(1719, 'pet_stance_report', "Current stance of %type \"%name\": %stance.", 0, 0,
|
||||
"%type \"%name\"의 현재 태세: %stance.",
|
||||
"Position actuelle du %type \"%name\": %stance.",
|
||||
"Aktuelle Haltung des %type \"%name\": %stance.",
|
||||
"%type \"%name\" 的当前姿态: %stance。",
|
||||
"%type \"%name\" 的當前姿態: %stance。",
|
||||
"Postura actual del %type \"%name\": %stance.",
|
||||
"Postura actual del %type \"%name\": %stance.",
|
||||
"Текущая позиция %type \"%name\": %stance."),
|
||||
|
||||
(1720, 'pet_no_target_error', "No valid target selected by master.", 0, 0,
|
||||
"주인이 유효한 대상을 선택하지 않았습니다.",
|
||||
"Aucune cible valide sélectionnée par le maître.",
|
||||
"Kein gültiges Ziel vom Meister ausgewählt.",
|
||||
"主人未选择有效目标。",
|
||||
"主人未選擇有效目標。",
|
||||
"No hay objetivo válido seleccionado por el maestro.",
|
||||
"No hay objetivo válido seleccionado por el maestro.",
|
||||
"Хозяин не выбрал действительную цель."),
|
||||
|
||||
(1721, 'pet_target_dead_error', "Target is not alive.", 0, 0,
|
||||
"대상이 살아있지 않습니다.",
|
||||
"La cible n'est pas vivante.",
|
||||
"Das Ziel ist nicht am Leben.",
|
||||
"目标未存活。",
|
||||
"目標未存活。",
|
||||
"El objetivo no está vivo.",
|
||||
"El objetivo no está vivo.",
|
||||
"Цель не жива."),
|
||||
|
||||
(1722, 'pet_invalid_target_error', "Target is not a valid attack target for the bot.", 0, 0,
|
||||
"대상이 봇에게 유효한 공격 대상이 아닙니다.",
|
||||
"La cible n'est pas une cible d'attaque valide pour le bot.",
|
||||
"Das Ziel ist kein gültiges Angriffsziel für den Bot.",
|
||||
"目标不是机器人的有效攻击目标。",
|
||||
"目標不是機器人的有效攻擊目標。",
|
||||
"El objetivo no es un objetivo de ataque válido para el bot.",
|
||||
"El objetivo no es un objetivo de ataque válido para el bot.",
|
||||
"Цель не является допустимой целью атаки для бота."),
|
||||
|
||||
(1723, 'pet_pvp_prohibited_error', "I cannot command my pet to attack players in PvP prohibited areas.", 0, 0,
|
||||
"PvP 금지 지역에서는 펫에게 플레이어 공격 명령을 내릴 수 없습니다.",
|
||||
"Je ne peux pas commander à mon familier d'attaquer des joueurs dans les zones où le PvP est interdit.",
|
||||
"Ich kann meinem Tier nicht befehlen, Spieler in PvP-verbotenen Gebieten anzugreifen.",
|
||||
"我不能命令我的宠物在禁止PvP的区域攻击玩家。",
|
||||
"我不能命令我的寵物在禁止PvP的區域攻擊玩家。",
|
||||
"No puedo ordenar a mi mascota atacar jugadores en áreas donde el PvP está prohibido.",
|
||||
"No puedo ordenar a mi mascota atacar jugadores en áreas donde el PvP está prohibido.",
|
||||
"Я не могу приказать своему питомцу атаковать игроков в зонах, где PvP запрещено."),
|
||||
|
||||
(1724, 'pet_attack_success', "Pet commanded to attack your target.", 0, 0,
|
||||
"펫이 당신의 대상을 공격하도록 명령했습니다.",
|
||||
"Le familier a reçu l'ordre d'attaquer votre cible.",
|
||||
"Tier wurde befohlen, dein Ziel anzugreifen.",
|
||||
"宠物已命令攻击你的目标。",
|
||||
"寵物已命令攻擊你的目標。",
|
||||
"Mascota ordenada a atacar tu objetivo.",
|
||||
"Mascota ordenada a atacar tu objetivo.",
|
||||
"Питомцу приказано атаковать вашу цель."),
|
||||
|
||||
(1725, 'pet_attack_failed', "Pet did not attack. (Already attacking or unable to attack target)", 0, 0,
|
||||
"펫이 공격하지 않았습니다. (이미 공격 중이거나 대상 공격 불가)",
|
||||
"Le familier n'a pas attaqué. (Attaque déjà en cours ou impossible d'attaquer la cible)",
|
||||
"Tier hat nicht angegriffen. (Greift bereits an oder kann Ziel nicht angreifen)",
|
||||
"宠物未攻击。(已在攻击或无法攻击目标)",
|
||||
"寵物未攻擊。(已在攻擊或無法攻擊目標)",
|
||||
"La mascota no atacó. (Ya está atacando o no puede atacar al objetivo)",
|
||||
"La mascota no atacó. (Ya está atacando o no puede atacar al objetivo)",
|
||||
"Питомец не атаковал. (Уже атакует или не может атаковать цель)"),
|
||||
|
||||
(1726, 'pet_follow_success', "Pet commanded to follow.", 0, 0,
|
||||
"펫이 따라오도록 명령했습니다.",
|
||||
"Le familier a reçu l'ordre de suivre.",
|
||||
"Tier wurde befohlen zu folgen.",
|
||||
"宠物已命令跟随。",
|
||||
"寵物已命令跟隨。",
|
||||
"Mascota ordenada a seguir.",
|
||||
"Mascota ordenada a seguir.",
|
||||
"Питомцу приказано следовать."),
|
||||
|
||||
(1727, 'pet_stay_success', "Pet commanded to stay.", 0, 0,
|
||||
"펫이 머물도록 명령했습니다.",
|
||||
"Le familier a reçu l'ordre de rester.",
|
||||
"Tier wurde befohlen zu bleiben.",
|
||||
"宠物已命令停留。",
|
||||
"寵物已命令停留。",
|
||||
"Mascota ordenada a quedarse.",
|
||||
"Mascota ordenada a quedarse.",
|
||||
"Питомцу приказано остаться."),
|
||||
|
||||
(1728, 'pet_unknown_command_error', "Unknown pet command: %param. Use: pet <aggressive|defensive|passive|stance|attack|follow|stay>", 0, 0,
|
||||
"알 수 없는 펫 명령: %param. 사용법: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Commande de familier inconnue: %param. Utilisation: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Unbekannter Tierbefehl: %param. Verwendung: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"未知宠物命令: %param。用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"未知寵物命令: %param。用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Comando de mascota desconocido: %param. Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Comando de mascota desconocido: %param. Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
"Неизвестная команда питомца: %param. Использование: pet <aggressive|defensive|passive|stance|attack|follow|stay>"),
|
||||
|
||||
(1729, 'pet_stance_set_success', "Pet stance set to %stance.", 0, 0,
|
||||
"펫 태세가 %stance(으)로 설정되었습니다.",
|
||||
"Position du familier définie sur %stance.",
|
||||
"Tierhaltung auf %stance gesetzt.",
|
||||
"宠物姿态设置为 %stance。",
|
||||
"寵物姿態設置為 %stance。",
|
||||
"Postura de mascota establecida en %stance.",
|
||||
"Postura de mascota establecida en %stance.",
|
||||
"Позиция питомца установлена на %stance."),
|
||||
|
||||
(1730, 'pet_type_pet', "pet", 0, 0,
|
||||
"펫",
|
||||
"familier",
|
||||
"Tier",
|
||||
"宠物",
|
||||
"寵物",
|
||||
"mascota",
|
||||
"mascota",
|
||||
"питомец"),
|
||||
|
||||
(1731, 'pet_type_guardian', "guardian", 0, 0,
|
||||
"수호자",
|
||||
"gardien",
|
||||
"Wächter",
|
||||
"守护者",
|
||||
"守護者",
|
||||
"guardián",
|
||||
"guardián",
|
||||
"защитник"),
|
||||
|
||||
(1732, 'pet_stance_aggressive', "aggressive", 0, 0,
|
||||
"공격적",
|
||||
"agressif",
|
||||
"aggressiv",
|
||||
"进攻",
|
||||
"進攻",
|
||||
"agresivo",
|
||||
"agresivo",
|
||||
"агрессивная"),
|
||||
|
||||
(1733, 'pet_stance_defensive', "defensive", 0, 0,
|
||||
"방어적",
|
||||
"défensif",
|
||||
"defensiv",
|
||||
"防御",
|
||||
"防禦",
|
||||
"defensivo",
|
||||
"defensivo",
|
||||
"защитная"),
|
||||
|
||||
(1734, 'pet_stance_passive', "passive", 0, 0,
|
||||
"수동적",
|
||||
"passif",
|
||||
"passiv",
|
||||
"被动",
|
||||
"被動",
|
||||
"pasivo",
|
||||
"pasivo",
|
||||
"пассивная"),
|
||||
|
||||
(1735, 'pet_stance_unknown', "unknown", 0, 0,
|
||||
"알 수 없음",
|
||||
"inconnu",
|
||||
"unbekannt",
|
||||
"未知",
|
||||
"未知",
|
||||
"desconocido",
|
||||
"desconocido",
|
||||
"неизвестная");
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES
|
||||
('pet_usage_error', 100),
|
||||
('pet_no_pet_error', 100),
|
||||
('pet_stance_report', 100),
|
||||
('pet_no_target_error', 100),
|
||||
('pet_target_dead_error', 100),
|
||||
('pet_invalid_target_error', 100),
|
||||
('pet_pvp_prohibited_error', 100),
|
||||
('pet_attack_success', 100),
|
||||
('pet_attack_failed', 100),
|
||||
('pet_follow_success', 100),
|
||||
('pet_stay_success', 100),
|
||||
('pet_unknown_command_error', 100),
|
||||
('pet_stance_set_success', 100),
|
||||
('pet_type_pet', 100),
|
||||
('pet_type_guardian', 100),
|
||||
('pet_stance_aggressive', 100),
|
||||
('pet_stance_defensive', 100),
|
||||
('pet_stance_passive', 100),
|
||||
('pet_stance_unknown', 100);
|
||||
@@ -84,9 +84,10 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((sPlayerbotAIConfig->IsInPvpProhibitedZone(bot->GetZoneId()) ||
|
||||
sPlayerbotAIConfig->IsInPvpProhibitedArea(bot->GetAreaId()))
|
||||
&& (target->IsPlayer() || target->IsPet()))
|
||||
// Check if bot OR target is in prohibited zone/area
|
||||
if ((target->IsPlayer() || target->IsPet()) &&
|
||||
(sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) ||
|
||||
sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId())))
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I cannot attack other players in PvP prohibited areas.");
|
||||
|
||||
@@ -25,7 +25,9 @@ bool PetsAction::Execute(Event event)
|
||||
if (param.empty())
|
||||
{
|
||||
// If no parameter is provided, show usage instructions and return.
|
||||
botAI->TellError("Usage: pet <aggressive|defensive|passive|stance|attack|follow|stay>");
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_usage_error", "Usage: pet <aggressive|defensive|passive|stance|attack|follow|stay>", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -52,7 +54,9 @@ bool PetsAction::Execute(Event event)
|
||||
// If no pets or guardians are found, notify and return.
|
||||
if (targets.empty())
|
||||
{
|
||||
botAI->TellError("You have no pet or guardian pet.");
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_no_pet_error", "You have no pet or guardian pet.", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -63,42 +67,54 @@ bool PetsAction::Execute(Event event)
|
||||
if (param == "aggressive")
|
||||
{
|
||||
react = REACT_AGGRESSIVE;
|
||||
stanceText = "aggressive";
|
||||
stanceText = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_aggressive", "aggressive", {});
|
||||
}
|
||||
else if (param == "defensive")
|
||||
{
|
||||
react = REACT_DEFENSIVE;
|
||||
stanceText = "defensive";
|
||||
stanceText = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_defensive", "defensive", {});
|
||||
}
|
||||
else if (param == "passive")
|
||||
{
|
||||
react = REACT_PASSIVE;
|
||||
stanceText = "passive";
|
||||
stanceText = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_passive", "passive", {});
|
||||
}
|
||||
// The "stance" command simply reports the current stance of each pet/guardian.
|
||||
else if (param == "stance")
|
||||
{
|
||||
for (Creature* target : targets)
|
||||
{
|
||||
std::string type = target->IsPet() ? "pet" : "guardian";
|
||||
std::string type = target->IsPet() ?
|
||||
sPlayerbotTextMgr->GetBotTextOrDefault("pet_type_pet", "pet", {}) :
|
||||
sPlayerbotTextMgr->GetBotTextOrDefault("pet_type_guardian", "guardian", {});
|
||||
std::string name = target->GetName();
|
||||
std::string stance;
|
||||
switch (target->GetReactState())
|
||||
{
|
||||
case REACT_AGGRESSIVE:
|
||||
stance = "aggressive";
|
||||
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_aggressive", "aggressive", {});
|
||||
break;
|
||||
case REACT_DEFENSIVE:
|
||||
stance = "defensive";
|
||||
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_defensive", "defensive", {});
|
||||
break;
|
||||
case REACT_PASSIVE:
|
||||
stance = "passive";
|
||||
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_passive", "passive", {});
|
||||
break;
|
||||
default:
|
||||
stance = "unknown";
|
||||
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_unknown", "unknown", {});
|
||||
break;
|
||||
}
|
||||
botAI->TellMaster("Current stance of " + type + " \"" + name + "\": " + stance + ".");
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_report", "Current stance of %type \"%name\": %stance.",
|
||||
{{"type", type}, {"name", name}, {"stance", stance}});
|
||||
botAI->TellMaster(text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -121,17 +137,31 @@ bool PetsAction::Execute(Event event)
|
||||
// If no valid target is selected, show an error and return.
|
||||
if (!targetUnit)
|
||||
{
|
||||
botAI->TellError("No valid target selected by master.");
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_no_target_error", "No valid target selected by master.", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
if (!targetUnit->IsAlive())
|
||||
{
|
||||
botAI->TellError("Target is not alive.");
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_target_dead_error", "Target is not alive.", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
if (!bot->IsValidAttackTarget(targetUnit))
|
||||
{
|
||||
botAI->TellError("Target is not a valid attack target for the bot.");
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_invalid_target_error", "Target is not a valid attack target for the bot.", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId())
|
||||
&& (targetUnit->IsPlayer() || targetUnit->IsPet()))
|
||||
{
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_pvp_prohibited_error", "I cannot command my pet to attack players in PvP prohibited areas.", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -182,9 +212,17 @@ bool PetsAction::Execute(Event event)
|
||||
}
|
||||
// Inform the master if the command succeeded or failed.
|
||||
if (didAttack && sPlayerbotAIConfig->petChatCommandDebug == 1)
|
||||
botAI->TellMaster("Pet commanded to attack your target.");
|
||||
{
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_attack_success", "Pet commanded to attack your target.", {});
|
||||
botAI->TellMaster(text);
|
||||
}
|
||||
else if (!didAttack)
|
||||
botAI->TellError("Pet did not attack. (Already attacking or unable to attack target)");
|
||||
{
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_attack_failed", "Pet did not attack. (Already attacking or unable to attack target)", {});
|
||||
botAI->TellError(text);
|
||||
}
|
||||
return didAttack;
|
||||
}
|
||||
// The "follow" command makes all pets/guardians follow the bot.
|
||||
@@ -192,7 +230,11 @@ bool PetsAction::Execute(Event event)
|
||||
{
|
||||
botAI->PetFollow();
|
||||
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
|
||||
botAI->TellMaster("Pet commanded to follow.");
|
||||
{
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_follow_success", "Pet commanded to follow.", {});
|
||||
botAI->TellMaster(text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// The "stay" command causes all pets/guardians to stop and stay in place.
|
||||
@@ -229,14 +271,20 @@ bool PetsAction::Execute(Event event)
|
||||
}
|
||||
}
|
||||
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
|
||||
botAI->TellMaster("Pet commanded to stay.");
|
||||
{
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stay_success", "Pet commanded to stay.", {});
|
||||
botAI->TellMaster(text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Unknown command: show usage instructions and return.
|
||||
else
|
||||
{
|
||||
botAI->TellError("Unknown pet command: " + param +
|
||||
". Use: pet <aggressive|defensive|passive|stance|attack|follow|stay>");
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_unknown_command_error", "Unknown pet command: %param. Use: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
|
||||
{{"param", param}});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -251,7 +299,12 @@ bool PetsAction::Execute(Event event)
|
||||
|
||||
// Inform the master of the new stance if debug is enabled.
|
||||
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
|
||||
botAI->TellMaster("Pet stance set to " + stanceText + ".");
|
||||
{
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"pet_stance_set_success", "Pet stance set to %stance.",
|
||||
{{"stance", stanceText}});
|
||||
botAI->TellMaster(text);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -107,7 +107,6 @@ void AttackersValue::AddAttackersOf(Player* player, std::unordered_set<Unit*>& t
|
||||
{
|
||||
ThreatMgr* threatMgr = ref->GetSource();
|
||||
Unit* attacker = threatMgr->GetOwner();
|
||||
Unit* victim = attacker->GetVictim();
|
||||
|
||||
if (player->IsValidAttackTarget(attacker) &&
|
||||
player->GetDistance2d(attacker) < sPlayerbotAIConfig->sightDistance)
|
||||
@@ -142,17 +141,83 @@ bool AttackersValue::hasRealThreat(Unit* attacker)
|
||||
(attacker->GetThreatMgr().getCurrentVictim() || dynamic_cast<Player*>(attacker));
|
||||
}
|
||||
|
||||
bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range)
|
||||
bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float /*range*/)
|
||||
{
|
||||
Creature* c = attacker->ToCreature();
|
||||
bool rti = false;
|
||||
if (attacker && bot->GetGroup())
|
||||
rti = bot->GetGroup()->GetTargetIcon(7) == attacker->GetGUID();
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
if (!botAI)
|
||||
return false;
|
||||
|
||||
// Basic check
|
||||
if (!attacker)
|
||||
return false;
|
||||
|
||||
// bool inCannon = botAI->IsInVehicle(false, true);
|
||||
// bool enemy = botAI->GetAiObjectContext()->GetValue<Unit*>("enemy player target")->Get();
|
||||
|
||||
// Validity checks
|
||||
if (!attacker->IsVisible() || !attacker->IsInWorld() || attacker->GetMapId() != bot->GetMapId())
|
||||
return false;
|
||||
|
||||
if (attacker->isDead() || attacker->HasSpiritOfRedemptionAura())
|
||||
return false;
|
||||
|
||||
// Flag checks
|
||||
if (attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2))
|
||||
return false;
|
||||
|
||||
if (attacker->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) || attacker->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
return false;
|
||||
|
||||
// Relationship checks
|
||||
if (attacker->IsFriendlyTo(bot))
|
||||
return false;
|
||||
|
||||
// Critter exception
|
||||
if (attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat())
|
||||
return false;
|
||||
|
||||
// Visibility check
|
||||
if (!bot->CanSeeOrDetect(attacker))
|
||||
return false;
|
||||
|
||||
// PvP prohibition checks
|
||||
if ((attacker->GetGUID().IsPlayer() || attacker->GetGUID().IsPet()) &&
|
||||
(sPlayerbotAIConfig->IsPvpProhibited(attacker->GetZoneId(), attacker->GetAreaId()) ||
|
||||
sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId())))
|
||||
{
|
||||
// This will stop aggresive pets from starting an attack.
|
||||
// This will stop currently attacking pets from continuing their attack.
|
||||
// This will first require the bot to change from a combat strat. It will
|
||||
// not be reached if the bot only switches targets, including NPC targets.
|
||||
for (Unit::ControlSet::const_iterator itr = bot->m_Controlled.begin();
|
||||
itr != bot->m_Controlled.end(); ++itr)
|
||||
{
|
||||
Creature* creature = dynamic_cast<Creature*>(*itr);
|
||||
if (creature && creature->GetVictim() == attacker)
|
||||
{
|
||||
creature->AttackStop();
|
||||
if (CharmInfo* charmInfo = creature->GetCharmInfo())
|
||||
charmInfo->SetIsCommandAttack(false);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unflagged player check
|
||||
if (attacker->IsPlayer() && !attacker->IsPvP() && !attacker->IsFFAPvP() &&
|
||||
(!bot->duel || bot->duel->Opponent != attacker))
|
||||
return false;
|
||||
|
||||
// Creature-specific checks
|
||||
Creature* c = attacker->ToCreature();
|
||||
if (c)
|
||||
{
|
||||
if (c->IsInEvadeMode())
|
||||
return false;
|
||||
|
||||
bool leaderHasThreat = false;
|
||||
if (attacker && bot->GetGroup() && botAI->GetMaster())
|
||||
if (bot->GetGroup() && botAI->GetMaster())
|
||||
leaderHasThreat = attacker->GetThreatMgr().GetThreat(botAI->GetMaster());
|
||||
|
||||
bool isMemberBotGroup = false;
|
||||
@@ -163,36 +228,20 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range)
|
||||
isMemberBotGroup = true;
|
||||
}
|
||||
|
||||
// bool inCannon = botAI->IsInVehicle(false, true);
|
||||
// bool enemy = botAI->GetAiObjectContext()->GetValue<Unit*>("enemy player target")->Get();
|
||||
|
||||
return attacker && attacker->IsVisible() && attacker->IsInWorld() && attacker->GetMapId() == bot->GetMapId() &&
|
||||
!attacker->isDead() &&
|
||||
!attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2) &&
|
||||
// (inCannon || !attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) &&
|
||||
// attacker->CanSeeOrDetect(bot) &&
|
||||
// !(attacker->HasUnitState(UNIT_STATE_STUNNED) && botAI->HasAura("shackle undead", attacker)) &&
|
||||
// !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/
|
||||
// attacker->isFeared()) && !rti) &&
|
||||
/*!sServerFacade->IsInRoots(attacker) &&*/
|
||||
!attacker->IsFriendlyTo(bot) && !attacker->HasSpiritOfRedemptionAura() &&
|
||||
// !(attacker->GetGUID().IsPet() && enemy) &&
|
||||
!(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) &&
|
||||
!attacker->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && !attacker->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) &&
|
||||
bot->CanSeeOrDetect(attacker) &&
|
||||
!(sPlayerbotAIConfig->IsPvpProhibited(attacker->GetZoneId(), attacker->GetAreaId()) &&
|
||||
(attacker->GetGUID().IsPlayer() || attacker->GetGUID().IsPet())) &&
|
||||
!(attacker->IsPlayer() && !attacker->IsPvP() && !attacker->IsFFAPvP() &&
|
||||
(!bot->duel || bot->duel->Opponent != attacker)) &&
|
||||
(!c ||
|
||||
(!c->IsInEvadeMode() &&
|
||||
((!isMemberBotGroup && botAI->HasStrategy("attack tagged", BOT_STATE_NON_COMBAT)) || leaderHasThreat ||
|
||||
bool canAttack = (!isMemberBotGroup && botAI->HasStrategy("attack tagged", BOT_STATE_NON_COMBAT)) ||
|
||||
leaderHasThreat ||
|
||||
(!c->hasLootRecipient() &&
|
||||
(!c->GetVictim() ||
|
||||
(c->GetVictim() &&
|
||||
((!c->GetVictim()->IsPlayer() || bot->IsInSameGroupWith(c->GetVictim()->ToPlayer())) ||
|
||||
(botAI->GetMaster() && c->GetVictim() == botAI->GetMaster()))))) ||
|
||||
c->isTappedBy(bot))));
|
||||
c->isTappedBy(bot);
|
||||
|
||||
if (!canAttack)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttackersValue::IsValidTarget(Unit* attacker, Player* bot)
|
||||
|
||||
Reference in New Issue
Block a user