mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 18:51:29 +00:00
[Quest API] Add Bot Special Attacks for Immune Aggro/Damage (#4108)
* [Quest API] Add Bot Special Attacks for Immune Aggro/Damage # Notes - Adds `IMMUNE_AGGRO_BOT` and `IMMUNE_DAMAGE_BOT` for uses in special abilities. * Cleanup * Update attack.cpp
This commit is contained in:
parent
1d38e473d7
commit
70ee95efc0
@ -698,6 +698,8 @@ const std::map<uint32, std::string>& EQ::constants::GetSpecialAbilityMap()
|
|||||||
{ IMMUNE_OPEN, "Immune to Open" },
|
{ IMMUNE_OPEN, "Immune to Open" },
|
||||||
{ IMMUNE_ASSASSINATE, "Immune to Assassinate" },
|
{ IMMUNE_ASSASSINATE, "Immune to Assassinate" },
|
||||||
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
|
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
|
||||||
|
{ IMMUNE_AGGRO_BOT, "Immune to Bot Aggro" },
|
||||||
|
{ IMMUNE_DAMAGE_BOT, "Immune to Bot Damage" },
|
||||||
};
|
};
|
||||||
|
|
||||||
return special_ability_map;
|
return special_ability_map;
|
||||||
|
|||||||
@ -656,7 +656,9 @@ enum {
|
|||||||
IMMUNE_OPEN = 53,
|
IMMUNE_OPEN = 53,
|
||||||
IMMUNE_ASSASSINATE = 54,
|
IMMUNE_ASSASSINATE = 54,
|
||||||
IMMUNE_HEADSHOT = 55,
|
IMMUNE_HEADSHOT = 55,
|
||||||
MAX_SPECIAL_ATTACK = 56
|
IMMUNE_AGGRO_BOT = 56,
|
||||||
|
IMMUNE_DAMAGE_BOT = 57,
|
||||||
|
MAX_SPECIAL_ATTACK = 58
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -621,28 +621,38 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
|
|||||||
// NPC *npc1, *npc2;
|
// NPC *npc1, *npc2;
|
||||||
int reverse;
|
int reverse;
|
||||||
|
|
||||||
if(!zone->CanDoCombat())
|
if (!zone->CanDoCombat()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// some special cases
|
// some special cases
|
||||||
if(!target)
|
if (!target) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(this == target) // you can attack yourself
|
if (this == target) { // you can attack yourself
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (target->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
if (target->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
|
if (IsBot() && target->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
|
if (IsClient() && target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (target->IsHorse())
|
if (IsNPC() && target->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->IsHorse()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// can't damage own pet (applies to everthing)
|
// can't damage own pet (applies to everthing)
|
||||||
Mob *target_owner = target->GetOwner();
|
Mob *target_owner = target->GetOwner();
|
||||||
|
|||||||
@ -3091,26 +3091,37 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
|||||||
TryTriggerOnCastRequirement();
|
TryTriggerOnCastRequirement();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsClient() && !IsAIControlled())
|
if (IsClient() && !IsAIControlled()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO))
|
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
|
if (other->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient())
|
if (other->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id))
|
if (other->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (other == myowner)
|
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON))
|
if (other == myowner) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetSpecialAbility(NPC_TUNNELVISION)) {
|
if (GetSpecialAbility(NPC_TUNNELVISION)) {
|
||||||
int tv_mod = GetSpecialAbilityParam(NPC_TUNNELVISION, 0);
|
int tv_mod = GetSpecialAbilityParam(NPC_TUNNELVISION, 0);
|
||||||
@ -3194,8 +3205,9 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
|||||||
// owner must get on list, but he's not actually gained any hate yet
|
// owner must get on list, but he's not actually gained any hate yet
|
||||||
if (
|
if (
|
||||||
!owner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
!owner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||||
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && owner->IsClient()) &&
|
!(owner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||||
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && owner->IsNPC())
|
!(owner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||||
|
!(owner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||||
) {
|
) {
|
||||||
if (owner->IsClient() && !CheckAggro(owner)) {
|
if (owner->IsClient() && !CheckAggro(owner)) {
|
||||||
owner->CastToClient()->AddAutoXTarget(this);
|
owner->CastToClient()->AddAutoXTarget(this);
|
||||||
@ -3209,8 +3221,9 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
|||||||
if (
|
if (
|
||||||
!mypet->IsFamiliar() &&
|
!mypet->IsFamiliar() &&
|
||||||
!mypet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
!mypet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||||
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && IsClient()) &&
|
!(IsBot() && mypet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||||
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && IsNPC())
|
!(IsClient() && mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||||
|
!(IsNPC() && mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||||
) {
|
) {
|
||||||
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||||
}
|
}
|
||||||
@ -3219,8 +3232,9 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
|||||||
if (
|
if (
|
||||||
myowner->IsAIControlled() &&
|
myowner->IsAIControlled() &&
|
||||||
!myowner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
!myowner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||||
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && myowner->IsClient()) &&
|
!(myowner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||||
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && myowner->IsNPC())
|
!(myowner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||||
|
!(myowner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||||
) {
|
) {
|
||||||
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||||
}
|
}
|
||||||
@ -4060,8 +4074,9 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
|||||||
!pet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
!pet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||||
!pet->IsEngaged() &&
|
!pet->IsEngaged() &&
|
||||||
attacker &&
|
attacker &&
|
||||||
!(pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
|
!(attacker->IsBot() && pet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||||
!(pet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
|
!(attacker->IsClient() && pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||||
|
!(attacker->IsNPC() && pet->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
|
||||||
attacker != this &&
|
attacker != this &&
|
||||||
!attacker->IsCorpse() &&
|
!attacker->IsCorpse() &&
|
||||||
!pet->IsGHeld() &&
|
!pet->IsGHeld() &&
|
||||||
|
|||||||
@ -4379,8 +4379,9 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
|
|||||||
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
|
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
|
||||||
if (
|
if (
|
||||||
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient()) &&
|
!(other->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
|
!(other->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||||
|
!(other->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||||
) {
|
) {
|
||||||
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||||
}
|
}
|
||||||
@ -4405,8 +4406,9 @@ void EntityList::AddTempPetsToHateListOnOwnerDamage(Mob *owner, Mob* attacker, i
|
|||||||
attacker != n &&
|
attacker != n &&
|
||||||
!n->IsEngaged() &&
|
!n->IsEngaged() &&
|
||||||
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
|
!(attacker->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
|
!(attacker->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||||
|
!(attacker->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
|
||||||
!attacker->IsTrap() &&
|
!attacker->IsTrap() &&
|
||||||
!attacker->IsCorpse()
|
!attacker->IsCorpse()
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -3866,7 +3866,9 @@ luabind::scope lua_register_special_abilities() {
|
|||||||
luabind::value("modify_avoid_damage", static_cast<int>(MODIFY_AVOID_DAMAGE)),
|
luabind::value("modify_avoid_damage", static_cast<int>(MODIFY_AVOID_DAMAGE)),
|
||||||
luabind::value("immune_open", static_cast<int>(IMMUNE_OPEN)),
|
luabind::value("immune_open", static_cast<int>(IMMUNE_OPEN)),
|
||||||
luabind::value("immune_assassinate", static_cast<int>(IMMUNE_ASSASSINATE)),
|
luabind::value("immune_assassinate", static_cast<int>(IMMUNE_ASSASSINATE)),
|
||||||
luabind::value("immune_headshot", static_cast<int>(IMMUNE_HEADSHOT))
|
luabind::value("immune_headshot", static_cast<int>(IMMUNE_HEADSHOT)),
|
||||||
|
luabind::value("immune_aggro_bot", static_cast<int>(IMMUNE_AGGRO_BOT)),
|
||||||
|
luabind::value("immune_damage_bot", static_cast<int>(IMMUNE_DAMAGE_BOT))
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
103
zone/mob.cpp
103
zone/mob.cpp
@ -5204,7 +5204,8 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on, int level_override) {
|
void Mob::ExecWeaponProc(const EQ::ItemInstance* inst, uint16 spell_id, Mob* on, int level_override)
|
||||||
|
{
|
||||||
// Changed proc targets to look up based on the spells goodEffect flag.
|
// Changed proc targets to look up based on the spells goodEffect flag.
|
||||||
// This should work for the majority of weapons.
|
// This should work for the majority of weapons.
|
||||||
if (!on) {
|
if (!on) {
|
||||||
@ -5216,20 +5217,34 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (on->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
|
if (IsBot() && on->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (on->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
|
if (IsClient() && on->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsNoCast())
|
if (IsNPC() && on->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsNoCast()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsValidSpell(spell_id)) { // Check for a valid spell otherwise it will crash through the function
|
if (!IsValidSpell(spell_id)) { // Check for a valid spell otherwise it will crash through the function
|
||||||
if (IsClient()) {
|
if (IsClient()) {
|
||||||
Message(0, "Invalid spell proc %u", spell_id);
|
Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Invalid spell ID for proc {}.",
|
||||||
|
spell_id
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
LogSpells("Player [{}] Weapon Procced invalid spell [{}]", GetName(), spell_id);
|
LogSpells("Player [{}] Weapon Procced invalid spell [{}]", GetName(), spell_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5263,30 +5278,76 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool twinproc = false;
|
bool twin_proc = false;
|
||||||
int32 twinproc_chance = 0;
|
int32 twin_proc_chance = 0;
|
||||||
|
|
||||||
if (IsClient() || IsBot()) {
|
if (IsClient() || IsBot()) {
|
||||||
twinproc_chance = GetFocusEffect(focusTwincast, spell_id);
|
twin_proc_chance = GetFocusEffect(focusTwincast, spell_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (twinproc_chance && zone->random.Roll(twinproc_chance)) {
|
if (twin_proc_chance && zone->random.Roll(twin_proc_chance)) {
|
||||||
twinproc = true;
|
twin_proc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsBeneficialSpell(spell_id) && (!IsNPC() || (IsNPC() && CastToNPC()->GetInnateProcSpellID() != spell_id)) && spells[spell_id].target_type != ST_TargetsTarget) { // NPC innate procs don't take this path ever
|
if (
|
||||||
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
IsBeneficialSpell(spell_id) &&
|
||||||
if (twinproc) {
|
(
|
||||||
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
!IsNPC() ||
|
||||||
|
(
|
||||||
|
IsNPC() &&
|
||||||
|
CastToNPC()->GetInnateProcSpellID() != spell_id
|
||||||
|
)
|
||||||
|
) &&
|
||||||
|
spells[spell_id].target_type != ST_TargetsTarget
|
||||||
|
) { // NPC innate procs don't take this path ever
|
||||||
|
SpellFinished(
|
||||||
|
spell_id,
|
||||||
|
this,
|
||||||
|
EQ::spells::CastingSlot::Item,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
spells[spell_id].resist_difficulty,
|
||||||
|
true,
|
||||||
|
level_override
|
||||||
|
);
|
||||||
|
|
||||||
|
if (twin_proc) {
|
||||||
|
SpellFinished(
|
||||||
|
spell_id,
|
||||||
|
this,
|
||||||
|
EQ::spells::CastingSlot::Item,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
spells[spell_id].resist_difficulty,
|
||||||
|
true,
|
||||||
|
level_override
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
|
||||||
|
SpellFinished(
|
||||||
|
spell_id,
|
||||||
|
on,
|
||||||
|
EQ::spells::CastingSlot::Item,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
spells[spell_id].resist_difficulty,
|
||||||
|
true,
|
||||||
|
level_override
|
||||||
|
);
|
||||||
|
|
||||||
|
if (twin_proc && (!(on->IsClient() && on->CastToClient()->dead))) {
|
||||||
|
SpellFinished(
|
||||||
|
spell_id,
|
||||||
|
on,
|
||||||
|
EQ::spells::CastingSlot::Item,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
spells[spell_id].resist_difficulty,
|
||||||
|
true,
|
||||||
|
level_override
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
|
|
||||||
SpellFinished(spell_id, on, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
|
||||||
if (twinproc && (!(on->IsClient() && on->CastToClient()->dead))) {
|
|
||||||
SpellFinished(spell_id, on, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Mob::GetZoneID() const {
|
uint32 Mob::GetZoneID() const {
|
||||||
|
|||||||
@ -3798,6 +3798,8 @@ void NPC::DescribeSpecialAbilities(Client* c)
|
|||||||
IMMUNE_OPEN,
|
IMMUNE_OPEN,
|
||||||
IMMUNE_ASSASSINATE,
|
IMMUNE_ASSASSINATE,
|
||||||
IMMUNE_HEADSHOT,
|
IMMUNE_HEADSHOT,
|
||||||
|
IMMUNE_AGGRO_BOT,
|
||||||
|
IMMUNE_DAMAGE_BOT
|
||||||
};
|
};
|
||||||
|
|
||||||
// These abilities have parameters that need to be parsed out individually
|
// These abilities have parameters that need to be parsed out individually
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user