mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-25 06:18:21 +00:00
More fixes
TGB, ^cast, group/ae checks, in group/raid checks, inviting others bots to group, group disband fix, prevent rogue bs spam, ^follow fixes and cleanup, follow owner only by default when joining raid/group, group buff fixes for bots, range fixes for group buffs
This commit is contained in:
+3
-1
@@ -836,7 +836,7 @@ RULE_INT(Bots, PullSpellID, 5225, "Default 5225 - Throw Stone. Spell that will b
|
|||||||
RULE_BOOL(Bots, AllowBotEquipAnyClassGear, false, "Allows Bots to wear Equipment even if their class is not valid")
|
RULE_BOOL(Bots, AllowBotEquipAnyClassGear, false, "Allows Bots to wear Equipment even if their class is not valid")
|
||||||
RULE_BOOL(Bots, BotArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
|
RULE_BOOL(Bots, BotArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
|
||||||
RULE_BOOL(Bots, BotThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
|
RULE_BOOL(Bots, BotThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
|
||||||
RULE_INT(Bots, StackSizeMin, 100, "100 Default. -1 to disable and use default max stack size. Minimum stack size to give a bot (Arrows/Throwing).")
|
RULE_INT(Bots, StackSizeMin, 20, "20 Default. -1 to disable and use default max stack size. Minimum stack size to give a bot (Arrows/Throwing).")
|
||||||
RULE_INT(Bots, HasOrMayGetAggroThreshold, 90, "90 Default. Percent threshold of total hate where bots will stop casting spells that generate hate if they are set to try to not pull aggro via spells.")
|
RULE_INT(Bots, HasOrMayGetAggroThreshold, 90, "90 Default. Percent threshold of total hate where bots will stop casting spells that generate hate if they are set to try to not pull aggro via spells.")
|
||||||
RULE_BOOL(Bots, UseFlatNormalMeleeRange, false, "False Default. If true, bots melee distance will be a flat distance set by Bots:NormalMeleeRangeDistance.")
|
RULE_BOOL(Bots, UseFlatNormalMeleeRange, false, "False Default. If true, bots melee distance will be a flat distance set by Bots:NormalMeleeRangeDistance.")
|
||||||
RULE_REAL(Bots, NormalMeleeRangeDistance, 0.75, "Multiplier of the max melee range at which a bot will stand in melee combat. 0.75 Recommended, max melee for all abilities to land.")
|
RULE_REAL(Bots, NormalMeleeRangeDistance, 0.75, "Multiplier of the max melee range at which a bot will stand in melee combat. 0.75 Recommended, max melee for all abilities to land.")
|
||||||
@@ -871,6 +871,8 @@ RULE_INT(Bots, StatusSpawnLimit, 120, "Minimum status to bypass spawn limit. Def
|
|||||||
RULE_INT(Bots, MinStatusToBypassCreateLimit, 100, "Minimum status to bypass the anti-spam system")
|
RULE_INT(Bots, MinStatusToBypassCreateLimit, 100, "Minimum status to bypass the anti-spam system")
|
||||||
RULE_INT(Bots, StatusCreateLimit, 120, "Minimum status to bypass spawn limit. Default 120.")
|
RULE_INT(Bots, StatusCreateLimit, 120, "Minimum status to bypass spawn limit. Default 120.")
|
||||||
RULE_BOOL(Bots, BardsAnnounceCasts, false, "This determines whether or not Bard bots will announce that they're casting songs (Buffs, Heals, Nukes, Slows, etc.) they will always announce Mez.")
|
RULE_BOOL(Bots, BardsAnnounceCasts, false, "This determines whether or not Bard bots will announce that they're casting songs (Buffs, Heals, Nukes, Slows, etc.) they will always announce Mez.")
|
||||||
|
RULE_BOOL(Bots, EnableBotTGB, true, "If enabled bots will cast group buffs as TGB.")
|
||||||
|
RULE_BOOL(Bots, DoResponseAnimations, true, "If enabled bots will do animations to certain responses or commands.")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Chat)
|
RULE_CATEGORY(Chat)
|
||||||
|
|||||||
+73
-3
@@ -2782,15 +2782,16 @@ int8 SpellEffectsCount(uint16 spell_id) {
|
|||||||
if (!IsValidSpell(spell_id)) {
|
if (!IsValidSpell(spell_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int8 i = 0;
|
|
||||||
|
int8 x = 0;
|
||||||
|
|
||||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||||
if (!IsBlankSpellEffect(spell_id, i)) {
|
if (!IsBlankSpellEffect(spell_id, i)) {
|
||||||
++i;
|
++x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLichSpell(uint16 spell_id)
|
bool IsLichSpell(uint16 spell_id)
|
||||||
@@ -3175,3 +3176,72 @@ bool RequiresStackCheck(uint16 spellType) {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsResistanceOnlySpell(uint16 spell_id) {
|
||||||
|
if (!IsValidSpell(spell_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& spell = spells[spell_id];
|
||||||
|
|
||||||
|
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||||
|
if (IsBlankSpellEffect(spell_id, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
spell.effect_id[i] == SE_ResistFire ||
|
||||||
|
spell.effect_id[i] == SE_ResistCold ||
|
||||||
|
spell.effect_id[i] == SE_ResistPoison ||
|
||||||
|
spell.effect_id[i] == SE_ResistDisease ||
|
||||||
|
spell.effect_id[i] == SE_ResistMagic ||
|
||||||
|
spell.effect_id[i] == SE_ResistCorruption ||
|
||||||
|
spell.effect_id[i] == SE_ResistAll
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDamageShieldOnlySpell(uint16 spell_id) {
|
||||||
|
if (SpellEffectsCount(spell_id) == 1 && IsEffectInSpell(spell_id, SE_DamageShield)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDamageShieldAndResistanceSpellOnly(uint16 spell_id) {
|
||||||
|
if (!IsValidSpell(spell_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& spell = spells[spell_id];
|
||||||
|
|
||||||
|
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||||
|
if (IsBlankSpellEffect(spell_id, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
spell.effect_id[i] == SE_DamageShield ||
|
||||||
|
spell.effect_id[i] == SE_ResistFire ||
|
||||||
|
spell.effect_id[i] == SE_ResistCold ||
|
||||||
|
spell.effect_id[i] == SE_ResistPoison ||
|
||||||
|
spell.effect_id[i] == SE_ResistDisease ||
|
||||||
|
spell.effect_id[i] == SE_ResistMagic ||
|
||||||
|
spell.effect_id[i] == SE_ResistCorruption ||
|
||||||
|
spell.effect_id[i] == SE_ResistAll
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1722,5 +1722,8 @@ bool IsLichSpell(uint16 spell_id);
|
|||||||
bool IsInstantHealSpell(uint32 spell_id);
|
bool IsInstantHealSpell(uint32 spell_id);
|
||||||
bool IsResurrectSpell(uint16 spell_id);
|
bool IsResurrectSpell(uint16 spell_id);
|
||||||
bool RequiresStackCheck(uint16 spellType);
|
bool RequiresStackCheck(uint16 spellType);
|
||||||
|
bool IsResistanceOnlySpell(uint16 spell_id);
|
||||||
|
bool IsDamageShieldOnlySpell(uint16 spell_id);
|
||||||
|
bool IsDamageShieldAndResistanceSpellOnly(uint16 spell_id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+104
-165
@@ -87,6 +87,7 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
|||||||
SetGuardFlag(false);
|
SetGuardFlag(false);
|
||||||
SetHoldFlag(false);
|
SetHoldFlag(false);
|
||||||
SetAttackFlag(false);
|
SetAttackFlag(false);
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
SetPullFlag(false);
|
SetPullFlag(false);
|
||||||
SetPullingFlag(false);
|
SetPullingFlag(false);
|
||||||
@@ -210,6 +211,7 @@ Bot::Bot(
|
|||||||
SetGuardFlag(false);
|
SetGuardFlag(false);
|
||||||
SetHoldFlag(false);
|
SetHoldFlag(false);
|
||||||
SetAttackFlag(false);
|
SetAttackFlag(false);
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
SetPullFlag(false);
|
SetPullFlag(false);
|
||||||
SetPullingFlag(false);
|
SetPullingFlag(false);
|
||||||
@@ -1797,8 +1799,10 @@ void Bot::BotRangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if (!Ammo || ammoItem->GetCharges() < 1) {
|
if (!Ammo || ammoItem->GetCharges() < 1) {
|
||||||
|
if (!GetCombatRoundForAlerts()) {
|
||||||
GetOwner()->Message(Chat::Yellow, "I do not have enough any ammo.");
|
GetOwner()->Message(Chat::Yellow, "I do not have enough any ammo.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2014,15 +2018,26 @@ void Bot::AI_Process()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto leash_owner = SetLeashOwner(bot_owner, bot_group, raid, r_group);
|
Client* leash_owner = bot_owner;
|
||||||
|
|
||||||
if (!leash_owner) {
|
if (!leash_owner) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetFollowID(leash_owner->GetID());
|
Mob* follow_mob = nullptr;
|
||||||
|
|
||||||
auto follow_mob = SetFollowMob(leash_owner);
|
if (!GetFollowID()) {
|
||||||
|
follow_mob = leash_owner;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
follow_mob = entity_list.GetMob(GetFollowID());
|
||||||
|
|
||||||
|
if (!follow_mob || !IsInGroupOrRaid(follow_mob)) {
|
||||||
|
follow_mob = leash_owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetFollowID(follow_mob->GetID());
|
||||||
|
|
||||||
SetBerserkState();
|
SetBerserkState();
|
||||||
|
|
||||||
@@ -2094,6 +2109,7 @@ void Bot::AI_Process()
|
|||||||
// ATTACKING FLAG (HATE VALIDATION)
|
// ATTACKING FLAG (HATE VALIDATION)
|
||||||
|
|
||||||
if (GetAttackingFlag() && tar->CheckAggro(this)) {
|
if (GetAttackingFlag() && tar->CheckAggro(this)) {
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2264,6 +2280,7 @@ void Bot::AI_Process()
|
|||||||
}
|
}
|
||||||
else { // Out-of-combat behavior
|
else { // Out-of-combat behavior
|
||||||
SetAttackFlag(false);
|
SetAttackFlag(false);
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
if (!bot_owner->GetBotPulling()) {
|
if (!bot_owner->GetBotPulling()) {
|
||||||
|
|
||||||
@@ -2408,6 +2425,7 @@ bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance) {
|
|||||||
AddToHateList(hater, 1);
|
AddToHateList(hater, 1);
|
||||||
SetTarget(hater);
|
SetTarget(hater);
|
||||||
SetAttackingFlag();
|
SetAttackingFlag();
|
||||||
|
SetCombatRoundForAlerts();
|
||||||
|
|
||||||
if (HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
if (HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
||||||
GetPet()->AddToHateList(hater, 1);
|
GetPet()->AddToHateList(hater, 1);
|
||||||
@@ -2869,6 +2887,7 @@ bool Bot::IsValidTarget(
|
|||||||
SetTarget(nullptr);
|
SetTarget(nullptr);
|
||||||
|
|
||||||
SetAttackFlag(false);
|
SetAttackFlag(false);
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
|
|
||||||
if (PULLING_BOT) {
|
if (PULLING_BOT) {
|
||||||
@@ -2902,6 +2921,7 @@ Mob* Bot::GetBotTarget(Client* bot_owner)
|
|||||||
|
|
||||||
WipeHateList();
|
WipeHateList();
|
||||||
SetAttackFlag(false);
|
SetAttackFlag(false);
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
|
|
||||||
if (PULLING_BOT) {
|
if (PULLING_BOT) {
|
||||||
@@ -3120,6 +3140,7 @@ void Bot::SetOwnerTarget(Client* bot_owner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetAttackFlag(false);
|
SetAttackFlag(false);
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
SetPullFlag(false);
|
SetPullFlag(false);
|
||||||
SetPullingFlag(false);
|
SetPullingFlag(false);
|
||||||
@@ -3134,6 +3155,7 @@ void Bot::SetOwnerTarget(Client* bot_owner) {
|
|||||||
WipeHateList();
|
WipeHateList();
|
||||||
AddToHateList(attack_target, 1);
|
AddToHateList(attack_target, 1);
|
||||||
SetTarget(attack_target);
|
SetTarget(attack_target);
|
||||||
|
SetCombatRoundForAlerts();
|
||||||
SetAttackingFlag();
|
SetAttackingFlag();
|
||||||
if (GetPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
if (GetPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
||||||
GetPet()->WipeHateList();
|
GetPet()->WipeHateList();
|
||||||
@@ -3146,6 +3168,7 @@ void Bot::SetOwnerTarget(Client* bot_owner) {
|
|||||||
|
|
||||||
void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) {
|
void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) {
|
||||||
SetAttackFlag(false);
|
SetAttackFlag(false);
|
||||||
|
SetCombatRoundForAlerts(true);
|
||||||
SetAttackingFlag(false);
|
SetAttackingFlag(false);
|
||||||
SetPullFlag(false);
|
SetPullFlag(false);
|
||||||
SetPullingFlag(false);
|
SetPullingFlag(false);
|
||||||
@@ -3838,7 +3861,6 @@ bool Bot::AddBotToGroup(Bot* bot, Group* group) {
|
|||||||
|
|
||||||
if (bot && group->AddMember(bot)) {
|
if (bot && group->AddMember(bot)) {
|
||||||
if (group->GetLeader()) {
|
if (group->GetLeader()) {
|
||||||
bot->SetFollowID(group->GetLeader()->GetID());
|
|
||||||
// Need to send this only once when a group is formed with a bot so the client knows it is also the group leader
|
// Need to send this only once when a group is formed with a bot so the client knows it is also the group leader
|
||||||
if (group->GroupCount() == 2 && group->GetLeader()->IsClient()) {
|
if (group->GroupCount() == 2 && group->GetLeader()->IsClient()) {
|
||||||
group->UpdateGroupAAs();
|
group->UpdateGroupAAs();
|
||||||
@@ -4882,7 +4904,10 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) {
|
|||||||
botpiercer = inst->GetItem();
|
botpiercer = inst->GetItem();
|
||||||
|
|
||||||
if (!botpiercer || (botpiercer->ItemType != EQ::item::ItemType1HPiercing)) {
|
if (!botpiercer || (botpiercer->ItemType != EQ::item::ItemType1HPiercing)) {
|
||||||
|
if (!GetCombatRoundForAlerts()) {
|
||||||
BotGroupSay(this, "I can't backstab with this weapon!");
|
BotGroupSay(this, "I can't backstab with this weapon!");
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5818,7 +5843,7 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQ::spe
|
|||||||
GetClass() != Class::Bard &&
|
GetClass() != Class::Bard &&
|
||||||
(IsGrouped() || (IsRaidGrouped() && GetRaid()->GetGroup(GetCleanName()) != RAID_GROUPLESS)) &&
|
(IsGrouped() || (IsRaidGrouped() && GetRaid()->GetGroup(GetCleanName()) != RAID_GROUPLESS)) &&
|
||||||
(spellTarget->IsBot() || spellTarget->IsClient()) &&
|
(spellTarget->IsBot() || spellTarget->IsClient()) &&
|
||||||
(RuleB(Bots, GroupBuffing) || RuleB(Bots, CrossRaidBuffingAndHealing))
|
(RuleB(Bots, GroupBuffing) || RuleB(Bots, RaidBuffing))
|
||||||
) {
|
) {
|
||||||
bool noGroupSpell = false;
|
bool noGroupSpell = false;
|
||||||
uint16 thespell = spell_id;
|
uint16 thespell = spell_id;
|
||||||
@@ -5847,7 +5872,8 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQ::spe
|
|||||||
|
|
||||||
if (!noGroupSpell) {
|
if (!noGroupSpell) {
|
||||||
std::vector<Mob*> v;
|
std::vector<Mob*> v;
|
||||||
if (RuleB(Bots, CrossRaidBuffingAndHealing)) {
|
|
||||||
|
if (RuleB(Bots, RaidBuffing)) {
|
||||||
v = GatherSpellTargets(true);
|
v = GatherSpellTargets(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -5906,8 +5932,20 @@ bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQ::spel
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (spellTarget->IsOfClientBotMerc()) {
|
if (spellTarget->IsOfClientBotMerc()) {
|
||||||
const std::vector<Mob*> v = GatherGroupSpellTargets(spellTarget);
|
std::vector<Mob*> v;
|
||||||
|
|
||||||
|
if (RuleB(Bots, RaidBuffing)) {
|
||||||
|
v = GatherSpellTargets(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = GatherGroupSpellTargets(spellTarget);
|
||||||
|
}
|
||||||
|
|
||||||
for (Mob* m : v) {
|
for (Mob* m : v) {
|
||||||
|
if (m == this && spellTarget != this) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SpellOnTarget(spell_id, m);
|
SpellOnTarget(spell_id, m);
|
||||||
|
|
||||||
if (m->GetPetID() && (!RuleB(Bots, RequirePetAffinity) || m->HasPetAffinity())) {
|
if (m->GetPetID() && (!RuleB(Bots, RequirePetAffinity) || m->HasPetAffinity())) {
|
||||||
@@ -6595,40 +6633,6 @@ void Bot::DoEnduranceUpkeep() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Bot::Camp(bool save_to_database) {
|
void Bot::Camp(bool save_to_database) {
|
||||||
|
|
||||||
if (RuleB(Bots, PreventBotCampOnFD) && GetBotOwner()->GetFeigned()) {
|
|
||||||
GetBotOwner()->Message(Chat::White, "You cannot camp bots while feigned.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RuleB(Bots, PreventBotCampOnEngaged)) {
|
|
||||||
Raid* raid = entity_list.GetRaidByClient(GetBotOwner()->CastToClient());
|
|
||||||
if (raid && raid->IsEngaged()) {
|
|
||||||
GetBotOwner()->Message(Chat::White, "You cannot spawn bots while your raid is engaged.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* owner_group = GetBotOwner()->GetGroup();
|
|
||||||
if (owner_group) {
|
|
||||||
std::list<Client*> member_list;
|
|
||||||
owner_group->GetClientList(member_list);
|
|
||||||
member_list.remove(nullptr);
|
|
||||||
|
|
||||||
for (auto member_iter : member_list) {
|
|
||||||
if (member_iter->IsEngaged() || member_iter->GetAggroCount() > 0) {
|
|
||||||
GetBotOwner()->Message(Chat::White, "You cannot spawn bots while your group is engaged,");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (GetBotOwner()->CastToClient()->GetAggroCount() > 0) {
|
|
||||||
GetBotOwner()->Message(Chat::White, "You cannot spawn bots while you are engaged,");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Sit();
|
Sit();
|
||||||
|
|
||||||
LeaveHealRotationMemberPool();
|
LeaveHealRotationMemberPool();
|
||||||
@@ -6828,11 +6832,26 @@ Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, const std::string& botName
|
|||||||
|
|
||||||
void Bot::ProcessBotGroupInvite(Client* c, std::string const& botName) {
|
void Bot::ProcessBotGroupInvite(Client* c, std::string const& botName) {
|
||||||
if (c && !c->HasRaid()) {
|
if (c && !c->HasRaid()) {
|
||||||
Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName);
|
Bot* invitedBot = entity_list.GetBotByBotName(botName);
|
||||||
|
|
||||||
if (!invitedBot) {
|
if (!invitedBot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
invitedBot->GetBotOwnerCharacterID() != c->CharacterID() &&
|
||||||
|
!(
|
||||||
|
c->GetGroup() &&
|
||||||
|
!invitedBot->HasGroup() &&
|
||||||
|
invitedBot->GetOwner()->HasGroup() &&
|
||||||
|
c->GetGroup() == invitedBot->GetOwner()->GetGroup()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
c->Message(Chat::Red, "%s's owner needs to be in your group to be able to invite them.", invitedBot->GetCleanName());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!invitedBot->HasGroup() && !invitedBot->HasRaid()) {
|
if (!invitedBot->HasGroup() && !invitedBot->HasRaid()) {
|
||||||
if (!c->IsGrouped()) {
|
if (!c->IsGrouped()) {
|
||||||
auto g = new Group(c);
|
auto g = new Group(c);
|
||||||
@@ -7074,7 +7093,6 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
|
|||||||
else {
|
else {
|
||||||
v = caster->GatherGroupSpellTargets();
|
v = caster->GatherGroupSpellTargets();
|
||||||
}
|
}
|
||||||
v = caster->GatherSpellTargets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mob* tar = nullptr;
|
Mob* tar = nullptr;
|
||||||
@@ -8433,17 +8451,19 @@ int32 Bot::CalcItemATKCap()
|
|||||||
return RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
return RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::CheckSpawnConditions(Client* c) {
|
bool Bot::CheckCampSpawnConditions(Client* c) {
|
||||||
|
|
||||||
if (RuleB(Bots, PreventBotSpawnOnFD) && c->GetFeigned()) {
|
if (RuleB(Bots, PreventBotSpawnOnFD) && c->GetFeigned()) {
|
||||||
c->Message(Chat::White, "You cannot spawn bots while feigned.");
|
c->Message(Chat::White, "You cannot camp or spawn bots while feigned.");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RuleB(Bots, PreventBotSpawnOnEngaged)) {
|
if (RuleB(Bots, PreventBotSpawnOnEngaged)) {
|
||||||
Raid* raid = entity_list.GetRaidByClient(c);
|
Raid* raid = entity_list.GetRaidByClient(c);
|
||||||
if (raid && raid->IsEngaged()) {
|
if (raid && raid->IsEngaged()) {
|
||||||
c->Message(Chat::White, "You cannot spawn bots while your raid is engaged.");
|
c->Message(Chat::White, "You cannot camp or spawn bots while your raid is engaged.");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8455,14 +8475,14 @@ bool Bot::CheckSpawnConditions(Client* c) {
|
|||||||
|
|
||||||
for (auto member_iter : member_list) {
|
for (auto member_iter : member_list) {
|
||||||
if (member_iter->IsEngaged() || member_iter->GetAggroCount() > 0) {
|
if (member_iter->IsEngaged() || member_iter->GetAggroCount() > 0) {
|
||||||
c->Message(Chat::White, "You cannot spawn bots while your group is engaged,");
|
c->Message(Chat::White, "You cannot camp or spawn bots while your group is engaged,");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (c->GetAggroCount() > 0) {
|
if (c->GetAggroCount() > 0) {
|
||||||
c->Message(Chat::White, "You cannot spawn bots while you are engaged,");
|
c->Message(Chat::White, "You cannot camp or spawn bots while you are engaged,");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9397,6 +9417,10 @@ bool Bot::CastChecks(uint16 spellid, Mob* tar, uint16 spellType, bool doPrecheck
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsBeneficialSpell(spellid) && tar->BuffCount() >= tar->GetCurrentBuffSlots() && CalcBuffDuration(this, tar, spellid) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LogBotPreChecksDetail("{} says, 'Doing CanCastSpellType checks of {} on {}.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
LogBotPreChecksDetail("{} says, 'Doing CanCastSpellType checks of {} on {}.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
||||||
if (!CanCastSpellType(spellType, spellid, tar)) {
|
if (!CanCastSpellType(spellType, spellid, tar)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -9426,8 +9450,7 @@ bool Bot::CanCastSpellType(uint16 spellType, uint16 spellid, Mob* tar) {
|
|||||||
spells[spellid].target_type == ST_Pet ||
|
spells[spellid].target_type == ST_Pet ||
|
||||||
(tar == this && spells[spellid].target_type != ST_TargetsTarget) ||
|
(tar == this && spells[spellid].target_type != ST_TargetsTarget) ||
|
||||||
spells[spellid].target_type == ST_Group ||
|
spells[spellid].target_type == ST_Group ||
|
||||||
spells[spellid].target_type == ST_GroupTeleport //||
|
spells[spellid].target_type == ST_GroupTeleport
|
||||||
//(botClass == Class::Bard && spells[spellid].target_type == ST_AEBard) //TODO bot rewrite - is this needed?
|
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
LogBotPreChecks("{} says, 'Cancelling cast of {} on {} due to target_type checks.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
LogBotPreChecks("{} says, 'Cancelling cast of {} on {} due to target_type checks.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
||||||
@@ -9471,7 +9494,7 @@ bool Bot::CanCastSpellType(uint16 spellType, uint16 spellid, Mob* tar) {
|
|||||||
tar->IsBot() && tar->GetLevel() > tar->CastToBot()->GetStopMeleeLevel() &&
|
tar->IsBot() && tar->GetLevel() > tar->CastToBot()->GetStopMeleeLevel() &&
|
||||||
(
|
(
|
||||||
IsEffectInSpell(spellid, SE_AttackSpeed) || IsEffectInSpell(spellid, SE_ReverseDS)) ||
|
IsEffectInSpell(spellid, SE_AttackSpeed) || IsEffectInSpell(spellid, SE_ReverseDS)) ||
|
||||||
(SpellEffectsCount(spellid) == 1 && IsEffectInSpell(spellid, SE_ATK) || IsEffectInSpell(spellid, SE_STR)
|
(SpellEffectsCount(spellid) == 1 && (IsEffectInSpell(spellid, SE_ATK) || IsEffectInSpell(spellid, SE_STR))
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to Archetype::Caster.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to Archetype::Caster.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
||||||
@@ -9516,18 +9539,6 @@ bool Bot::CanCastSpellType(uint16 spellType, uint16 spellid, Mob* tar) {
|
|||||||
case BotSpellTypes::PreCombatBuffSong:
|
case BotSpellTypes::PreCombatBuffSong:
|
||||||
case BotSpellTypes::InCombatBuffSong:
|
case BotSpellTypes::InCombatBuffSong:
|
||||||
case BotSpellTypes::OutOfCombatBuffSong:
|
case BotSpellTypes::OutOfCombatBuffSong:
|
||||||
//switch (spells[spellid].target_type) { //TODO bot rewrite - is this needed?
|
|
||||||
// case ST_AEBard:
|
|
||||||
// case ST_AECaster:
|
|
||||||
// case ST_GroupTeleport:
|
|
||||||
// case ST_Group:
|
|
||||||
// case ST_Self:
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// LogBotPreChecks("{} says, 'Cancelling cast of {} on {} due to target_type checks.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (!IsCommandedSpell() && IsTargetAlreadyReceivingSpell(tar, spellid)) {
|
if (!IsCommandedSpell() && IsTargetAlreadyReceivingSpell(tar, spellid)) {
|
||||||
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to IsTargetAlreadyReceivingSpell.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to IsTargetAlreadyReceivingSpell.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
||||||
return false;
|
return false;
|
||||||
@@ -9540,7 +9551,7 @@ bool Bot::CanCastSpellType(uint16 spellType, uint16 spellid, Mob* tar) {
|
|||||||
tar->IsBot() && tar->GetLevel() > tar->CastToBot()->GetStopMeleeLevel() &&
|
tar->IsBot() && tar->GetLevel() > tar->CastToBot()->GetStopMeleeLevel() &&
|
||||||
(
|
(
|
||||||
IsEffectInSpell(spellid, SE_AttackSpeed) || IsEffectInSpell(spellid, SE_ReverseDS)) ||
|
IsEffectInSpell(spellid, SE_AttackSpeed) || IsEffectInSpell(spellid, SE_ReverseDS)) ||
|
||||||
(SpellEffectsCount(spellid) == 1 && IsEffectInSpell(spellid, SE_ATK) || IsEffectInSpell(spellid, SE_STR)
|
(SpellEffectsCount(spellid) == 1 && (IsEffectInSpell(spellid, SE_ATK) || IsEffectInSpell(spellid, SE_STR))
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to Archetype::Caster.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to Archetype::Caster.'", GetCleanName(), GetSpellName(spellid), tar->GetCleanName()); //deleteme
|
||||||
@@ -9597,7 +9608,15 @@ bool Bot::IsTargetAlreadyReceivingSpell(Mob* tar, uint16 spellid) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Mob*> v = GatherSpellTargets();
|
std::vector<Mob*> v;
|
||||||
|
|
||||||
|
if (RuleB(Bots, CrossRaidBuffingAndHealing)) {
|
||||||
|
v = GatherSpellTargets(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = GatherGroupSpellTargets();
|
||||||
|
}
|
||||||
|
|
||||||
for (Mob* m : v) {
|
for (Mob* m : v) {
|
||||||
if (
|
if (
|
||||||
m->IsBot() &&
|
m->IsBot() &&
|
||||||
@@ -9618,9 +9637,10 @@ bool Bot::IsTargetAlreadyReceivingSpell(Mob* tar, uint16 spellid) {
|
|||||||
m->CastingSpellID() == spellid
|
m->CastingSpellID() == spellid
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const std::vector<Mob*> v = GatherGroupSpellTargets();
|
std::vector<Mob*> x = GatherGroupSpellTargets();
|
||||||
for (Mob* m : v) {
|
|
||||||
if (entity_list.GetMobID(m->CastToBot()->casting_spell_targetid) == entity_list.GetMobID(m->GetID())) {
|
for (Mob* t : x) {
|
||||||
|
if (entity_list.GetMobID(t->CastToBot()->casting_spell_targetid) == entity_list.GetMobID(t->GetID())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10264,60 +10284,56 @@ uint16 Bot::GetDefaultSpellTypeIdlePriority(uint16 spellType, uint8 botClass) {
|
|||||||
priority = 10;
|
priority = 10;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::InCombatBuff: // this has a check at the end to decrement everything below if it's not a SK (SK use InCombatBuffs as it is their hate line so it's not use when Idle)
|
case BotSpellTypes::PetVeryFastHeals:
|
||||||
priority = 11;
|
priority = 11;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::PetVeryFastHeals:
|
case BotSpellTypes::PetFastHeals:
|
||||||
priority = 12;
|
priority = 12;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::PetFastHeals:
|
case BotSpellTypes::PetRegularHeals:
|
||||||
priority = 13;
|
priority = 13;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::PetRegularHeals:
|
case BotSpellTypes::PetCompleteHeals:
|
||||||
priority = 14;
|
priority = 14;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::PetCompleteHeals:
|
case BotSpellTypes::PetHoTHeals:
|
||||||
priority = 15;
|
priority = 15;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::PetHoTHeals:
|
case BotSpellTypes::Pet:
|
||||||
priority = 16;
|
priority = 16;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::Pet:
|
case BotSpellTypes::Buff:
|
||||||
priority = 17;
|
priority = 17;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::Buff:
|
case BotSpellTypes::OutOfCombatBuffSong:
|
||||||
priority = 18;
|
priority = 18;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::OutOfCombatBuffSong:
|
case BotSpellTypes::ResistBuffs:
|
||||||
priority = 19;
|
priority = 19;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::ResistBuffs:
|
case BotSpellTypes::DamageShields:
|
||||||
priority = 20;
|
priority = 20;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::DamageShields:
|
case BotSpellTypes::PetBuffs:
|
||||||
priority = 21;
|
priority = 21;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::PetBuffs:
|
case BotSpellTypes::PreCombatBuff:
|
||||||
priority = 22;
|
priority = 22;
|
||||||
|
|
||||||
break;
|
|
||||||
case BotSpellTypes::PreCombatBuff:
|
|
||||||
priority = 23;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BotSpellTypes::PreCombatBuffSong:
|
case BotSpellTypes::PreCombatBuffSong:
|
||||||
priority = 24;
|
priority = 23;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -10326,14 +10342,6 @@ uint16 Bot::GetDefaultSpellTypeIdlePriority(uint16 spellType, uint8 botClass) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
priority >= 11 &&
|
|
||||||
botClass && botClass == Class::ShadowKnight &&
|
|
||||||
spellType != BotSpellTypes::InCombatBuff
|
|
||||||
) {
|
|
||||||
--priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10839,39 +10847,19 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spellType, uint16 spellid) {
|
|||||||
|
|
||||||
switch (spellType) { //TODO bot rewrite - fix Buff/ResistBuff
|
switch (spellType) { //TODO bot rewrite - fix Buff/ResistBuff
|
||||||
case BotSpellTypes::Buff:
|
case BotSpellTypes::Buff:
|
||||||
if (IsEffectInSpell(spellid, SE_DamageShield)) {
|
if (IsResistanceOnlySpell(spellid) || IsDamageShieldOnlySpell(spellid) || IsDamageShieldAndResistanceSpellOnly(spellid)) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
IsEffectInSpell(spellid, SE_ResistMagic) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistFire) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistCold) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistPoison) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistDisease) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistCorruption) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistAll)
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
case BotSpellTypes::ResistBuffs:
|
case BotSpellTypes::ResistBuffs:
|
||||||
if (
|
if (IsResistanceOnlySpell(spellid)) {
|
||||||
IsEffectInSpell(spellid, SE_ResistMagic) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistFire) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistCold) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistPoison) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistDisease) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistCorruption) ||
|
|
||||||
IsEffectInSpell(spellid, SE_ResistAll)
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
case BotSpellTypes::DamageShields:
|
case BotSpellTypes::DamageShields:
|
||||||
if (IsEffectInSpell(spellid, SE_DamageShield)) {
|
if (IsDamageShieldOnlySpell(spellid) || IsDamageShieldAndResistanceSpellOnly(spellid)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11086,55 +11074,6 @@ bool Bot::HasRequiredLoSForPositioning(Mob* tar) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::IsInGroupOrRaid(bool announce) {
|
|
||||||
if (!GetOwner()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mob* c = GetOwner();
|
|
||||||
|
|
||||||
if (
|
|
||||||
(!GetRaid() && !GetGroup()) ||
|
|
||||||
(!c->GetRaid() && !c->GetGroup())
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
c->GetRaid() &&
|
|
||||||
(
|
|
||||||
!GetRaid() ||
|
|
||||||
c->GetRaid() != GetRaid() ||
|
|
||||||
GetRaid()->GetGroup(GetCleanName()) == RAID_GROUPLESS
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
c->GetGroup() &&
|
|
||||||
(
|
|
||||||
!GetGroup() ||
|
|
||||||
c->GetGroup() != GetGroup()
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (announce) {
|
|
||||||
c->Message(
|
|
||||||
Chat::Yellow,
|
|
||||||
fmt::format(
|
|
||||||
"{} says, 'I am not currently in your group or raid.",
|
|
||||||
GetCleanName()
|
|
||||||
).c_str()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Bot::HasValidAETarget(Bot* botCaster, uint16 spellid, uint16 spellType, Mob* tar) {
|
bool Bot::HasValidAETarget(Bot* botCaster, uint16 spellid, uint16 spellType, Mob* tar) {
|
||||||
int spellRange = botCaster->GetActSpellRange(spellid, spells[spellid].range);
|
int spellRange = botCaster->GetActSpellRange(spellid, spells[spellid].range);
|
||||||
int spellAERange = botCaster->GetActSpellRange(spellid, spells[spellid].aoe_range);
|
int spellAERange = botCaster->GetActSpellRange(spellid, spells[spellid].aoe_range);
|
||||||
|
|||||||
+5
-3
@@ -278,6 +278,7 @@ public:
|
|||||||
void SetHoldFlag(bool flag = true) { m_hold_flag = flag; }
|
void SetHoldFlag(bool flag = true) { m_hold_flag = flag; }
|
||||||
bool GetAttackFlag() const { return m_attack_flag; }
|
bool GetAttackFlag() const { return m_attack_flag; }
|
||||||
void SetAttackFlag(bool flag = true) { m_attack_flag = flag; }
|
void SetAttackFlag(bool flag = true) { m_attack_flag = flag; }
|
||||||
|
bool GetCombatRoundForAlerts() const { return m_combat_round_alert_flag; }
|
||||||
bool GetAttackingFlag() const { return m_attacking_flag; }
|
bool GetAttackingFlag() const { return m_attacking_flag; }
|
||||||
bool GetPullFlag() const { return m_pull_flag; }
|
bool GetPullFlag() const { return m_pull_flag; }
|
||||||
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
|
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
|
||||||
@@ -403,7 +404,7 @@ public:
|
|||||||
void SetGuardMode();
|
void SetGuardMode();
|
||||||
void SetHoldMode();
|
void SetHoldMode();
|
||||||
|
|
||||||
bool IsValidSpellRange(uint16 spell_id, Mob const* tar);
|
bool IsValidSpellRange(uint16 spell_id, Mob* tar);
|
||||||
|
|
||||||
// Bot AI Methods
|
// Bot AI Methods
|
||||||
void AI_Bot_Init();
|
void AI_Bot_Init();
|
||||||
@@ -519,7 +520,6 @@ public:
|
|||||||
void SetHasLoS(bool hasLoS) { _hasLoS = hasLoS; }
|
void SetHasLoS(bool hasLoS) { _hasLoS = hasLoS; }
|
||||||
bool HasLoS() const { return _hasLoS; }
|
bool HasLoS() const { return _hasLoS; }
|
||||||
|
|
||||||
bool IsInGroupOrRaid(bool announce = false);
|
|
||||||
void SendSpellTypesWindow(Client* c, std::string arg0, std::string arg1, std::string arg2, bool helpPrompt = false);
|
void SendSpellTypesWindow(Client* c, std::string arg0, std::string arg1, std::string arg2, bool helpPrompt = false);
|
||||||
|
|
||||||
std::list<BotSpellTypeOrder> GetSpellTypesPrioritized(uint8 priorityType);
|
std::list<BotSpellTypeOrder> GetSpellTypesPrioritized(uint8 priorityType);
|
||||||
@@ -981,7 +981,7 @@ public:
|
|||||||
bool CheckDoubleRangedAttack();
|
bool CheckDoubleRangedAttack();
|
||||||
|
|
||||||
// Public "Refactor" Methods
|
// Public "Refactor" Methods
|
||||||
static bool CheckSpawnConditions(Client* c);
|
static bool CheckCampSpawnConditions(Client* c);
|
||||||
|
|
||||||
inline bool CommandedDoSpellCast(int32 i, Mob* tar, int32 mana_cost) { return AIDoSpellCast(i, tar, mana_cost); }
|
inline bool CommandedDoSpellCast(int32 i, Mob* tar, int32 mana_cost) { return AIDoSpellCast(i, tar, mana_cost); }
|
||||||
|
|
||||||
@@ -1047,6 +1047,7 @@ private:
|
|||||||
bool m_guard_flag;
|
bool m_guard_flag;
|
||||||
bool m_hold_flag;
|
bool m_hold_flag;
|
||||||
bool m_attack_flag;
|
bool m_attack_flag;
|
||||||
|
bool m_combat_round_alert_flag;
|
||||||
bool m_attacking_flag;
|
bool m_attacking_flag;
|
||||||
bool m_pull_flag;
|
bool m_pull_flag;
|
||||||
bool m_pulling_flag;
|
bool m_pulling_flag;
|
||||||
@@ -1104,6 +1105,7 @@ private:
|
|||||||
int32 GenerateBaseManaPoints();
|
int32 GenerateBaseManaPoints();
|
||||||
void GenerateSpecialAttacks();
|
void GenerateSpecialAttacks();
|
||||||
void SetBotID(uint32 botID);
|
void SetBotID(uint32 botID);
|
||||||
|
void SetCombatRoundForAlerts(bool flag = true) { m_combat_round_alert_flag; }
|
||||||
void SetAttackingFlag(bool flag = true) { m_attacking_flag = flag; }
|
void SetAttackingFlag(bool flag = true) { m_attacking_flag = flag; }
|
||||||
void SetPullingFlag(bool flag = true) { m_pulling_flag = flag; }
|
void SetPullingFlag(bool flag = true) { m_pulling_flag = flag; }
|
||||||
void SetReturningFlag(bool flag = true) { m_returning_flag = flag; }
|
void SetReturningFlag(bool flag = true) { m_returning_flag = flag; }
|
||||||
|
|||||||
@@ -30,12 +30,19 @@ void bot_command_bot(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void bot_command_camp(Client *c, const Seperator *sep)
|
void bot_command_camp(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_camp", sep->arg[0], "botcamp"))
|
if (helper_command_alias_fail(c, "bot_command_camp", sep->arg[0], "botcamp")) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
c->Message(Chat::White, "usage: %s ([actionable: target | byname | ownergroup | ownerraid | targetgroup | namesgroup | healrotationtargets | mmr | byclass | byrace | spawned] ([actionable_name]))", sep->arg[0]);
|
c->Message(Chat::White, "usage: %s ([actionable: target | byname | ownergroup | ownerraid | targetgroup | namesgroup | healrotationtargets | mmr | byclass | byrace | spawned] ([actionable_name]))", sep->arg[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Bot::CheckCampSpawnConditions(c)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const int ab_mask = ActionableBots::ABM_Type1;
|
const int ab_mask = ActionableBots::ABM_Type1;
|
||||||
|
|
||||||
std::string class_race_arg = sep->arg[1];
|
std::string class_race_arg = sep->arg[1];
|
||||||
@@ -49,8 +56,14 @@ void bot_command_camp(Client *c, const Seperator *sep)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto bot_iter : sbl)
|
uint16 campCount;
|
||||||
|
|
||||||
|
for (auto bot_iter : sbl) {
|
||||||
bot_iter->Camp();
|
bot_iter->Camp();
|
||||||
|
++campCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(Chat::White, "%i of your bots have been camped.", campCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bot_command_clone(Client *c, const Seperator *sep)
|
void bot_command_clone(Client *c, const Seperator *sep)
|
||||||
@@ -428,6 +441,10 @@ void bot_command_delete(Client *c, const Seperator *sep)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Bot::CheckCampSpawnConditions(c)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto my_bot = ActionableBots::AsTarget_ByBot(c);
|
auto my_bot = ActionableBots::AsTarget_ByBot(c);
|
||||||
if (!my_bot) {
|
if (!my_bot) {
|
||||||
c->Message(Chat::White, "You must <target> a bot that you own to use this command");
|
c->Message(Chat::White, "You must <target> a bot that you own to use this command");
|
||||||
@@ -829,7 +846,7 @@ void bot_command_spawn(Client *c, const Seperator *sep)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Bot::CheckSpawnConditions(c)) {
|
if (!Bot::CheckCampSpawnConditions(c)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ void bot_command_cast(Client* c, const Seperator* sep)
|
|||||||
Bot* firstFound = nullptr;
|
Bot* firstFound = nullptr;
|
||||||
|
|
||||||
for (auto bot_iter : sbl) {
|
for (auto bot_iter : sbl) {
|
||||||
if (!bot_iter->IsInGroupOrRaid()) {
|
if (!bot_iter->IsInGroupOrRaid(c)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +248,14 @@ void bot_command_cast(Client* c, const Seperator* sep)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
BOT_SPELL_TYPES_BENEFICIAL(spellType) &&
|
||||||
|
!RuleB(Bots, CrossRaidBuffingAndHealing) &&
|
||||||
|
!bot_iter->IsInGroupOrRaid(newTar, true)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (BOT_SPELL_TYPES_DETRIMENTAL(spellType, bot_iter->GetClass()) && !bot_iter->IsAttackAllowed(newTar)) {
|
if (BOT_SPELL_TYPES_DETRIMENTAL(spellType, bot_iter->GetClass()) && !bot_iter->IsAttackAllowed(newTar)) {
|
||||||
bot_iter->BotGroupSay(
|
bot_iter->BotGroupSay(
|
||||||
bot_iter,
|
bot_iter,
|
||||||
|
|||||||
+182
-70
@@ -2,47 +2,112 @@
|
|||||||
|
|
||||||
void bot_command_follow(Client* c, const Seperator* sep)
|
void bot_command_follow(Client* c, const Seperator* sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_follow", sep->arg[0], "follow"))
|
if (helper_command_alias_fail(c, "bot_command_follow", sep->arg[0], "follow")) {
|
||||||
return;
|
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
|
||||||
c->Message(Chat::White, "usage: (<friendly_target>) %s ([option: reset]) [actionable: byname | ownergroup | ownerraid | namesgroup | mmr | byclass | byrace | spawned]] ([actionable_name])", sep->arg[0]);
|
|
||||||
c->Message(Chat::White, "usage: %s chain", sep->arg[0]);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
|
std::vector<std::string> description =
|
||||||
|
{
|
||||||
|
"Sets bots of your choosing to follow your target, view their current following state or reset their following state."
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> notes =
|
||||||
|
{
|
||||||
|
"- You can only follow players, bots or mercenaries belonging to your group or raid."
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> example_format =
|
||||||
|
{
|
||||||
|
fmt::format(
|
||||||
|
"{} [optional] [actionable]"
|
||||||
|
, sep->arg[0]
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::vector<std::string> examples_one =
|
||||||
|
{
|
||||||
|
"To set all Clerics to follow your target:",
|
||||||
|
fmt::format(
|
||||||
|
"{} byclass {}",
|
||||||
|
sep->arg[0],
|
||||||
|
Class::Cleric
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::vector<std::string> examples_two =
|
||||||
|
{
|
||||||
|
"To check the current state of all bots:",
|
||||||
|
fmt::format(
|
||||||
|
"{} current spawned",
|
||||||
|
sep->arg[0]
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::vector<std::string> examples_three =
|
||||||
|
{
|
||||||
|
"To reset all bots:",
|
||||||
|
fmt::format(
|
||||||
|
"{} reset spawned",
|
||||||
|
sep->arg[0]
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> actionables =
|
||||||
|
{
|
||||||
|
"target, byname, ownergroup, ownerraid, targetgroup, namesgroup, healrotationtargets, mmr, byclass, byrace, spawned"
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> options = { };
|
||||||
|
std::vector<std::string> options_one = { };
|
||||||
|
std::vector<std::string> options_two = { };
|
||||||
|
std::vector<std::string> options_three = { };
|
||||||
|
|
||||||
|
std::string popup_text = c->SendCommandHelpWindow(
|
||||||
|
c,
|
||||||
|
description,
|
||||||
|
notes,
|
||||||
|
example_format,
|
||||||
|
examples_one, examples_two, examples_three,
|
||||||
|
actionables,
|
||||||
|
options,
|
||||||
|
options_one, options_two, options_three
|
||||||
|
);
|
||||||
|
|
||||||
|
popup_text = DialogueWindow::Table(popup_text);
|
||||||
|
|
||||||
|
c->SendPopupToClient(sep->arg[0], popup_text.c_str());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const int ab_mask = ActionableBots::ABM_Type2;
|
const int ab_mask = ActionableBots::ABM_Type2;
|
||||||
|
|
||||||
|
bool chain = false;
|
||||||
bool reset = false;
|
bool reset = false;
|
||||||
|
bool currentCheck = false;
|
||||||
int ab_arg = 1;
|
int ab_arg = 1;
|
||||||
int name_arg = 2;
|
|
||||||
Mob* target_mob = nullptr;
|
Mob* target_mob = nullptr;
|
||||||
|
|
||||||
std::string optional_arg = sep->arg[1];
|
std::string optional_arg = sep->arg[1];
|
||||||
if (!optional_arg.compare("chain")) {
|
|
||||||
|
|
||||||
auto chain_count = helper_bot_follow_option_chain(c);
|
if (!optional_arg.compare("reset")) {
|
||||||
c->Message(Chat::White, "%i of your bots %s now chain following you", chain_count, (chain_count == 1 ? "is" : "are"));
|
target_mob = c;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!optional_arg.compare("reset")) {
|
|
||||||
reset = true;
|
reset = true;
|
||||||
++ab_arg;
|
++ab_arg;
|
||||||
++name_arg ;
|
}
|
||||||
|
else if (!optional_arg.compare("current")) {
|
||||||
|
currentCheck = true;
|
||||||
|
++ab_arg;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//target_mob = ActionableTarget::VerifyFriendly(c, BCEnum::TT_Single);
|
|
||||||
target_mob = c->GetTarget();
|
target_mob = c->GetTarget();
|
||||||
if (!target_mob) {
|
|
||||||
c->Message(Chat::White, "You must <target> a friendly player or bot within your group or raid to use this command");
|
if (!target_mob || !target_mob->IsOfClientBotMerc() || !c->IsInGroupOrRaid(target_mob)) {
|
||||||
|
c->Message(Chat::Yellow, "You must <target> a friendly player, bot or merc within your group or raid to use this command");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!target_mob->IsBot() && !target_mob->IsClient()) {
|
|
||||||
c->Message(Chat::White, "You must <target> a friendly player or bot within your group or raid to use this command");
|
if (!optional_arg.compare("chain")) {
|
||||||
return;
|
chain = true;
|
||||||
}
|
++ab_arg;
|
||||||
else if ((target_mob->GetGroup() && target_mob->GetGroup() != c->GetGroup()) || (target_mob->GetRaid() && target_mob->GetRaid() != c->GetRaid())) {
|
|
||||||
c->Message(Chat::White, "You must <target> a friendly player or bot within your group or raid to use this command");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,12 +118,66 @@ void bot_command_follow(Client* c, const Seperator* sep)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::list<Bot*> sbl;
|
std::list<Bot*> sbl;
|
||||||
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[name_arg] : nullptr, class_race_check ? atoi(sep->arg[name_arg]) : 0) == ActionableBots::ABT_None) {
|
//if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg] : nullptr, class_race_check ? atoi(sep->arg[ab_arg]) : 0) == ActionableBots::ABT_None) {
|
||||||
|
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sbl.remove(nullptr);
|
sbl.remove(nullptr);
|
||||||
|
|
||||||
|
auto botCount = sbl.size();
|
||||||
|
Mob* follow_mob = nullptr;
|
||||||
|
std::list<Bot*> chainList;
|
||||||
|
std::list<Bot*>::const_iterator it = chainList.begin();
|
||||||
|
uint16 count = 0;
|
||||||
for (auto bot_iter : sbl) {
|
for (auto bot_iter : sbl) {
|
||||||
|
if (currentCheck) {
|
||||||
|
follow_mob = entity_list.GetMob(bot_iter->GetFollowID());
|
||||||
|
c->Message(
|
||||||
|
Chat::Green,
|
||||||
|
fmt::format(
|
||||||
|
"{} says, 'I am currently following {}.'",
|
||||||
|
bot_iter->GetCleanName(),
|
||||||
|
follow_mob ? follow_mob->GetCleanName() : "no one"
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!follow_mob && RuleB(Bots, DoResponseAnimations)) {
|
||||||
|
bot_iter->DoAnim(28);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bot_iter == target_mob) {
|
||||||
|
if (botCount == 1) {
|
||||||
|
c->Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
fmt::format(
|
||||||
|
"{} says, 'I cannot follow myself, you want me to run circles?",
|
||||||
|
bot_iter->GetCleanName()
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (RuleB(Bots, DoResponseAnimations)) {
|
||||||
|
bot_iter->DoAnim(60);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bot_iter->WipeHateList();
|
||||||
|
--botCount;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bot_iter->IsInGroupOrRaid(target_mob)) {
|
||||||
|
--botCount;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bot_iter->WipeHateList();
|
bot_iter->WipeHateList();
|
||||||
|
|
||||||
if (!bot_iter->GetGroup() && !bot_iter->GetRaid()) {
|
if (!bot_iter->GetGroup() && !bot_iter->GetRaid()) {
|
||||||
@@ -71,57 +190,52 @@ void bot_command_follow(Client* c, const Seperator* sep)
|
|||||||
bot_iter->SetManualFollow(false);
|
bot_iter->SetManualFollow(false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (target_mob->IsGrouped() || target_mob->IsRaidGrouped()) {
|
if (chain) {
|
||||||
bot_iter->SetFollowID(target_mob->GetID());
|
Mob* nextTar = target_mob;
|
||||||
bot_iter->SetManualFollow(true);
|
|
||||||
|
if (count > 0) {
|
||||||
|
nextTar = *it;
|
||||||
|
|
||||||
|
if (!nextTar) {
|
||||||
|
nextTar = target_mob;
|
||||||
}
|
}
|
||||||
else if (bot_iter == target_mob) {
|
}
|
||||||
bot_iter->SetFollowID(c->GetID());
|
LogTestDebug("{} is now following {}.", bot_iter->GetCleanName(), nextTar->GetCleanName()); //deleteme
|
||||||
bot_iter->SetManualFollow(true);
|
chainList.push_back(bot_iter);
|
||||||
|
++it;
|
||||||
|
++count;
|
||||||
|
bot_iter->SetFollowID(nextTar->GetID());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bot_iter->SetFollowID(0);
|
bot_iter->SetFollowID(target_mob->GetID());
|
||||||
bot_iter->SetManualFollow(false);
|
}
|
||||||
|
|
||||||
|
bot_iter->SetManualFollow(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//auto my_group = bot_iter->GetGroup();
|
if (!bot_iter->GetPet()) {
|
||||||
//if (my_group) {
|
|
||||||
// if (reset) {
|
|
||||||
// if (!my_group->GetLeader() || my_group->GetLeader() == bot_iter)
|
|
||||||
// bot_iter->SetFollowID(c->GetID());
|
|
||||||
// else
|
|
||||||
// bot_iter->SetFollowID(my_group->GetLeader()->GetID());
|
|
||||||
//
|
|
||||||
// bot_iter->SetManualFollow(false);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// if (bot_iter == target_mob)
|
|
||||||
// bot_iter->SetFollowID(c->GetID());
|
|
||||||
// else
|
|
||||||
// bot_iter->SetFollowID(target_mob->GetID());
|
|
||||||
//
|
|
||||||
// bot_iter->SetManualFollow(true);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//else {
|
|
||||||
// bot_iter->SetFollowID(0);
|
|
||||||
// bot_iter->SetManualFollow(false);
|
|
||||||
//}
|
|
||||||
if (!bot_iter->GetPet())
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bot_iter->GetPet()->WipeHateList();
|
bot_iter->GetPet()->WipeHateList();
|
||||||
bot_iter->GetPet()->SetFollowID(bot_iter->GetID());
|
bot_iter->GetPet()->SetFollowID(bot_iter->GetID());
|
||||||
}
|
}
|
||||||
|
|
||||||
Mob* follow_mob = nullptr;
|
if (currentCheck || !botCount) {
|
||||||
if (sbl.size() == 1) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
follow_mob = target_mob;
|
||||||
|
|
||||||
|
if (botCount == 1) {
|
||||||
follow_mob = entity_list.GetMob(sbl.front()->GetFollowID());
|
follow_mob = entity_list.GetMob(sbl.front()->GetFollowID());
|
||||||
|
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::Green,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Following {}.",
|
"{} says, 'Following {}.'",
|
||||||
|
sbl.front()->GetCleanName(),
|
||||||
follow_mob ? follow_mob->GetCleanName() : "you"
|
follow_mob ? follow_mob->GetCleanName() : "you"
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
@@ -129,22 +243,20 @@ void bot_command_follow(Client* c, const Seperator* sep)
|
|||||||
else {
|
else {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::Green,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"{} of your bots are following you.",
|
"{} of your bots are following you.",
|
||||||
sbl.size()
|
botCount
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!sbl.empty()) {
|
|
||||||
follow_mob = entity_list.GetMob(sbl.front()->GetFollowID());
|
|
||||||
}
|
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::Green,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"{} of your bots are following {}.",
|
"{} of your bots are {} {}.",
|
||||||
sbl.size(),
|
botCount,
|
||||||
|
chain ? "chain following" : "following",
|
||||||
follow_mob ? follow_mob->GetCleanName() : "you"
|
follow_mob ? follow_mob->GetCleanName() : "you"
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -179,8 +179,10 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
|||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (RuleB(Bots, DoResponseAnimations)) {
|
||||||
bot_iter->DoAnim(29);
|
bot_iter->DoAnim(29);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (!equipped_item) {
|
else if (!equipped_item) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::Say,
|
Chat::Say,
|
||||||
@@ -204,8 +206,10 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
|||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (RuleB(Bots, DoResponseAnimations)) {
|
||||||
bot_iter->DoAnim(29);
|
bot_iter->DoAnim(29);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ void bot_command_mesmerize(Client *c, const Seperator *sep)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bot_iter->IsInGroupOrRaid()) {
|
if (!bot_iter->IsInGroupOrRaid(c)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-11
@@ -176,13 +176,7 @@ void Bot::ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite) {
|
|||||||
// If the Bot Owner is in our raid we need to be able to invite their Bots
|
// If the Bot Owner is in our raid we need to be able to invite their Bots
|
||||||
}
|
}
|
||||||
else if (invitee->IsBot() && (invitee->CastToBot()->GetBotOwnerCharacterID() != invitor->CharacterID())) {
|
else if (invitee->IsBot() && (invitee->CastToBot()->GetBotOwnerCharacterID() != invitor->CharacterID())) {
|
||||||
invitor->Message(
|
invitor->Message(Chat::Red, "%s's owner needs to be in your raid to be able to invite them.", invitee->GetCleanName());
|
||||||
Chat::Red,
|
|
||||||
fmt::format(
|
|
||||||
"{} is not your Bot. You can only invite your own Bots, or Bots that belong to a Raid member.",
|
|
||||||
invitee->GetCleanName()
|
|
||||||
).c_str()
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,10 +251,6 @@ void Bot::CreateBotRaid(Mob* invitee, Client* invitor, bool group_invite, Raid*
|
|||||||
} else {
|
} else {
|
||||||
raid->AddBot(b);
|
raid->AddBot(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_raid) {
|
|
||||||
invitee->SetFollowID(invitor->GetID());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+61
-12
@@ -994,11 +994,28 @@ std::list<BotSpell_wPriority> Bot::GetPrioritizedBotSpellsBySpellType(Bot* botCa
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!RuleB(Bots, EnableBotTGB) &&
|
||||||
|
IsGroupSpell(botSpellList[i].spellid) &&
|
||||||
|
!IsTGBCompatibleSpell(botSpellList[i].spellid) &&
|
||||||
|
!botCaster->IsInGroupOrRaid(tar, true)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(
|
(
|
||||||
!botCaster->IsCommandedSpell() || (botCaster->IsCommandedSpell() && (spellType != BotSpellTypes::Mez && spellType != BotSpellTypes::AEMez))
|
!botCaster->IsCommandedSpell() ||
|
||||||
|
(
|
||||||
|
botCaster->IsCommandedSpell() &&
|
||||||
|
(spellType != BotSpellTypes::Mez && spellType != BotSpellTypes::AEMez)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
!IsPBAESpell(botSpellList[i].spellid) &&
|
||||||
|
!botCaster->CastChecks(botSpellList[i].spellid, tar, spellType, false, IsAEBotSpellType(spellType))
|
||||||
)
|
)
|
||||||
&& (!IsPBAESpell(botSpellList[i].spellid) && !botCaster->CastChecks(botSpellList[i].spellid, tar, spellType, false, IsGroupBotSpellType(spellType))) // TODO bot rewrite - needed for ae spells?
|
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1232,7 +1249,15 @@ BotSpell Bot::GetBestBotSpellForGroupHeal(Bot* botCaster, Mob* tar, uint16 spell
|
|||||||
|
|
||||||
if (botCaster) {
|
if (botCaster) {
|
||||||
std::list<BotSpell> botSpellList = GetBotSpellsForSpellEffect(botCaster, spellType, SE_CurrentHP);
|
std::list<BotSpell> botSpellList = GetBotSpellsForSpellEffect(botCaster, spellType, SE_CurrentHP);
|
||||||
const std::vector<Mob*> v = botCaster->GatherSpellTargets();
|
std::vector<Mob*> v;
|
||||||
|
|
||||||
|
if (RuleB(Bots, CrossRaidBuffingAndHealing)) {
|
||||||
|
v = botCaster->GatherSpellTargets(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = botCaster->GatherGroupSpellTargets();
|
||||||
|
}
|
||||||
|
|
||||||
int targetCount = 0;
|
int targetCount = 0;
|
||||||
|
|
||||||
for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
||||||
@@ -1273,7 +1298,15 @@ BotSpell Bot::GetBestBotSpellForGroupHealOverTime(Bot* botCaster, Mob* tar, uint
|
|||||||
|
|
||||||
if (botCaster) {
|
if (botCaster) {
|
||||||
std::list<BotSpell> botSpellList = GetBotSpellsForSpellEffect(botCaster, spellType, SE_HealOverTime);
|
std::list<BotSpell> botSpellList = GetBotSpellsForSpellEffect(botCaster, spellType, SE_HealOverTime);
|
||||||
const std::vector<Mob*> v = botCaster->GatherSpellTargets();
|
std::vector<Mob*> v;
|
||||||
|
|
||||||
|
if (RuleB(Bots, CrossRaidBuffingAndHealing)) {
|
||||||
|
v = botCaster->GatherSpellTargets(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = botCaster->GatherGroupSpellTargets();
|
||||||
|
}
|
||||||
|
|
||||||
int targetCount = 0;
|
int targetCount = 0;
|
||||||
|
|
||||||
for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
||||||
@@ -1314,7 +1347,15 @@ BotSpell Bot::GetBestBotSpellForGroupCompleteHeal(Bot* botCaster, Mob* tar, uint
|
|||||||
|
|
||||||
if (botCaster) {
|
if (botCaster) {
|
||||||
std::list<BotSpell> botSpellList = GetBotSpellsForSpellEffect(botCaster, spellType, SE_CompleteHeal);
|
std::list<BotSpell> botSpellList = GetBotSpellsForSpellEffect(botCaster, spellType, SE_CompleteHeal);
|
||||||
const std::vector<Mob*> v = botCaster->GatherSpellTargets();
|
std::vector<Mob*> v;
|
||||||
|
|
||||||
|
if (RuleB(Bots, CrossRaidBuffingAndHealing)) {
|
||||||
|
v = botCaster->GatherSpellTargets(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = botCaster->GatherGroupSpellTargets();
|
||||||
|
}
|
||||||
|
|
||||||
int targetCount = 0;
|
int targetCount = 0;
|
||||||
|
|
||||||
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
||||||
@@ -1629,7 +1670,7 @@ BotSpell Bot::GetBestBotSpellForNukeByTargetType(Bot* botCaster, SpellTargetType
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsPBAESpell(botSpellListItr->SpellId) && !botCaster->CastChecks(botSpellListItr->SpellId, tar, spellType, false, IsGroupBotSpellType(spellType))) {
|
if (!IsPBAESpell(botSpellListItr->SpellId) && !botCaster->CastChecks(botSpellListItr->SpellId, tar, spellType, false, IsAEBotSpellType(spellType))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1679,7 +1720,7 @@ BotSpell Bot::GetBestBotSpellForStunByTargetType(Bot* botCaster, SpellTargetType
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsPBAESpell(botSpellListItr->SpellId) && !botCaster->CastChecks(botSpellListItr->SpellId, tar, spellType, false, IsGroupBotSpellType(spellType))) {
|
if (!IsPBAESpell(botSpellListItr->SpellId) && !botCaster->CastChecks(botSpellListItr->SpellId, tar, spellType, false, IsAEBotSpellType(spellType))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2583,19 +2624,27 @@ bool Bot::HasBotSpellEntry(uint16 spellid) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::IsValidSpellRange(uint16 spell_id, Mob const* tar) {
|
bool Bot::IsValidSpellRange(uint16 spell_id, Mob* tar) {
|
||||||
if (!IsValidSpell(spell_id)) {
|
if (!IsValidSpell(spell_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tar) {
|
if (tar) {
|
||||||
int spellrange = (GetActSpellRange(spell_id, spells[spell_id].range) * GetActSpellRange(spell_id, spells[spell_id].range));
|
float range = spells[spell_id].range;
|
||||||
if (spellrange >= DistanceSquared(m_Position, tar->GetPosition())) {
|
|
||||||
|
if (tar != this) {
|
||||||
|
range += GetRangeDistTargetSizeMod(tar);
|
||||||
|
}
|
||||||
|
|
||||||
|
range = GetActSpellRange(spell_id, range);
|
||||||
|
|
||||||
|
if (range >= Distance(m_Position, tar->GetPosition())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
spellrange = (GetActSpellRange(spell_id, spells[spell_id].aoe_range) * GetActSpellRange(spell_id, spells[spell_id].aoe_range));
|
range = GetActSpellRange(spell_id, spells[spell_id].aoe_range);
|
||||||
if (spellrange >= DistanceSquared(m_Position, tar->GetPosition())) {
|
|
||||||
|
if (range >= Distance(m_Position, tar->GetPosition())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+126
-12
@@ -1017,6 +1017,27 @@ void Group::GetBotList(std::list<Bot*>& bot_list, bool clear_list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Group::GetRawBotList(std::list<uint32>& bot_list, bool clear_list)
|
||||||
|
{
|
||||||
|
if (clear_list) {
|
||||||
|
bot_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& l = GroupIdRepository::GetWhere(
|
||||||
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"`group_id` = {}",
|
||||||
|
GetID()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const auto& e : l) {
|
||||||
|
if (e.bot_id) {
|
||||||
|
bot_list.push_back(e.bot_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Group::Process() {
|
bool Group::Process() {
|
||||||
if(disbandcheck && !GroupCount())
|
if(disbandcheck && !GroupCount())
|
||||||
return false;
|
return false;
|
||||||
@@ -1234,30 +1255,49 @@ void Group::GroupMessageString(Mob* sender, uint32 type, uint32 string_id, const
|
|||||||
void Client::LeaveGroup() {
|
void Client::LeaveGroup() {
|
||||||
Group *g = GetGroup();
|
Group *g = GetGroup();
|
||||||
|
|
||||||
if(g)
|
if (g) {
|
||||||
{
|
|
||||||
int32 MemberCount = g->GroupCount();
|
int32 MemberCount = g->GroupCount();
|
||||||
// Account for both client and merc leaving the group
|
// Account for both client and merc leaving the group
|
||||||
if (GetMerc() && g == GetMerc()->GetGroup())
|
if (GetMerc() && g == GetMerc()->GetGroup()) {
|
||||||
{
|
|
||||||
MemberCount -= 1;
|
MemberCount -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MemberCount < 3)
|
if (RuleB(Bots, Enabled)) {
|
||||||
{
|
std::list<uint32> sbl;
|
||||||
|
g->GetRawBotList(sbl);
|
||||||
|
|
||||||
|
for (auto botID : sbl) {
|
||||||
|
auto b = entity_list.GetBotByBotID(botID);
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
if (b->GetBotOwnerCharacterID() == CharacterID()) {
|
||||||
|
MemberCount -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (database.botdb.GetOwnerID(botID) == CharacterID()) {
|
||||||
|
MemberCount -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MemberCount < 3) {
|
||||||
g->DisbandGroup();
|
g->DisbandGroup();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
g->DelMember(this);
|
g->DelMember(this);
|
||||||
if (GetMerc() != nullptr && g == GetMerc()->GetGroup() )
|
|
||||||
{
|
if (GetMerc() != nullptr && g == GetMerc()->GetGroup()) {
|
||||||
GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup());
|
GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Bots, Enabled)) {
|
||||||
|
g->RemoveClientsBots(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
else {
|
||||||
//force things a little
|
//force things a little
|
||||||
Group::RemoveFromGroup(this);
|
Group::RemoveFromGroup(this);
|
||||||
|
|
||||||
@@ -2576,3 +2616,77 @@ void Group::AddToGroup(AddToGroupRequest r)
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Group::RemoveClientsBots(Client* c) {
|
||||||
|
std::list<uint32> sbl;
|
||||||
|
GetRawBotList(sbl);
|
||||||
|
|
||||||
|
for (auto botID : sbl) {
|
||||||
|
auto b = entity_list.GetBotByBotID(botID);
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
if (b->GetBotOwnerCharacterID() == c->CharacterID()) {
|
||||||
|
b->RemoveBotFromGroup(b, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (database.botdb.GetOwnerID(botID) == c->CharacterID()) {
|
||||||
|
auto botName = database.botdb.GetBotNameByID(botID);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||||
|
if (membername[i] == botName) {
|
||||||
|
members[i] = nullptr;
|
||||||
|
membername[i][0] = '\0';
|
||||||
|
memset(membername[i], 0, 64);
|
||||||
|
MemberRoles[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pack = new ServerPacket(ServerOP_GroupLeave, sizeof(ServerGroupLeave_Struct));
|
||||||
|
ServerGroupLeave_Struct* gl = (ServerGroupLeave_Struct*)pack->pBuffer;
|
||||||
|
gl->gid = GetID();
|
||||||
|
gl->zoneid = zone->GetZoneID();
|
||||||
|
gl->instance_id = zone->GetInstanceID();
|
||||||
|
strcpy(gl->member_name, botName.c_str());
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
|
||||||
|
GroupJoin_Struct* gu = (GroupJoin_Struct*)outapp->pBuffer;
|
||||||
|
gu->action = groupActLeave;
|
||||||
|
strcpy(gu->membername, botName.c_str());
|
||||||
|
strcpy(gu->yourname, botName.c_str());
|
||||||
|
|
||||||
|
gu->leader_aas = LeaderAbilities;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||||
|
if (members[i] == nullptr) {
|
||||||
|
//if (DEBUG>=5) LogFile->write(EQEMuLog::Debug, "Group::DelMember() null member at slot %i", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (membername[i] != botName.c_str()) {
|
||||||
|
strcpy(gu->yourname, members[i]->GetCleanName());
|
||||||
|
|
||||||
|
if (members[i]->IsClient()) {
|
||||||
|
members[i]->CastToClient()->QueuePacket(outapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_delete(outapp);
|
||||||
|
|
||||||
|
DelMemberOOZ(botName.c_str());
|
||||||
|
|
||||||
|
GroupIdRepository::DeleteWhere(
|
||||||
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"`bot_id` = {}",
|
||||||
|
botID
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ public:
|
|||||||
void GetMemberList(std::list<Mob*>& member_list, bool clear_list = true);
|
void GetMemberList(std::list<Mob*>& member_list, bool clear_list = true);
|
||||||
void GetClientList(std::list<Client*>& client_list, bool clear_list = true);
|
void GetClientList(std::list<Client*>& client_list, bool clear_list = true);
|
||||||
void GetBotList(std::list<Bot*>& bot_list, bool clear_list = true);
|
void GetBotList(std::list<Bot*>& bot_list, bool clear_list = true);
|
||||||
|
void GetRawBotList(std::list<uint32>& bot_list, bool clear_list = true);
|
||||||
bool IsGroupMember(Mob* c);
|
bool IsGroupMember(Mob* c);
|
||||||
bool IsGroupMember(const char* name);
|
bool IsGroupMember(const char* name);
|
||||||
bool Process();
|
bool Process();
|
||||||
@@ -153,6 +154,7 @@ public:
|
|||||||
void AddToGroup(AddToGroupRequest r);
|
void AddToGroup(AddToGroupRequest r);
|
||||||
void AddToGroup(Mob* m);
|
void AddToGroup(Mob* m);
|
||||||
static void RemoveFromGroup(Mob* m);
|
static void RemoveFromGroup(Mob* m);
|
||||||
|
void RemoveClientsBots(Client* c);
|
||||||
|
|
||||||
void SetGroupMentor(int percent, char *name);
|
void SetGroupMentor(int percent, char *name);
|
||||||
void ClearGroupMentor();
|
void ClearGroupMentor();
|
||||||
|
|||||||
+39
-3
@@ -6123,7 +6123,6 @@ bool Mob::IsTargetedFocusEffect(int focus_type) {
|
|||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7311,7 +7310,6 @@ uint16 Mob::GetWeaponSpeedbyHand(uint16 hand) {
|
|||||||
|
|
||||||
uint16 weapon_speed = 0;
|
uint16 weapon_speed = 0;
|
||||||
switch (hand) {
|
switch (hand) {
|
||||||
|
|
||||||
case 13:
|
case 13:
|
||||||
weapon_speed = attack_timer.GetDuration();
|
weapon_speed = attack_timer.GetDuration();
|
||||||
break;
|
break;
|
||||||
@@ -9423,7 +9421,7 @@ bool Mob::TargetValidation(Mob* other) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<uint16, Mob *> &Mob::GetCloseMobList(float distance)
|
std::unordered_map<uint16, Mob*>& Mob::GetCloseMobList(float distance)
|
||||||
{
|
{
|
||||||
return entity_list.GetCloseMobList(this, distance);
|
return entity_list.GetCloseMobList(this, distance);
|
||||||
}
|
}
|
||||||
@@ -9445,3 +9443,41 @@ void Mob::ClearDataBucketCache()
|
|||||||
DataBucket::DeleteFromCache(id, t);
|
DataBucket::DeleteFromCache(id, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mob::IsInGroupOrRaid(Mob *other, bool sameRaidGroup) {
|
||||||
|
if (!other || !IsOfClientBotMerc() || !other->IsOfClientBotMerc()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* r = GetRaid();
|
||||||
|
auto* rO = other->GetRaid();
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
if (!rO || r != rO) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rG = r->GetGroup(GetCleanName());
|
||||||
|
auto rOG = rO->GetGroup(other->GetCleanName());
|
||||||
|
|
||||||
|
if (rG == RAID_GROUPLESS || rOG == RAID_GROUPLESS || (sameRaidGroup && rG != rOG)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto* g = GetGroup();
|
||||||
|
auto* gO = other->GetGroup();
|
||||||
|
|
||||||
|
if (g) {
|
||||||
|
if (!gO || g != gO) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -774,6 +774,7 @@ public:
|
|||||||
virtual bool HasGroup() = 0;
|
virtual bool HasGroup() = 0;
|
||||||
virtual Raid* GetRaid() = 0;
|
virtual Raid* GetRaid() = 0;
|
||||||
virtual Group* GetGroup() = 0;
|
virtual Group* GetGroup() = 0;
|
||||||
|
bool IsInGroupOrRaid(Mob* other, bool sameRaidGroup = false);
|
||||||
|
|
||||||
//Faction
|
//Faction
|
||||||
virtual inline int32 GetPrimaryFaction() const { return 0; }
|
virtual inline int32 GetPrimaryFaction() const { return 0; }
|
||||||
|
|||||||
+41
-7
@@ -2182,14 +2182,42 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
case ST_Group:
|
case ST_Group:
|
||||||
case ST_GroupNoPets:
|
case ST_GroupNoPets:
|
||||||
{
|
{
|
||||||
if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id) && (slot != CastingSlot::Item || RuleB(Spells, AllowItemTGB))) {
|
if (
|
||||||
if( (!target) ||
|
IsClient() && CastToClient()->TGB() &&
|
||||||
(target->IsNPC() && !(target->GetOwner() && target->GetOwner()->IsClient())) ||
|
IsTGBCompatibleSpell(spell_id) &&
|
||||||
(target->IsCorpse()) )
|
(slot != CastingSlot::Item || RuleB(Spells, AllowItemTGB))
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!target ||
|
||||||
|
target->IsCorpse() ||
|
||||||
|
(
|
||||||
|
target->IsNPC() &&
|
||||||
|
!(target->GetOwner() && target->GetOwner()->IsClient())
|
||||||
|
)
|
||||||
|
) {
|
||||||
spell_target = this;
|
spell_target = this;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
spell_target = target;
|
spell_target = target;
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
IsBot() && RuleB(Bots, EnableBotTGB) &&
|
||||||
|
IsTGBCompatibleSpell(spell_id) &&
|
||||||
|
(slot != CastingSlot::Item || RuleB(Spells, AllowItemTGB))
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!spell_target ||
|
||||||
|
spell_target->IsCorpse() ||
|
||||||
|
(
|
||||||
|
spell_target->IsNPC() &&
|
||||||
|
!(spell_target->GetOwner() && spell_target->GetOwner()->IsOfClientBot())
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
spell_target = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
spell_target = this;
|
spell_target = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2516,8 +2544,14 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
|
|||||||
|
|
||||||
//range check our target, if we have one and it is not us
|
//range check our target, if we have one and it is not us
|
||||||
float range = spells[spell_id].range + GetRangeDistTargetSizeMod(spell_target);
|
float range = spells[spell_id].range + GetRangeDistTargetSizeMod(spell_target);
|
||||||
if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id) && IsGroupSpell(spell_id))
|
if (
|
||||||
|
(
|
||||||
|
(IsClient() && CastToClient()->TGB()) || (IsBot() && RuleB(Bots, EnableBotTGB)
|
||||||
|
) &&
|
||||||
|
IsTGBCompatibleSpell(spell_id) && IsGroupSpell(spell_id))
|
||||||
|
) {
|
||||||
range = spells[spell_id].aoe_range;
|
range = spells[spell_id].aoe_range;
|
||||||
|
}
|
||||||
|
|
||||||
range = GetActSpellRange(spell_id, range);
|
range = GetActSpellRange(spell_id, range);
|
||||||
if(IsClient() && IsIllusionSpell(spell_id) && (HasProjectIllusion())){
|
if(IsClient() && IsIllusionSpell(spell_id) && (HasProjectIllusion())){
|
||||||
|
|||||||
Reference in New Issue
Block a user