mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16: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_ASSASSINATE, "Immune to Assassinate" },
|
||||
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
|
||||
{ IMMUNE_AGGRO_BOT, "Immune to Bot Aggro" },
|
||||
{ IMMUNE_DAMAGE_BOT, "Immune to Bot Damage" },
|
||||
};
|
||||
|
||||
return special_ability_map;
|
||||
|
||||
@ -656,7 +656,9 @@ enum {
|
||||
IMMUNE_OPEN = 53,
|
||||
IMMUNE_ASSASSINATE = 54,
|
||||
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;
|
||||
int reverse;
|
||||
|
||||
if(!zone->CanDoCombat())
|
||||
return false;
|
||||
|
||||
// some special cases
|
||||
if(!target)
|
||||
return false;
|
||||
|
||||
if(this == target) // you can attack yourself
|
||||
return true;
|
||||
|
||||
if(target->GetSpecialAbility(NO_HARM_FROM_CLIENT)){
|
||||
if (!zone->CanDoCombat()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
|
||||
// some special cases
|
||||
if (!target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
|
||||
return false;
|
||||
if (this == target) { // you can attack yourself
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target->IsHorse())
|
||||
if (target->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsBot() && target->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsClient() && target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsNPC() && target->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->IsHorse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// can't damage own pet (applies to everthing)
|
||||
Mob *target_owner = target->GetOwner();
|
||||
|
||||
@ -3091,26 +3091,37 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
TryTriggerOnCastRequirement();
|
||||
}
|
||||
|
||||
if (IsClient() && !IsAIControlled())
|
||||
if (IsClient() && !IsAIControlled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO))
|
||||
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
|
||||
if (other->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient())
|
||||
if (other->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id))
|
||||
if (other->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other == myowner)
|
||||
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON))
|
||||
if (other == myowner) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSpecialAbility(NPC_TUNNELVISION)) {
|
||||
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
|
||||
if (
|
||||
!owner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && owner->IsClient()) &&
|
||||
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && owner->IsNPC())
|
||||
!(owner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(owner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(owner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
) {
|
||||
if (owner->IsClient() && !CheckAggro(owner)) {
|
||||
owner->CastToClient()->AddAutoXTarget(this);
|
||||
@ -3209,8 +3221,9 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
if (
|
||||
!mypet->IsFamiliar() &&
|
||||
!mypet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && IsClient()) &&
|
||||
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && IsNPC())
|
||||
!(IsBot() && mypet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(IsClient() && mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(IsNPC() && mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
) {
|
||||
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 (
|
||||
myowner->IsAIControlled() &&
|
||||
!myowner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && myowner->IsClient()) &&
|
||||
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && myowner->IsNPC())
|
||||
!(myowner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(myowner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(myowner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
) {
|
||||
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->IsEngaged() &&
|
||||
attacker &&
|
||||
!(pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
|
||||
!(pet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
|
||||
!(attacker->IsBot() && pet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(attacker->IsClient() && pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(attacker->IsNPC() && pet->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
|
||||
attacker != this &&
|
||||
!attacker->IsCorpse() &&
|
||||
!pet->IsGHeld() &&
|
||||
|
||||
@ -4379,8 +4379,9 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
|
||||
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
|
||||
if (
|
||||
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient()) &&
|
||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
|
||||
!(other->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(other->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(other->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
) {
|
||||
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
@ -4405,8 +4406,9 @@ void EntityList::AddTempPetsToHateListOnOwnerDamage(Mob *owner, Mob* attacker, i
|
||||
attacker != n &&
|
||||
!n->IsEngaged() &&
|
||||
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
|
||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
|
||||
!(attacker->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(attacker->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(attacker->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
|
||||
!attacker->IsTrap() &&
|
||||
!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("immune_open", static_cast<int>(IMMUNE_OPEN)),
|
||||
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))
|
||||
)];
|
||||
}
|
||||
|
||||
|
||||
111
zone/mob.cpp
111
zone/mob.cpp
@ -5204,32 +5204,47 @@ 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.
|
||||
// This should work for the majority of weapons.
|
||||
if (!on) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!IsValidSpell(spell_id) || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
if (!IsValidSpell(spell_id) || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
//This is so 65535 doesn't get passed to the client message and to logs because it is not relavant information for debugging.
|
||||
return;
|
||||
}
|
||||
|
||||
if (on->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
|
||||
if (IsBot() && on->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (on->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
|
||||
if (IsClient() && on->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsNoCast())
|
||||
if (IsNPC() && on->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!IsValidSpell(spell_id)) { // Check for a valid spell otherwise it will crash through the function
|
||||
if(IsClient()){
|
||||
Message(0, "Invalid spell proc %u", spell_id);
|
||||
if (IsNoCast()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsValidSpell(spell_id)) { // Check for a valid spell otherwise it will crash through the function
|
||||
if (IsClient()) {
|
||||
Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Invalid spell ID for proc {}.",
|
||||
spell_id
|
||||
).c_str()
|
||||
);
|
||||
LogSpells("Player [{}] Weapon Procced invalid spell [{}]", GetName(), spell_id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5243,7 +5258,7 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on,
|
||||
return;
|
||||
}
|
||||
|
||||
if(inst && IsClient()) {
|
||||
if (inst && IsClient()) {
|
||||
//const cast is dirty but it would require redoing a ton of interfaces at this point
|
||||
//It should be safe as we don't have any truly const EQ::ItemInstance floating around anywhere.
|
||||
//So we'll live with it for now
|
||||
@ -5263,30 +5278,76 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on,
|
||||
}
|
||||
}
|
||||
|
||||
bool twinproc = false;
|
||||
int32 twinproc_chance = 0;
|
||||
bool twin_proc = false;
|
||||
int32 twin_proc_chance = 0;
|
||||
|
||||
if (IsClient() || IsBot()) {
|
||||
twinproc_chance = GetFocusEffect(focusTwincast, spell_id);
|
||||
twin_proc_chance = GetFocusEffect(focusTwincast, spell_id);
|
||||
}
|
||||
|
||||
if (twinproc_chance && zone->random.Roll(twinproc_chance)) {
|
||||
twinproc = true;
|
||||
if (twin_proc_chance && zone->random.Roll(twin_proc_chance)) {
|
||||
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
|
||||
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
||||
if (twinproc) {
|
||||
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
||||
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
|
||||
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 {
|
||||
|
||||
@ -3798,6 +3798,8 @@ void NPC::DescribeSpecialAbilities(Client* c)
|
||||
IMMUNE_OPEN,
|
||||
IMMUNE_ASSASSINATE,
|
||||
IMMUNE_HEADSHOT,
|
||||
IMMUNE_AGGRO_BOT,
|
||||
IMMUNE_DAMAGE_BOT
|
||||
};
|
||||
|
||||
// These abilities have parameters that need to be parsed out individually
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user