mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-15 00:22:27 +00:00
[Spells] Invisibility updates and rework (#1991)
* updates pre merge * update * Update spell_effects.cpp * Update mob.h * test * test * updates * updates * save * update * working solid * animal and undead start * progress * updates * rename * set invis appearance on bonus * remove fade buff state check * update IsViisble check * optimizing * don't break bots * debug remover * Update ruletypes.h * perl adds * Update client_packet.cpp * update * done * remove debugs * Update client_packet.cpp * update * [Spells] Invisibility updates and rework lua support * [Spells] Invisibility updates and rework lua
This commit is contained in:
parent
51c8771bd2
commit
b938e6223c
@ -404,7 +404,7 @@ RULE_BOOL(Spells, July242002PetResists, true, "Enable Pets using PCs resist chan
|
||||
RULE_INT(Spells, AOEMaxTargets, 0, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
|
||||
RULE_BOOL(Spells, CazicTouchTargetsPetOwner, true, "If True, causes Cazic Touch to swap targets from pet to pet owner if a pet is tanking.")
|
||||
RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts and dot removal on charm break to prevent faction wars.")
|
||||
RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible")
|
||||
RULE_BOOL(Spells, AllowDoubleInvis, true, "Allows you to cast invisibility spells on a player that is already invisible, live like behavior.")
|
||||
RULE_BOOL(Spells, AllowSpellMemorizeFromItem, false, "Allows players to memorize spells by right-clicking spell scrolls")
|
||||
RULE_BOOL(Spells, InvisRequiresGroup, false, "Invis requires the the target to be in group.")
|
||||
RULE_INT(Spells, ClericInnateHealFocus, 5, "Clerics on live get a 5 pct innate heal focus")
|
||||
|
||||
@ -191,6 +191,8 @@
|
||||
#define MAX_APPEARANCE_EFFECTS 20 //Up to 20 Appearance Effects can be saved to a mobs appearance effect array, these will be sent to other clients when they enter a zone (This is arbitrary)
|
||||
#define MAX_CAST_ON_SKILL_USE 36 //Actual amount is MAX/3
|
||||
|
||||
#define MAX_INVISIBILTY_LEVEL 254
|
||||
|
||||
//instrument item id's used as song components
|
||||
#define INSTRUMENT_HAND_DRUM 13000
|
||||
#define INSTRUMENT_WOODEN_FLUTE 13001
|
||||
@ -540,6 +542,13 @@ enum ReflectSpellType
|
||||
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
|
||||
REFLECT_ALL_SPELLS = 4,
|
||||
};
|
||||
|
||||
enum InvisType {
|
||||
T_INVISIBLE = 0,
|
||||
T_INVISIBLE_VERSE_UNDEAD = 1,
|
||||
T_INVISIBLE_VERSE_ANIMAL = 2,
|
||||
};
|
||||
|
||||
//For better organizing in proc effects, not used in spells.
|
||||
enum ProcType
|
||||
{
|
||||
@ -1039,7 +1048,7 @@ typedef enum {
|
||||
#define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items
|
||||
#define SE_Invisibility2 314 // implemented - fixed duration invisible
|
||||
#define SE_InvisVsUndead2 315 // implemented - fixed duration ITU
|
||||
//#define SE_ImprovedInvisAnimals 316 // not used
|
||||
#define SE_ImprovedInvisAnimals 316 // implemented
|
||||
#define SE_ItemHPRegenCapIncrease 317 // implemented[AA] - increases amount of health regen gained via items
|
||||
#define SE_ItemManaRegenCapIncrease 318 // implemented - increases amount of mana regen you can gain via items
|
||||
#define SE_CriticalHealOverTime 319 // implemented
|
||||
|
||||
@ -5626,28 +5626,12 @@ void Mob::DoShieldDamageOnShielder(Mob *shield_target, int hit_damage_done, EQ::
|
||||
void Mob::CommonBreakInvisibleFromCombat()
|
||||
{
|
||||
//break invis when you attack
|
||||
if (invisible) {
|
||||
LogCombat("Removing invisibility due to melee attack");
|
||||
BuffFadeByEffect(SE_Invisibility);
|
||||
BuffFadeByEffect(SE_Invisibility2);
|
||||
invisible = false;
|
||||
}
|
||||
if (invisible_undead) {
|
||||
LogCombat("Removing invisibility vs. undead due to melee attack");
|
||||
BuffFadeByEffect(SE_InvisVsUndead);
|
||||
BuffFadeByEffect(SE_InvisVsUndead2);
|
||||
invisible_undead = false;
|
||||
}
|
||||
if (invisible_animals) {
|
||||
LogCombat("Removing invisibility vs. animals due to melee attack");
|
||||
BuffFadeByEffect(SE_InvisVsAnimals);
|
||||
invisible_animals = false;
|
||||
}
|
||||
|
||||
BreakInvisibleSpells();
|
||||
CancelSneakHide();
|
||||
|
||||
if (spellbonuses.NegateIfCombat)
|
||||
if (spellbonuses.NegateIfCombat) {
|
||||
BuffFadeByEffect(SE_NegateIfCombat);
|
||||
}
|
||||
|
||||
hidden = false;
|
||||
improved_hidden = false;
|
||||
|
||||
@ -47,6 +47,8 @@ void Mob::CalcBonuses()
|
||||
CalcMaxMana();
|
||||
SetAttackTimer();
|
||||
CalcAC();
|
||||
CalcSeeInvisibleLevel();
|
||||
CalcInvisibleLevel();
|
||||
|
||||
/* Fast walking NPC's are prone to disappear into walls/hills
|
||||
We set this here because NPC's can cast spells to change walkspeed/runspeed
|
||||
@ -81,6 +83,9 @@ void Client::CalcBonuses()
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
CalcAABonuses(&aabonuses);
|
||||
|
||||
CalcSeeInvisibleLevel();
|
||||
CalcInvisibleLevel();
|
||||
|
||||
ProcessItemCaps(); // caps that depend on spell/aa bonuses
|
||||
|
||||
RecalcWeight();
|
||||
@ -867,7 +872,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
newbon->MaxBindWound += base_value;
|
||||
break;
|
||||
case SE_SeeInvis:
|
||||
newbon->SeeInvis = base_value;
|
||||
base_value = std::min({ base_value, MAX_INVISIBILTY_LEVEL });
|
||||
if (newbon->SeeInvis < base_value) {
|
||||
newbon->SeeInvis = base_value;
|
||||
}
|
||||
break;
|
||||
case SE_BaseMovementSpeed:
|
||||
newbon->BaseMovementSpeed += base_value;
|
||||
@ -3825,6 +3833,32 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Invisibility:
|
||||
case SE_Invisibility2:
|
||||
effect_value = std::min({ effect_value, MAX_INVISIBILTY_LEVEL });
|
||||
if (new_bonus->invisibility < effect_value)
|
||||
new_bonus->invisibility = effect_value;
|
||||
break;
|
||||
|
||||
case SE_InvisVsUndead:
|
||||
case SE_InvisVsUndead2:
|
||||
if (new_bonus->invisibility_verse_undead < effect_value)
|
||||
new_bonus->invisibility_verse_undead = effect_value;
|
||||
break;
|
||||
|
||||
case SE_InvisVsAnimals:
|
||||
effect_value = std::min({ effect_value, MAX_INVISIBILTY_LEVEL });
|
||||
if (new_bonus->invisibility_verse_animal < effect_value)
|
||||
new_bonus->invisibility_verse_animal = effect_value;
|
||||
break;
|
||||
|
||||
case SE_SeeInvis:
|
||||
effect_value = std::min({ effect_value, MAX_INVISIBILTY_LEVEL });
|
||||
if (new_bonus->SeeInvis < effect_value) {
|
||||
new_bonus->SeeInvis = effect_value;
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_ZoneSuspendMinion:
|
||||
new_bonus->ZoneSuspendMinion = effect_value;
|
||||
break;
|
||||
|
||||
@ -7438,6 +7438,8 @@ void Bot::CalcBonuses() {
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
CalcAABonuses(&aabonuses);
|
||||
SetAttackTimer();
|
||||
CalcSeeInvisibleLevel();
|
||||
CalcInvisibleLevel();
|
||||
CalcATK();
|
||||
CalcSTR();
|
||||
CalcSTA();
|
||||
|
||||
@ -109,7 +109,7 @@ public:
|
||||
} AType;
|
||||
static const int AilmentTypeCount = 5;
|
||||
|
||||
typedef enum InvisibilityType {
|
||||
typedef enum InvisType {
|
||||
IT_None = 0,
|
||||
IT_Animal,
|
||||
IT_Undead,
|
||||
|
||||
@ -3454,7 +3454,6 @@ void Client::Escape()
|
||||
{
|
||||
entity_list.RemoveFromTargets(this, true);
|
||||
SetInvisible(Invisibility::Invisible);
|
||||
|
||||
MessageString(Chat::Skills, ESCAPE);
|
||||
}
|
||||
|
||||
|
||||
@ -682,8 +682,7 @@ void Client::CompleteConnect()
|
||||
case SE_Invisibility2:
|
||||
case SE_Invisibility:
|
||||
{
|
||||
invisible = true;
|
||||
SendAppearancePacket(AT_Invis, 1);
|
||||
SendAppearancePacket(AT_Invis, Invisibility::Invisible);
|
||||
break;
|
||||
}
|
||||
case SE_Levitate:
|
||||
@ -707,17 +706,6 @@ void Client::CompleteConnect()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_InvisVsUndead2:
|
||||
case SE_InvisVsUndead:
|
||||
{
|
||||
invisible_undead = true;
|
||||
break;
|
||||
}
|
||||
case SE_InvisVsAnimals:
|
||||
{
|
||||
invisible_animals = true;
|
||||
break;
|
||||
}
|
||||
case SE_AddMeleeProc:
|
||||
case SE_WeaponProc:
|
||||
{
|
||||
@ -3819,6 +3807,9 @@ void Client::Handle_OP_BoardBoat(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_Buff(const EQApplicationPacket *app)
|
||||
{
|
||||
/*
|
||||
Note: if invisibility is on client, this will force it to drop.
|
||||
*/
|
||||
if (app->size != sizeof(SpellBuffPacket_Struct))
|
||||
{
|
||||
LogError("Size mismatch in OP_Buff. expected [{}] got [{}]", sizeof(SpellBuffPacket_Struct), app->size);
|
||||
@ -3833,10 +3824,12 @@ void Client::Handle_OP_Buff(const EQApplicationPacket *app)
|
||||
//something about IsDetrimentalSpell() crashes this portion of code..
|
||||
//tbh we shouldn't use it anyway since this is a simple red vs blue buff check and
|
||||
//isdetrimentalspell() is much more complex
|
||||
if (spid == 0xFFFF || (IsValidSpell(spid) && (spells[spid].good_effect == 0)))
|
||||
if (spid == 0xFFFF || (IsValidSpell(spid) && (spells[spid].good_effect == 0))) {
|
||||
QueuePacket(app);
|
||||
else
|
||||
}
|
||||
else {
|
||||
BuffFadeBySpellID(spid);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@ -3990,12 +3983,20 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
if (invisible) {
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||
BuffFadeByEffect(SE_Invisibility);
|
||||
BuffFadeByEffect(SE_Invisibility2);
|
||||
}
|
||||
|
||||
// Hack for broken RoF2 which allows casting after a zoned IVU/IVA
|
||||
if (invisible_undead || invisible_animals) {
|
||||
BuffFadeByEffect(SE_InvisVsAnimals);
|
||||
if (invisible_undead) {
|
||||
BuffFadeByEffect(SE_InvisVsUndead);
|
||||
BuffFadeByEffect(SE_InvisVsUndead2);
|
||||
BuffFadeByEffect(SE_Invisibility); // Included per JJ for completeness - client handles this one atm
|
||||
}
|
||||
if (invisible_animals) {
|
||||
BuffFadeByEffect(SE_InvisVsAnimals);
|
||||
BuffFadeByEffect(SE_ImprovedInvisAnimals);
|
||||
}
|
||||
|
||||
CastSpell_Struct* castspell = (CastSpell_Struct*)app->pBuffer;
|
||||
@ -4826,7 +4827,7 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
|
||||
|
||||
// this could be done better, but this is only called when you con so w/e
|
||||
// Shroud of Stealth has a special message
|
||||
if (improved_hidden && (!tmob->see_improved_hide && (tmob->see_invis || tmob->see_hide)))
|
||||
if (improved_hidden && (!tmob->see_improved_hide && (tmob->SeeInvisible() || tmob->see_hide)))
|
||||
MessageString(Chat::NPCQuestSay, SOS_KEEPS_HIDDEN);
|
||||
// we are trying to hide but they can see us
|
||||
else if ((invisible || invisible_undead || hidden || invisible_animals) && !IsInvisible(tmob))
|
||||
@ -13565,7 +13566,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
}
|
||||
return;
|
||||
}
|
||||
invisible = false;
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||
hidden = false;
|
||||
improved_hidden = false;
|
||||
entity_list.QueueClients(this, app, true);
|
||||
|
||||
@ -1163,9 +1163,9 @@ void Client::BreakInvis()
|
||||
sa_out->parameter = 0;
|
||||
entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
invisible = false;
|
||||
invisible_undead = false;
|
||||
invisible_animals = false;
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_UNDEAD);
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_ANIMAL);
|
||||
hidden = false;
|
||||
improved_hidden = false;
|
||||
}
|
||||
|
||||
@ -561,6 +561,9 @@ struct StatBonuses {
|
||||
bool ZoneSuspendMinion; // base 1 allows suspended minions to zone
|
||||
bool CompleteHealBuffBlocker; // Use in SPA 101 to prevent recast of complete heal from this effect till blocker buff is removed.
|
||||
int32 Illusion; // illusion spell id
|
||||
uint8 invisibility; // invisibility level
|
||||
uint8 invisibility_verse_undead; // IVU level
|
||||
uint8 invisibility_verse_animal; // IVA level
|
||||
|
||||
// AAs
|
||||
int32 TrapCircumvention; // reduce chance to trigger a trap.
|
||||
|
||||
@ -2118,7 +2118,7 @@ uint8 Lua_Mob::SeeInvisible() {
|
||||
return self->SeeInvisible();
|
||||
}
|
||||
|
||||
bool Lua_Mob::SeeInvisibleUndead() {
|
||||
uint8 Lua_Mob::SeeInvisibleUndead() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SeeInvisibleUndead();
|
||||
}
|
||||
@ -2423,6 +2423,31 @@ Lua_NPC Lua_Mob::GetHateRandomNPC() {
|
||||
return Lua_NPC(self->GetHateRandomNPC());
|
||||
}
|
||||
|
||||
uint8 Lua_Mob::GetInvisibleLevel()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetInvisibleLevel();
|
||||
}
|
||||
|
||||
uint8 Lua_Mob::GetInvisibleUndeadLevel()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetInvisibleUndeadLevel();
|
||||
}
|
||||
|
||||
void Lua_Mob::SetSeeInvisibleLevel(uint8 invisible_level)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetInnateSeeInvisible(invisible_level);
|
||||
self->CalcSeeInvisibleLevel();
|
||||
}
|
||||
|
||||
void Lua_Mob::SetSeeInvisibleUndeadLevel(uint8 invisible_level)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetSeeInvisibleUndead(invisible_level);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_mob() {
|
||||
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
||||
.def(luabind::constructor<>())
|
||||
@ -2618,6 +2643,8 @@ luabind::scope lua_register_mob() {
|
||||
.def("GetHelmTexture", &Lua_Mob::GetHelmTexture)
|
||||
.def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel)
|
||||
.def("GetINT", &Lua_Mob::GetINT)
|
||||
.def("GetInvisibleLevel", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetInvisibleLevel)
|
||||
.def("GetInvisibleUndeadLevel", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetInvisibleUndeadLevel)
|
||||
.def("GetInvul", (bool(Lua_Mob::*)(void))&Lua_Mob::GetInvul)
|
||||
.def("GetItemBonuses", &Lua_Mob::GetItemBonuses)
|
||||
.def("GetItemHPBonuses", &Lua_Mob::GetItemHPBonuses)
|
||||
@ -2763,7 +2790,9 @@ luabind::scope lua_register_mob() {
|
||||
.def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide)
|
||||
.def("SeeImprovedHide", (bool(Lua_Mob::*)(bool))&Lua_Mob::SeeImprovedHide)
|
||||
.def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible)
|
||||
.def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead)
|
||||
.def("SeeInvisibleUndead", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead)
|
||||
.def("SetSeeInvisibleLevel", (void(Lua_Mob::*)(uint8))&Lua_Mob::SetSeeInvisibleLevel)
|
||||
.def("SetSeeInvisibleUndeadLevel", (void(Lua_Mob::*)(uint8))&Lua_Mob::SetSeeInvisibleUndeadLevel)
|
||||
.def("SendAppearanceEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,uint32,uint32))&Lua_Mob::SendAppearanceEffect)
|
||||
.def("SendAppearanceEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,uint32,uint32,Lua_Client))&Lua_Mob::SendAppearanceEffect)
|
||||
.def("SendBeginCast", &Lua_Mob::SendBeginCast)
|
||||
|
||||
@ -86,6 +86,10 @@ public:
|
||||
bool IsInvisible();
|
||||
bool IsInvisible(Lua_Mob other);
|
||||
void SetInvisible(int state);
|
||||
uint8 GetInvisibleLevel();
|
||||
uint8 GetInvisibleUndeadLevel();
|
||||
void SetSeeInvisibleLevel(uint8 invisible_level);
|
||||
void SetSeeInvisibleUndeadLevel(uint8 invisible_level);
|
||||
bool FindBuff(int spell_id);
|
||||
uint16 FindBuffBySlot(int slot);
|
||||
uint32 BuffCount();
|
||||
@ -406,7 +410,7 @@ public:
|
||||
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
|
||||
void SetPseudoRoot(bool in);
|
||||
uint8 SeeInvisible();
|
||||
bool SeeInvisibleUndead();
|
||||
uint8 SeeInvisibleUndead();
|
||||
bool SeeHide();
|
||||
bool SeeImprovedHide();
|
||||
uint8 GetNimbusEffect1();
|
||||
|
||||
156
zone/mob.cpp
156
zone/mob.cpp
@ -81,8 +81,8 @@ Mob::Mob(
|
||||
uint32 in_drakkin_details,
|
||||
EQ::TintProfile in_armor_tint,
|
||||
uint8 in_aa_title,
|
||||
uint8 in_see_invis, // see through invis/ivu
|
||||
uint8 in_see_invis_undead,
|
||||
uint16 in_see_invis, // see through invis/ivu
|
||||
uint16 in_see_invis_undead,
|
||||
uint8 in_see_hide,
|
||||
uint8 in_see_improved_hide,
|
||||
int32 in_hp_regen,
|
||||
@ -269,8 +269,8 @@ Mob::Mob(
|
||||
maxlevel = in_maxlevel;
|
||||
scalerate = in_scalerate;
|
||||
invisible = 0;
|
||||
invisible_undead = false;
|
||||
invisible_animals = false;
|
||||
invisible_undead = 0;
|
||||
invisible_animals = 0;
|
||||
sneaking = false;
|
||||
hidden = false;
|
||||
improved_hidden = false;
|
||||
@ -440,10 +440,13 @@ Mob::Mob(
|
||||
pStandingPetOrder = SPO_Follow;
|
||||
pseudo_rooted = false;
|
||||
|
||||
see_invis = GetSeeInvisible(in_see_invis);
|
||||
see_invis_undead = GetSeeInvisible(in_see_invis_undead);
|
||||
see_hide = GetSeeInvisible(in_see_hide);
|
||||
see_improved_hide = GetSeeInvisible(in_see_improved_hide);
|
||||
nobuff_invisible = 0;
|
||||
see_invis = 0;
|
||||
|
||||
innate_see_invis = GetSeeInvisibleLevelFromNPCStat(in_see_invis);
|
||||
see_invis_undead = GetSeeInvisibleLevelFromNPCStat(in_see_invis_undead);
|
||||
see_hide = GetSeeInvisibleLevelFromNPCStat(in_see_hide);
|
||||
see_improved_hide = GetSeeInvisibleLevelFromNPCStat(in_see_improved_hide);
|
||||
|
||||
qglobal = in_qglobal != 0;
|
||||
|
||||
@ -584,10 +587,52 @@ uint32 Mob::GetAppearanceValue(EmuAppearance iAppearance) {
|
||||
return(ANIM_STAND);
|
||||
}
|
||||
|
||||
void Mob::SetInvisible(uint8 state)
|
||||
|
||||
void Mob::CalcSeeInvisibleLevel()
|
||||
{
|
||||
if (state != Invisibility::Special) {
|
||||
invisible = state;
|
||||
see_invis = std::max({ spellbonuses.SeeInvis, itembonuses.SeeInvis, aabonuses.SeeInvis, innate_see_invis });
|
||||
}
|
||||
|
||||
void Mob::CalcInvisibleLevel()
|
||||
{
|
||||
bool is_invisible = invisible;
|
||||
|
||||
invisible = std::max({ spellbonuses.invisibility, nobuff_invisible });
|
||||
invisible_undead = spellbonuses.invisibility_verse_undead;
|
||||
invisible_animals = spellbonuses.invisibility_verse_animal;
|
||||
|
||||
if (!is_invisible && invisible) {
|
||||
SetInvisible(Invisibility::Invisible, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_invisible && !invisible) {
|
||||
SetInvisible(invisible, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetInvisible(uint8 state, bool set_on_bonus_calc)
|
||||
{
|
||||
/*
|
||||
If you set an NPC to invisible you will only be able to see it on
|
||||
your client if your see invisible level is greater than equal to the invisible level.
|
||||
Note, the clients spell file must match the servers see invisible level on the spell.
|
||||
*/
|
||||
|
||||
if (state == Invisibility::Visible) {
|
||||
SendAppearancePacket(AT_Invis, Invisibility::Visible);
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
if your setting invisible from a script, or escape/fading memories effect then
|
||||
we use the internal invis variable which allows invisible without a buff on mob.
|
||||
*/
|
||||
if (!set_on_bonus_calc) {
|
||||
nobuff_invisible = state;
|
||||
CalcInvisibleLevel();
|
||||
}
|
||||
SendAppearancePacket(AT_Invis, invisible);
|
||||
}
|
||||
|
||||
@ -597,35 +642,53 @@ void Mob::SetInvisible(uint8 state)
|
||||
if (RuleB(Pets, LivelikeBreakCharmOnInvis) || IsInvisible(pet)) {
|
||||
pet->BuffFadeByEffect(SE_Charm);
|
||||
}
|
||||
|
||||
LogRules("Pets:LivelikeBreakCharmOnInvis for [{}] | Invis [{}] - Hidden [{}] - Shroud of Stealth [{}] - IVA [{}] - IVU [{}]", GetCleanName(), invisible, hidden, improved_hidden, invisible_animals, invisible_undead);
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::ZeroInvisibleVars(uint8 invisible_type)
|
||||
{
|
||||
switch (invisible_type) {
|
||||
|
||||
case T_INVISIBLE:
|
||||
invisible = 0;
|
||||
nobuff_invisible = 0;
|
||||
break;
|
||||
|
||||
case T_INVISIBLE_VERSE_UNDEAD:
|
||||
invisible_undead = 0;
|
||||
break;
|
||||
|
||||
case T_INVISIBLE_VERSE_ANIMAL:
|
||||
invisible_animals = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if `this` is invisible to `other`
|
||||
bool Mob::IsInvisible(Mob* other) const
|
||||
{
|
||||
if(!other)
|
||||
if (!other) {
|
||||
return(false);
|
||||
|
||||
uint8 SeeInvisBonus = 0;
|
||||
if (IsClient())
|
||||
SeeInvisBonus = aabonuses.SeeInvis;
|
||||
}
|
||||
|
||||
//check regular invisibility
|
||||
if (invisible && invisible > (other->SeeInvisible()))
|
||||
if (invisible && (invisible > other->SeeInvisible())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//check invis vs. undead
|
||||
if (other->GetBodyType() == BT_Undead || other->GetBodyType() == BT_SummonedUndead) {
|
||||
if(invisible_undead && !other->SeeInvisibleUndead())
|
||||
if (invisible_undead && (invisible_undead > other->SeeInvisibleUndead())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//check invis vs. animals...
|
||||
//check invis vs. animals. //TODO: should we have a specific see invisible animal stat or this how live does it?
|
||||
if (other->GetBodyType() == BT_Animal){
|
||||
if(invisible_animals && !other->SeeInvisible())
|
||||
if (invisible_animals && (invisible_animals > other->SeeInvisible())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(hidden){
|
||||
@ -642,8 +705,9 @@ bool Mob::IsInvisible(Mob* other) const
|
||||
|
||||
//handle sneaking
|
||||
if(sneaking) {
|
||||
if(BehindMob(other, GetX(), GetY()) )
|
||||
if (BehindMob(other, GetX(), GetY())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return(false);
|
||||
@ -6110,19 +6174,47 @@ float Mob::HeadingAngleToMob(float other_x, float other_y)
|
||||
return CalculateHeadingAngleBetweenPositions(this_x, this_y, other_x, other_y);
|
||||
}
|
||||
|
||||
bool Mob::GetSeeInvisible(uint8 see_invis)
|
||||
uint8 Mob::GetSeeInvisibleLevelFromNPCStat(uint16 in_see_invis)
|
||||
{
|
||||
if(see_invis > 0)
|
||||
{
|
||||
if(see_invis == 1)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
if (zone->random.Int(0, 99) < see_invis)
|
||||
return true;
|
||||
/*
|
||||
Returns the NPC's see invisible level based on 'see_invs' value in npc_types.
|
||||
1 = See Invs Level 1, 2-99 will gives a random roll to apply see invs level 1
|
||||
100 = See Invs Level 2, where 101-199 gives a random roll to apply see invs 2, if fails get see invs 1
|
||||
ect... for higher levels, 200,300 ect.
|
||||
MAX 25499, which can give you level 254.
|
||||
*/
|
||||
|
||||
//npc does not have see invis
|
||||
if (!in_see_invis) {
|
||||
return 0;
|
||||
}
|
||||
//npc has basic see invis
|
||||
if (in_see_invis == 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//random chance to apply standard level 1 see invs
|
||||
if (in_see_invis > 1 && in_see_invis < 100) {
|
||||
if (zone->random.Int(0, 99) < in_see_invis) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
//covers npcs with see invis levels beyond level 1, max calculated level allowed is 254
|
||||
int see_invis_level = 1;
|
||||
see_invis_level += (in_see_invis / 100);
|
||||
|
||||
int see_invis_chance = in_see_invis % 100;
|
||||
|
||||
//has enhanced see invis level
|
||||
if (see_invis_chance == 0) {
|
||||
return std::min(see_invis_level, MAX_INVISIBILTY_LEVEL);
|
||||
}
|
||||
//has chance for enhanced see invis level
|
||||
if (zone->random.Int(0, 99) < see_invis_chance) {
|
||||
return std::min(see_invis_level, MAX_INVISIBILTY_LEVEL);
|
||||
}
|
||||
//failed chance at attempted enhanced see invs level, use previous level.
|
||||
return std::min((see_invis_level - 1), MAX_INVISIBILTY_LEVEL);
|
||||
}
|
||||
|
||||
int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
|
||||
|
||||
55
zone/mob.h
55
zone/mob.h
@ -147,8 +147,8 @@ public:
|
||||
uint32 in_drakkin_details,
|
||||
EQ::TintProfile in_armor_tint,
|
||||
uint8 in_aa_title,
|
||||
uint8 in_see_invis, // see through invis
|
||||
uint8 in_see_invis_undead, // see through invis vs. undead
|
||||
uint16 in_see_invis, // see through invis
|
||||
uint16 in_see_invis_undead, // see through invis vs. undead
|
||||
uint8 in_see_hide,
|
||||
uint8 in_see_improved_hide,
|
||||
int32 in_hp_regen,
|
||||
@ -226,10 +226,6 @@ public:
|
||||
virtual inline bool IsBerserk() { return false; } // only clients
|
||||
void RogueEvade(Mob *other);
|
||||
void CommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
||||
void BreakInvisibleSpells();
|
||||
virtual void CancelSneakHide();
|
||||
void CommonBreakInvisible();
|
||||
void CommonBreakInvisibleFromCombat();
|
||||
bool HasDied();
|
||||
virtual bool CheckDualWield();
|
||||
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
||||
@ -246,6 +242,39 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
//Invisible
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
void SetInvisible(uint8 state, bool set_on_bonus_calc = false);
|
||||
|
||||
void CalcSeeInvisibleLevel();
|
||||
void CalcInvisibleLevel();
|
||||
void ZeroInvisibleVars(uint8 invisible_type);
|
||||
|
||||
inline uint8 GetSeeInvisibleLevelFromNPCStat(uint16 in_see_invis);
|
||||
|
||||
void BreakInvisibleSpells();
|
||||
virtual void CancelSneakHide();
|
||||
void CommonBreakInvisible();
|
||||
void CommonBreakInvisibleFromCombat();
|
||||
|
||||
inline uint8 GetInvisibleLevel() const { return invisible; }
|
||||
inline uint8 GetInvisibleUndeadLevel() const { return invisible_undead; }
|
||||
|
||||
inline bool SeeHide() const { return see_hide; }
|
||||
inline bool SeeImprovedHide() const { return see_improved_hide; }
|
||||
inline uint8 SeeInvisibleUndead() const { return see_invis_undead; }
|
||||
inline uint8 SeeInvisible() const { return see_invis; }
|
||||
|
||||
inline void SetInnateSeeInvisible(uint8 val) { innate_see_invis = val; }
|
||||
inline void SetSeeInvisibleUndead(uint8 val) { see_invis_undead = val; }
|
||||
|
||||
uint32 tmHidden; // timestamp of hide, only valid while hidden == true
|
||||
uint8 invisible, nobuff_invisible, invisible_undead, invisible_animals;
|
||||
uint8 see_invis, innate_see_invis, see_invis_undead; //TODO: do we need a see_invis_animal ?
|
||||
|
||||
bool sneaking, hidden, improved_hidden;
|
||||
bool see_hide, see_improved_hide;
|
||||
|
||||
/**
|
||||
************************************************
|
||||
* Appearance
|
||||
@ -254,16 +283,8 @@ public:
|
||||
|
||||
EQ::InternalTextureProfile mob_texture_profile = {};
|
||||
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
|
||||
EQ::skills::SkillType AttackAnimation(int Hand, const EQ::ItemInstance* weapon, EQ::skills::SkillType skillinuse = EQ::skills::Skill1HBlunt);
|
||||
|
||||
inline bool GetSeeInvisible(uint8 see_invis);
|
||||
inline bool SeeHide() const { return see_hide; }
|
||||
inline bool SeeImprovedHide() const { return see_improved_hide; }
|
||||
inline bool SeeInvisibleUndead() const { return see_invis_undead; }
|
||||
inline uint8 SeeInvisible() const { return see_invis; }
|
||||
|
||||
int32 GetTextureProfileMaterial(uint8 material_slot) const;
|
||||
int32 GetTextureProfileColor(uint8 material_slot) const;
|
||||
int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const;
|
||||
@ -282,7 +303,6 @@ public:
|
||||
void SendLevelAppearance();
|
||||
void SendStunAppearance();
|
||||
void SendTargetable(bool on, Client *specific_target = nullptr);
|
||||
void SetInvisible(uint8 state);
|
||||
void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0);
|
||||
|
||||
//Spell
|
||||
@ -974,10 +994,7 @@ public:
|
||||
inline const bodyType GetOrigBodyType() const { return orig_bodytype; }
|
||||
void SetBodyType(bodyType new_body, bool overwrite_orig);
|
||||
|
||||
uint32 tmHidden; // timestamp of hide, only valid while hidden == true
|
||||
uint8 invisible, see_invis;
|
||||
bool invulnerable, invisible_undead, invisible_animals, sneaking, hidden, improved_hidden;
|
||||
bool see_invis_undead, see_hide, see_improved_hide;
|
||||
bool invulnerable;
|
||||
bool qglobal;
|
||||
|
||||
virtual void SetAttackTimer();
|
||||
|
||||
@ -916,6 +916,35 @@ XS(XS_Mob_SetInvisible) {
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_SetSeeInvisibleLevel); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SetSeeInvisibleLevel) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::SetSeeInvisibleLevel(THIS, uint8 see_invis_level)"); // @categories Script Utility
|
||||
{
|
||||
Mob *THIS;
|
||||
uint8 see_invis_level = (uint8)SvUV(ST(1));
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
THIS->SetInnateSeeInvisible(see_invis_level);
|
||||
THIS->CalcSeeInvisibleLevel();
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_SetSeeInvisibleUndeadLevel); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SetSeeInvisibleUndeadLevel) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::SetSeeInvisibleUndeadLevel(THIS, uint8 see_invis_undead_level)"); // @categories Script Utility
|
||||
{
|
||||
Mob *THIS;
|
||||
uint8 see_invis_undead_level = (uint8)SvUV(ST(1));
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
THIS->SetSeeInvisibleUndead(see_invis_undead_level);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_FindBuff); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_FindBuff) {
|
||||
dXSARGS;
|
||||
@ -5777,6 +5806,41 @@ XS(XS_Mob_IsBlind) {
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetInvisibleLevel);
|
||||
XS(XS_Mob_GetInvisibleLevel) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetInvisibleLevel(THIS)"); // @categories Stats and Attributes
|
||||
{
|
||||
Mob *THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
RETVAL = THIS->GetInvisibleLevel();
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetInvisibleUndeadLevel);
|
||||
XS(XS_Mob_GetInvisibleUndeadLevel) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetInvisibleUndeadLevel(THIS)"); // @categories Stats and Attributes
|
||||
{
|
||||
Mob *THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
RETVAL = THIS->GetInvisibleUndeadLevel();
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
|
||||
XS(XS_Mob_SeeInvisible);
|
||||
XS(XS_Mob_SeeInvisible) {
|
||||
dXSARGS;
|
||||
@ -5801,11 +5865,12 @@ XS(XS_Mob_SeeInvisibleUndead) {
|
||||
Perl_croak(aTHX_ "Usage: Mob::SeeInvisibleUndead(THIS)"); // @categories Stats and Attributes
|
||||
{
|
||||
Mob *THIS;
|
||||
bool RETVAL;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
RETVAL = THIS->SeeInvisibleUndead();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@ -6698,6 +6763,8 @@ XS(boot_Mob) {
|
||||
newXSproto(strcpy(buf, "GetHerosForgeModel"), XS_Mob_GetHerosForgeModel, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetID"), XS_Mob_GetID, file, "$");
|
||||
newXSproto(strcpy(buf, "GetINT"), XS_Mob_GetINT, file, "$");
|
||||
newXSproto(strcpy(buf, "GetInvisibleLevel"), XS_Mob_GetInvisibleLevel, file, "$");
|
||||
newXSproto(strcpy(buf, "GetInvisibleUndeadLevel"), XS_Mob_GetInvisibleUndeadLevel, file, "$");
|
||||
newXSproto(strcpy(buf, "GetInvul"), XS_Mob_GetInvul, file, "$");
|
||||
newXSproto(strcpy(buf, "GetItemHPBonuses"), XS_Mob_GetItemHPBonuses, file, "$");
|
||||
newXSproto(strcpy(buf, "GetItemStat"), XS_Mob_GetItemStat, file, "$$$");
|
||||
@ -6877,6 +6944,8 @@ XS(boot_Mob) {
|
||||
newXSproto(strcpy(buf, "SetRace"), XS_Mob_SetRace, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetRunAnimSpeed"), XS_Mob_SetRunAnimSpeed, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetRunning"), XS_Mob_SetRunning, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetSeeInvisibleLevel"), XS_Mob_SetSeeInvisibleLevel, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetSeeInvisibleUndeadLevel"), XS_Mob_SetSeeInvisibleUndeadLevel, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetSlotTint"), XS_Mob_SetSlotTint, file, "$$$$$");
|
||||
newXSproto(strcpy(buf, "SetSpecialAbility"), XS_Mob_SetSpecialAbility, file, "$$$");
|
||||
newXSproto(strcpy(buf, "SetSpecialAbilityParam"), XS_Mob_SetSpecialAbilityParam, file, "$$$$");
|
||||
|
||||
@ -583,45 +583,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Invisibility:
|
||||
case SE_Invisibility2:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Invisibility");
|
||||
#endif
|
||||
SetInvisible(spell.base_value[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_InvisVsAnimals:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Invisibility to Animals");
|
||||
#endif
|
||||
invisible_animals = true;
|
||||
SetInvisible(Invisibility::Special);
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_InvisVsUndead2:
|
||||
case SE_InvisVsUndead:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Invisibility to Undead");
|
||||
#endif
|
||||
invisible_undead = true;
|
||||
SetInvisible(Invisibility::Special);
|
||||
break;
|
||||
}
|
||||
case SE_SeeInvis:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "See Invisible");
|
||||
#endif
|
||||
see_invis = spell.base_value[i];
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_FleshToBone:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
@ -3277,6 +3238,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
case SE_Proc_Timer_Modifier:
|
||||
case SE_FFItemClass:
|
||||
case SE_SpellEffectResistChance:
|
||||
case SE_SeeInvis:
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -3946,10 +3908,13 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
|
||||
}
|
||||
}
|
||||
}
|
||||
case SE_ImprovedInvisAnimals:
|
||||
case SE_Invisibility2:
|
||||
case SE_InvisVsUndead2: {
|
||||
if (buff.ticsremaining <= 3 && buff.ticsremaining > 1) {
|
||||
MessageString(Chat::Spells, INVIS_BEGIN_BREAK);
|
||||
if (!IsBardSong(buff.spellid)) {
|
||||
if (buff.ticsremaining <= 3 && buff.ticsremaining > 1) {
|
||||
MessageString(Chat::Spells, INVIS_BEGIN_BREAK);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -4186,32 +4151,6 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Invisibility2:
|
||||
case SE_Invisibility:
|
||||
{
|
||||
SetInvisible(Invisibility::Visible);
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_InvisVsUndead2:
|
||||
case SE_InvisVsUndead:
|
||||
{
|
||||
invisible_undead = false; // Mongrel: No longer IVU
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_InvisVsAnimals:
|
||||
{
|
||||
invisible_animals = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SeeInvis:
|
||||
{
|
||||
see_invis = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Silence:
|
||||
{
|
||||
Silence(false);
|
||||
@ -9580,18 +9519,19 @@ void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster)
|
||||
void Mob::BreakInvisibleSpells()
|
||||
{
|
||||
if(invisible) {
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||
BuffFadeByEffect(SE_Invisibility);
|
||||
BuffFadeByEffect(SE_Invisibility2);
|
||||
invisible = false;
|
||||
}
|
||||
if(invisible_undead) {
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_UNDEAD);
|
||||
BuffFadeByEffect(SE_InvisVsUndead);
|
||||
BuffFadeByEffect(SE_InvisVsUndead2);
|
||||
invisible_undead = false;
|
||||
}
|
||||
if(invisible_animals){
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_ANIMAL);
|
||||
BuffFadeByEffect(SE_ImprovedInvisAnimals);
|
||||
BuffFadeByEffect(SE_InvisVsAnimals);
|
||||
invisible_animals = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9600,22 +9540,20 @@ void Client::BreakSneakWhenCastOn(Mob *caster, bool IsResisted)
|
||||
bool IsCastersTarget = false; // Chance to avoid only applies to AOE spells when not targeted.
|
||||
if (hidden || improved_hidden) {
|
||||
if (caster) {
|
||||
Mob *target = nullptr;
|
||||
target = caster->GetTarget();
|
||||
IsCastersTarget = target && target == this;
|
||||
Mob *spell_target = caster->GetTarget();
|
||||
if (spell_target && spell_target == this) {
|
||||
IsCastersTarget = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsCastersTarget) {
|
||||
int chance =
|
||||
spellbonuses.NoBreakAESneak + itembonuses.NoBreakAESneak + aabonuses.NoBreakAESneak;
|
||||
|
||||
if (IsResisted)
|
||||
int chance = spellbonuses.NoBreakAESneak + itembonuses.NoBreakAESneak + aabonuses.NoBreakAESneak;
|
||||
if (IsResisted) {
|
||||
chance *= 2;
|
||||
|
||||
if (chance && zone->random.Roll(chance))
|
||||
}
|
||||
if (chance && zone->random.Roll(chance)) {
|
||||
return; // Do not drop Sneak/Hide
|
||||
}
|
||||
}
|
||||
|
||||
CancelSneakHide();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3622,7 +3622,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes
|
||||
|
||||
// Prevent double invising, which made you uninvised
|
||||
// Not sure if all 3 should be stacking
|
||||
|
||||
//This is not live like behavior (~Kayen confirmed 2/2/22)
|
||||
if (!RuleB(Spells, AllowDoubleInvis)) {
|
||||
if (IsEffectInSpell(spell_id, SE_Invisibility))
|
||||
{
|
||||
|
||||
@ -108,8 +108,8 @@ struct NPCType
|
||||
int32 mana_regen;
|
||||
int32 aggroradius; // added for AI improvement - neotokyo
|
||||
int32 assistradius; // assist radius, defaults to aggroradis if not set
|
||||
uint8 see_invis; // See Invis flag added
|
||||
bool see_invis_undead; // See Invis vs. Undead flag added
|
||||
uint16 see_invis; // See Invis flag added
|
||||
uint16 see_invis_undead; // See Invis vs. Undead flag added
|
||||
bool see_hide;
|
||||
bool see_improved_hide;
|
||||
bool qglobal;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user