mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-15 08:42:26 +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_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, 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, 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, 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_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")
|
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_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_CAST_ON_SKILL_USE 36 //Actual amount is MAX/3
|
||||||
|
|
||||||
|
#define MAX_INVISIBILTY_LEVEL 254
|
||||||
|
|
||||||
//instrument item id's used as song components
|
//instrument item id's used as song components
|
||||||
#define INSTRUMENT_HAND_DRUM 13000
|
#define INSTRUMENT_HAND_DRUM 13000
|
||||||
#define INSTRUMENT_WOODEN_FLUTE 13001
|
#define INSTRUMENT_WOODEN_FLUTE 13001
|
||||||
@ -540,6 +542,13 @@ enum ReflectSpellType
|
|||||||
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
|
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
|
||||||
REFLECT_ALL_SPELLS = 4,
|
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.
|
//For better organizing in proc effects, not used in spells.
|
||||||
enum ProcType
|
enum ProcType
|
||||||
{
|
{
|
||||||
@ -1039,7 +1048,7 @@ typedef enum {
|
|||||||
#define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items
|
#define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items
|
||||||
#define SE_Invisibility2 314 // implemented - fixed duration invisible
|
#define SE_Invisibility2 314 // implemented - fixed duration invisible
|
||||||
#define SE_InvisVsUndead2 315 // implemented - fixed duration ITU
|
#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_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_ItemManaRegenCapIncrease 318 // implemented - increases amount of mana regen you can gain via items
|
||||||
#define SE_CriticalHealOverTime 319 // implemented
|
#define SE_CriticalHealOverTime 319 // implemented
|
||||||
|
|||||||
@ -5626,28 +5626,12 @@ void Mob::DoShieldDamageOnShielder(Mob *shield_target, int hit_damage_done, EQ::
|
|||||||
void Mob::CommonBreakInvisibleFromCombat()
|
void Mob::CommonBreakInvisibleFromCombat()
|
||||||
{
|
{
|
||||||
//break invis when you attack
|
//break invis when you attack
|
||||||
if (invisible) {
|
BreakInvisibleSpells();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
CancelSneakHide();
|
CancelSneakHide();
|
||||||
|
|
||||||
if (spellbonuses.NegateIfCombat)
|
if (spellbonuses.NegateIfCombat) {
|
||||||
BuffFadeByEffect(SE_NegateIfCombat);
|
BuffFadeByEffect(SE_NegateIfCombat);
|
||||||
|
}
|
||||||
|
|
||||||
hidden = false;
|
hidden = false;
|
||||||
improved_hidden = false;
|
improved_hidden = false;
|
||||||
|
|||||||
@ -47,6 +47,8 @@ void Mob::CalcBonuses()
|
|||||||
CalcMaxMana();
|
CalcMaxMana();
|
||||||
SetAttackTimer();
|
SetAttackTimer();
|
||||||
CalcAC();
|
CalcAC();
|
||||||
|
CalcSeeInvisibleLevel();
|
||||||
|
CalcInvisibleLevel();
|
||||||
|
|
||||||
/* Fast walking NPC's are prone to disappear into walls/hills
|
/* 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
|
We set this here because NPC's can cast spells to change walkspeed/runspeed
|
||||||
@ -81,6 +83,9 @@ void Client::CalcBonuses()
|
|||||||
CalcSpellBonuses(&spellbonuses);
|
CalcSpellBonuses(&spellbonuses);
|
||||||
CalcAABonuses(&aabonuses);
|
CalcAABonuses(&aabonuses);
|
||||||
|
|
||||||
|
CalcSeeInvisibleLevel();
|
||||||
|
CalcInvisibleLevel();
|
||||||
|
|
||||||
ProcessItemCaps(); // caps that depend on spell/aa bonuses
|
ProcessItemCaps(); // caps that depend on spell/aa bonuses
|
||||||
|
|
||||||
RecalcWeight();
|
RecalcWeight();
|
||||||
@ -867,7 +872,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
newbon->MaxBindWound += base_value;
|
newbon->MaxBindWound += base_value;
|
||||||
break;
|
break;
|
||||||
case SE_SeeInvis:
|
case SE_SeeInvis:
|
||||||
|
base_value = std::min({ base_value, MAX_INVISIBILTY_LEVEL });
|
||||||
|
if (newbon->SeeInvis < base_value) {
|
||||||
newbon->SeeInvis = base_value;
|
newbon->SeeInvis = base_value;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SE_BaseMovementSpeed:
|
case SE_BaseMovementSpeed:
|
||||||
newbon->BaseMovementSpeed += base_value;
|
newbon->BaseMovementSpeed += base_value;
|
||||||
@ -3825,6 +3833,32 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
|||||||
break;
|
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:
|
case SE_ZoneSuspendMinion:
|
||||||
new_bonus->ZoneSuspendMinion = effect_value;
|
new_bonus->ZoneSuspendMinion = effect_value;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -7438,6 +7438,8 @@ void Bot::CalcBonuses() {
|
|||||||
CalcSpellBonuses(&spellbonuses);
|
CalcSpellBonuses(&spellbonuses);
|
||||||
CalcAABonuses(&aabonuses);
|
CalcAABonuses(&aabonuses);
|
||||||
SetAttackTimer();
|
SetAttackTimer();
|
||||||
|
CalcSeeInvisibleLevel();
|
||||||
|
CalcInvisibleLevel();
|
||||||
CalcATK();
|
CalcATK();
|
||||||
CalcSTR();
|
CalcSTR();
|
||||||
CalcSTA();
|
CalcSTA();
|
||||||
|
|||||||
@ -109,7 +109,7 @@ public:
|
|||||||
} AType;
|
} AType;
|
||||||
static const int AilmentTypeCount = 5;
|
static const int AilmentTypeCount = 5;
|
||||||
|
|
||||||
typedef enum InvisibilityType {
|
typedef enum InvisType {
|
||||||
IT_None = 0,
|
IT_None = 0,
|
||||||
IT_Animal,
|
IT_Animal,
|
||||||
IT_Undead,
|
IT_Undead,
|
||||||
|
|||||||
@ -3454,7 +3454,6 @@ void Client::Escape()
|
|||||||
{
|
{
|
||||||
entity_list.RemoveFromTargets(this, true);
|
entity_list.RemoveFromTargets(this, true);
|
||||||
SetInvisible(Invisibility::Invisible);
|
SetInvisible(Invisibility::Invisible);
|
||||||
|
|
||||||
MessageString(Chat::Skills, ESCAPE);
|
MessageString(Chat::Skills, ESCAPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -682,8 +682,7 @@ void Client::CompleteConnect()
|
|||||||
case SE_Invisibility2:
|
case SE_Invisibility2:
|
||||||
case SE_Invisibility:
|
case SE_Invisibility:
|
||||||
{
|
{
|
||||||
invisible = true;
|
SendAppearancePacket(AT_Invis, Invisibility::Invisible);
|
||||||
SendAppearancePacket(AT_Invis, 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_Levitate:
|
case SE_Levitate:
|
||||||
@ -707,17 +706,6 @@ void Client::CompleteConnect()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_InvisVsUndead2:
|
|
||||||
case SE_InvisVsUndead:
|
|
||||||
{
|
|
||||||
invisible_undead = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_InvisVsAnimals:
|
|
||||||
{
|
|
||||||
invisible_animals = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_AddMeleeProc:
|
case SE_AddMeleeProc:
|
||||||
case SE_WeaponProc:
|
case SE_WeaponProc:
|
||||||
{
|
{
|
||||||
@ -3819,6 +3807,9 @@ void Client::Handle_OP_BoardBoat(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_OP_Buff(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))
|
if (app->size != sizeof(SpellBuffPacket_Struct))
|
||||||
{
|
{
|
||||||
LogError("Size mismatch in OP_Buff. expected [{}] got [{}]", sizeof(SpellBuffPacket_Struct), app->size);
|
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..
|
//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
|
//tbh we shouldn't use it anyway since this is a simple red vs blue buff check and
|
||||||
//isdetrimentalspell() is much more complex
|
//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);
|
QueuePacket(app);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
BuffFadeBySpellID(spid);
|
BuffFadeBySpellID(spid);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3990,12 +3983,20 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
return;
|
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
|
// Hack for broken RoF2 which allows casting after a zoned IVU/IVA
|
||||||
if (invisible_undead || invisible_animals) {
|
if (invisible_undead) {
|
||||||
BuffFadeByEffect(SE_InvisVsAnimals);
|
|
||||||
BuffFadeByEffect(SE_InvisVsUndead);
|
BuffFadeByEffect(SE_InvisVsUndead);
|
||||||
BuffFadeByEffect(SE_InvisVsUndead2);
|
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;
|
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
|
// this could be done better, but this is only called when you con so w/e
|
||||||
// Shroud of Stealth has a special message
|
// 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);
|
MessageString(Chat::NPCQuestSay, SOS_KEEPS_HIDDEN);
|
||||||
// we are trying to hide but they can see us
|
// we are trying to hide but they can see us
|
||||||
else if ((invisible || invisible_undead || hidden || invisible_animals) && !IsInvisible(tmob))
|
else if ((invisible || invisible_undead || hidden || invisible_animals) && !IsInvisible(tmob))
|
||||||
@ -13565,7 +13566,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
invisible = false;
|
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||||
hidden = false;
|
hidden = false;
|
||||||
improved_hidden = false;
|
improved_hidden = false;
|
||||||
entity_list.QueueClients(this, app, true);
|
entity_list.QueueClients(this, app, true);
|
||||||
|
|||||||
@ -1163,9 +1163,9 @@ void Client::BreakInvis()
|
|||||||
sa_out->parameter = 0;
|
sa_out->parameter = 0;
|
||||||
entity_list.QueueClients(this, outapp, true);
|
entity_list.QueueClients(this, outapp, true);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
invisible = false;
|
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||||
invisible_undead = false;
|
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_UNDEAD);
|
||||||
invisible_animals = false;
|
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_ANIMAL);
|
||||||
hidden = false;
|
hidden = false;
|
||||||
improved_hidden = false;
|
improved_hidden = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -561,6 +561,9 @@ struct StatBonuses {
|
|||||||
bool ZoneSuspendMinion; // base 1 allows suspended minions to zone
|
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.
|
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
|
int32 Illusion; // illusion spell id
|
||||||
|
uint8 invisibility; // invisibility level
|
||||||
|
uint8 invisibility_verse_undead; // IVU level
|
||||||
|
uint8 invisibility_verse_animal; // IVA level
|
||||||
|
|
||||||
// AAs
|
// AAs
|
||||||
int32 TrapCircumvention; // reduce chance to trigger a trap.
|
int32 TrapCircumvention; // reduce chance to trigger a trap.
|
||||||
|
|||||||
@ -2118,7 +2118,7 @@ uint8 Lua_Mob::SeeInvisible() {
|
|||||||
return self->SeeInvisible();
|
return self->SeeInvisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::SeeInvisibleUndead() {
|
uint8 Lua_Mob::SeeInvisibleUndead() {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->SeeInvisibleUndead();
|
return self->SeeInvisibleUndead();
|
||||||
}
|
}
|
||||||
@ -2423,6 +2423,31 @@ Lua_NPC Lua_Mob::GetHateRandomNPC() {
|
|||||||
return Lua_NPC(self->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() {
|
luabind::scope lua_register_mob() {
|
||||||
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -2618,6 +2643,8 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("GetHelmTexture", &Lua_Mob::GetHelmTexture)
|
.def("GetHelmTexture", &Lua_Mob::GetHelmTexture)
|
||||||
.def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel)
|
.def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel)
|
||||||
.def("GetINT", &Lua_Mob::GetINT)
|
.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("GetInvul", (bool(Lua_Mob::*)(void))&Lua_Mob::GetInvul)
|
||||||
.def("GetItemBonuses", &Lua_Mob::GetItemBonuses)
|
.def("GetItemBonuses", &Lua_Mob::GetItemBonuses)
|
||||||
.def("GetItemHPBonuses", &Lua_Mob::GetItemHPBonuses)
|
.def("GetItemHPBonuses", &Lua_Mob::GetItemHPBonuses)
|
||||||
@ -2763,7 +2790,9 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide)
|
.def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide)
|
||||||
.def("SeeImprovedHide", (bool(Lua_Mob::*)(bool))&Lua_Mob::SeeImprovedHide)
|
.def("SeeImprovedHide", (bool(Lua_Mob::*)(bool))&Lua_Mob::SeeImprovedHide)
|
||||||
.def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible)
|
.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_Mob::SendAppearanceEffect)
|
||||||
.def("SendAppearanceEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,uint32,uint32,Lua_Client))&Lua_Mob::SendAppearanceEffect)
|
.def("SendAppearanceEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,uint32,uint32,Lua_Client))&Lua_Mob::SendAppearanceEffect)
|
||||||
.def("SendBeginCast", &Lua_Mob::SendBeginCast)
|
.def("SendBeginCast", &Lua_Mob::SendBeginCast)
|
||||||
|
|||||||
@ -86,6 +86,10 @@ public:
|
|||||||
bool IsInvisible();
|
bool IsInvisible();
|
||||||
bool IsInvisible(Lua_Mob other);
|
bool IsInvisible(Lua_Mob other);
|
||||||
void SetInvisible(int state);
|
void SetInvisible(int state);
|
||||||
|
uint8 GetInvisibleLevel();
|
||||||
|
uint8 GetInvisibleUndeadLevel();
|
||||||
|
void SetSeeInvisibleLevel(uint8 invisible_level);
|
||||||
|
void SetSeeInvisibleUndeadLevel(uint8 invisible_level);
|
||||||
bool FindBuff(int spell_id);
|
bool FindBuff(int spell_id);
|
||||||
uint16 FindBuffBySlot(int slot);
|
uint16 FindBuffBySlot(int slot);
|
||||||
uint32 BuffCount();
|
uint32 BuffCount();
|
||||||
@ -406,7 +410,7 @@ public:
|
|||||||
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
|
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
|
||||||
void SetPseudoRoot(bool in);
|
void SetPseudoRoot(bool in);
|
||||||
uint8 SeeInvisible();
|
uint8 SeeInvisible();
|
||||||
bool SeeInvisibleUndead();
|
uint8 SeeInvisibleUndead();
|
||||||
bool SeeHide();
|
bool SeeHide();
|
||||||
bool SeeImprovedHide();
|
bool SeeImprovedHide();
|
||||||
uint8 GetNimbusEffect1();
|
uint8 GetNimbusEffect1();
|
||||||
|
|||||||
166
zone/mob.cpp
166
zone/mob.cpp
@ -81,8 +81,8 @@ Mob::Mob(
|
|||||||
uint32 in_drakkin_details,
|
uint32 in_drakkin_details,
|
||||||
EQ::TintProfile in_armor_tint,
|
EQ::TintProfile in_armor_tint,
|
||||||
uint8 in_aa_title,
|
uint8 in_aa_title,
|
||||||
uint8 in_see_invis, // see through invis/ivu
|
uint16 in_see_invis, // see through invis/ivu
|
||||||
uint8 in_see_invis_undead,
|
uint16 in_see_invis_undead,
|
||||||
uint8 in_see_hide,
|
uint8 in_see_hide,
|
||||||
uint8 in_see_improved_hide,
|
uint8 in_see_improved_hide,
|
||||||
int32 in_hp_regen,
|
int32 in_hp_regen,
|
||||||
@ -269,8 +269,8 @@ Mob::Mob(
|
|||||||
maxlevel = in_maxlevel;
|
maxlevel = in_maxlevel;
|
||||||
scalerate = in_scalerate;
|
scalerate = in_scalerate;
|
||||||
invisible = 0;
|
invisible = 0;
|
||||||
invisible_undead = false;
|
invisible_undead = 0;
|
||||||
invisible_animals = false;
|
invisible_animals = 0;
|
||||||
sneaking = false;
|
sneaking = false;
|
||||||
hidden = false;
|
hidden = false;
|
||||||
improved_hidden = false;
|
improved_hidden = false;
|
||||||
@ -440,10 +440,13 @@ Mob::Mob(
|
|||||||
pStandingPetOrder = SPO_Follow;
|
pStandingPetOrder = SPO_Follow;
|
||||||
pseudo_rooted = false;
|
pseudo_rooted = false;
|
||||||
|
|
||||||
see_invis = GetSeeInvisible(in_see_invis);
|
nobuff_invisible = 0;
|
||||||
see_invis_undead = GetSeeInvisible(in_see_invis_undead);
|
see_invis = 0;
|
||||||
see_hide = GetSeeInvisible(in_see_hide);
|
|
||||||
see_improved_hide = GetSeeInvisible(in_see_improved_hide);
|
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;
|
qglobal = in_qglobal != 0;
|
||||||
|
|
||||||
@ -584,10 +587,52 @@ uint32 Mob::GetAppearanceValue(EmuAppearance iAppearance) {
|
|||||||
return(ANIM_STAND);
|
return(ANIM_STAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::SetInvisible(uint8 state)
|
|
||||||
|
void Mob::CalcSeeInvisibleLevel()
|
||||||
{
|
{
|
||||||
if (state != Invisibility::Special) {
|
see_invis = std::max({ spellbonuses.SeeInvis, itembonuses.SeeInvis, aabonuses.SeeInvis, innate_see_invis });
|
||||||
invisible = state;
|
}
|
||||||
|
|
||||||
|
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);
|
SendAppearancePacket(AT_Invis, invisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,36 +642,54 @@ void Mob::SetInvisible(uint8 state)
|
|||||||
if (RuleB(Pets, LivelikeBreakCharmOnInvis) || IsInvisible(pet)) {
|
if (RuleB(Pets, LivelikeBreakCharmOnInvis) || IsInvisible(pet)) {
|
||||||
pet->BuffFadeByEffect(SE_Charm);
|
pet->BuffFadeByEffect(SE_Charm);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogRules("Pets:LivelikeBreakCharmOnInvis for [{}] | Invis [{}] - Hidden [{}] - Shroud of Stealth [{}] - IVA [{}] - IVU [{}]", GetCleanName(), invisible, hidden, improved_hidden, invisible_animals, invisible_undead);
|
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`
|
//check to see if `this` is invisible to `other`
|
||||||
bool Mob::IsInvisible(Mob* other) const
|
bool Mob::IsInvisible(Mob* other) const
|
||||||
{
|
{
|
||||||
if(!other)
|
if (!other) {
|
||||||
return(false);
|
return(false);
|
||||||
|
}
|
||||||
uint8 SeeInvisBonus = 0;
|
|
||||||
if (IsClient())
|
|
||||||
SeeInvisBonus = aabonuses.SeeInvis;
|
|
||||||
|
|
||||||
//check regular invisibility
|
//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())
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check invis vs. animals...
|
//check invis vs. undead
|
||||||
if (other->GetBodyType() == BT_Animal){
|
if (other->GetBodyType() == BT_Undead || other->GetBodyType() == BT_SummonedUndead) {
|
||||||
if(invisible_animals && !other->SeeInvisible())
|
if (invisible_undead && (invisible_undead > other->SeeInvisibleUndead())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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 && (invisible_animals > other->SeeInvisible())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(hidden){
|
if(hidden){
|
||||||
if(!other->see_hide && !other->see_improved_hide){
|
if(!other->see_hide && !other->see_improved_hide){
|
||||||
@ -642,9 +705,10 @@ bool Mob::IsInvisible(Mob* other) const
|
|||||||
|
|
||||||
//handle sneaking
|
//handle sneaking
|
||||||
if(sneaking) {
|
if(sneaking) {
|
||||||
if(BehindMob(other, GetX(), GetY()) )
|
if (BehindMob(other, GetX(), GetY())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return(false);
|
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);
|
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)
|
/*
|
||||||
{
|
Returns the NPC's see invisible level based on 'see_invs' value in npc_types.
|
||||||
if(see_invis == 1)
|
1 = See Invs Level 1, 2-99 will gives a random roll to apply see invs level 1
|
||||||
return true;
|
100 = See Invs Level 2, where 101-199 gives a random roll to apply see invs 2, if fails get see invs 1
|
||||||
else
|
ect... for higher levels, 200,300 ect.
|
||||||
{
|
MAX 25499, which can give you level 254.
|
||||||
if (zone->random.Int(0, 99) < see_invis)
|
*/
|
||||||
return true;
|
|
||||||
|
//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)
|
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,
|
uint32 in_drakkin_details,
|
||||||
EQ::TintProfile in_armor_tint,
|
EQ::TintProfile in_armor_tint,
|
||||||
uint8 in_aa_title,
|
uint8 in_aa_title,
|
||||||
uint8 in_see_invis, // see through invis
|
uint16 in_see_invis, // see through invis
|
||||||
uint8 in_see_invis_undead, // see through invis vs. undead
|
uint16 in_see_invis_undead, // see through invis vs. undead
|
||||||
uint8 in_see_hide,
|
uint8 in_see_hide,
|
||||||
uint8 in_see_improved_hide,
|
uint8 in_see_improved_hide,
|
||||||
int32 in_hp_regen,
|
int32 in_hp_regen,
|
||||||
@ -226,10 +226,6 @@ public:
|
|||||||
virtual inline bool IsBerserk() { return false; } // only clients
|
virtual inline bool IsBerserk() { return false; } // only clients
|
||||||
void RogueEvade(Mob *other);
|
void RogueEvade(Mob *other);
|
||||||
void CommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
void CommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
||||||
void BreakInvisibleSpells();
|
|
||||||
virtual void CancelSneakHide();
|
|
||||||
void CommonBreakInvisible();
|
|
||||||
void CommonBreakInvisibleFromCombat();
|
|
||||||
bool HasDied();
|
bool HasDied();
|
||||||
virtual bool CheckDualWield();
|
virtual bool CheckDualWield();
|
||||||
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
||||||
@ -246,6 +242,39 @@ public:
|
|||||||
return;
|
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
|
* Appearance
|
||||||
@ -254,16 +283,8 @@ public:
|
|||||||
|
|
||||||
EQ::InternalTextureProfile mob_texture_profile = {};
|
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);
|
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 GetTextureProfileMaterial(uint8 material_slot) const;
|
||||||
int32 GetTextureProfileColor(uint8 material_slot) const;
|
int32 GetTextureProfileColor(uint8 material_slot) const;
|
||||||
int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const;
|
int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const;
|
||||||
@ -282,7 +303,6 @@ public:
|
|||||||
void SendLevelAppearance();
|
void SendLevelAppearance();
|
||||||
void SendStunAppearance();
|
void SendStunAppearance();
|
||||||
void SendTargetable(bool on, Client *specific_target = nullptr);
|
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);
|
void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0);
|
||||||
|
|
||||||
//Spell
|
//Spell
|
||||||
@ -974,10 +994,7 @@ public:
|
|||||||
inline const bodyType GetOrigBodyType() const { return orig_bodytype; }
|
inline const bodyType GetOrigBodyType() const { return orig_bodytype; }
|
||||||
void SetBodyType(bodyType new_body, bool overwrite_orig);
|
void SetBodyType(bodyType new_body, bool overwrite_orig);
|
||||||
|
|
||||||
uint32 tmHidden; // timestamp of hide, only valid while hidden == true
|
bool invulnerable;
|
||||||
uint8 invisible, see_invis;
|
|
||||||
bool invulnerable, invisible_undead, invisible_animals, sneaking, hidden, improved_hidden;
|
|
||||||
bool see_invis_undead, see_hide, see_improved_hide;
|
|
||||||
bool qglobal;
|
bool qglobal;
|
||||||
|
|
||||||
virtual void SetAttackTimer();
|
virtual void SetAttackTimer();
|
||||||
|
|||||||
@ -916,6 +916,35 @@ XS(XS_Mob_SetInvisible) {
|
|||||||
XSRETURN_EMPTY;
|
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); /* prototype to pass -Wmissing-prototypes */
|
||||||
XS(XS_Mob_FindBuff) {
|
XS(XS_Mob_FindBuff) {
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
@ -5777,6 +5806,41 @@ XS(XS_Mob_IsBlind) {
|
|||||||
XSRETURN(1);
|
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);
|
||||||
XS(XS_Mob_SeeInvisible) {
|
XS(XS_Mob_SeeInvisible) {
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
@ -5801,11 +5865,12 @@ XS(XS_Mob_SeeInvisibleUndead) {
|
|||||||
Perl_croak(aTHX_ "Usage: Mob::SeeInvisibleUndead(THIS)"); // @categories Stats and Attributes
|
Perl_croak(aTHX_ "Usage: Mob::SeeInvisibleUndead(THIS)"); // @categories Stats and Attributes
|
||||||
{
|
{
|
||||||
Mob *THIS;
|
Mob *THIS;
|
||||||
bool RETVAL;
|
uint8 RETVAL;
|
||||||
|
dXSTARG;
|
||||||
VALIDATE_THIS_IS_MOB;
|
VALIDATE_THIS_IS_MOB;
|
||||||
RETVAL = THIS->SeeInvisibleUndead();
|
RETVAL = THIS->SeeInvisibleUndead();
|
||||||
ST(0) = boolSV(RETVAL);
|
XSprePUSH;
|
||||||
sv_2mortal(ST(0));
|
PUSHu((UV)RETVAL);
|
||||||
}
|
}
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
}
|
}
|
||||||
@ -6698,6 +6763,8 @@ XS(boot_Mob) {
|
|||||||
newXSproto(strcpy(buf, "GetHerosForgeModel"), XS_Mob_GetHerosForgeModel, file, "$$");
|
newXSproto(strcpy(buf, "GetHerosForgeModel"), XS_Mob_GetHerosForgeModel, file, "$$");
|
||||||
newXSproto(strcpy(buf, "GetID"), XS_Mob_GetID, file, "$");
|
newXSproto(strcpy(buf, "GetID"), XS_Mob_GetID, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetINT"), XS_Mob_GetINT, 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, "GetInvul"), XS_Mob_GetInvul, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetItemHPBonuses"), XS_Mob_GetItemHPBonuses, file, "$");
|
newXSproto(strcpy(buf, "GetItemHPBonuses"), XS_Mob_GetItemHPBonuses, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetItemStat"), XS_Mob_GetItemStat, 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, "SetRace"), XS_Mob_SetRace, file, "$$");
|
||||||
newXSproto(strcpy(buf, "SetRunAnimSpeed"), XS_Mob_SetRunAnimSpeed, file, "$$");
|
newXSproto(strcpy(buf, "SetRunAnimSpeed"), XS_Mob_SetRunAnimSpeed, file, "$$");
|
||||||
newXSproto(strcpy(buf, "SetRunning"), XS_Mob_SetRunning, 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, "SetSlotTint"), XS_Mob_SetSlotTint, file, "$$$$$");
|
||||||
newXSproto(strcpy(buf, "SetSpecialAbility"), XS_Mob_SetSpecialAbility, file, "$$$");
|
newXSproto(strcpy(buf, "SetSpecialAbility"), XS_Mob_SetSpecialAbility, file, "$$$");
|
||||||
newXSproto(strcpy(buf, "SetSpecialAbilityParam"), XS_Mob_SetSpecialAbilityParam, 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;
|
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:
|
case SE_FleshToBone:
|
||||||
{
|
{
|
||||||
#ifdef SPELL_EFFECT_SPAM
|
#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_Proc_Timer_Modifier:
|
||||||
case SE_FFItemClass:
|
case SE_FFItemClass:
|
||||||
case SE_SpellEffectResistChance:
|
case SE_SpellEffectResistChance:
|
||||||
|
case SE_SeeInvis:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3946,11 +3908,14 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case SE_ImprovedInvisAnimals:
|
||||||
case SE_Invisibility2:
|
case SE_Invisibility2:
|
||||||
case SE_InvisVsUndead2: {
|
case SE_InvisVsUndead2: {
|
||||||
|
if (!IsBardSong(buff.spellid)) {
|
||||||
if (buff.ticsremaining <= 3 && buff.ticsremaining > 1) {
|
if (buff.ticsremaining <= 3 && buff.ticsremaining > 1) {
|
||||||
MessageString(Chat::Spells, INVIS_BEGIN_BREAK);
|
MessageString(Chat::Spells, INVIS_BEGIN_BREAK);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_InterruptCasting: {
|
case SE_InterruptCasting: {
|
||||||
@ -4186,32 +4151,6 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
break;
|
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:
|
case SE_Silence:
|
||||||
{
|
{
|
||||||
Silence(false);
|
Silence(false);
|
||||||
@ -9580,18 +9519,19 @@ void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster)
|
|||||||
void Mob::BreakInvisibleSpells()
|
void Mob::BreakInvisibleSpells()
|
||||||
{
|
{
|
||||||
if(invisible) {
|
if(invisible) {
|
||||||
|
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||||
BuffFadeByEffect(SE_Invisibility);
|
BuffFadeByEffect(SE_Invisibility);
|
||||||
BuffFadeByEffect(SE_Invisibility2);
|
BuffFadeByEffect(SE_Invisibility2);
|
||||||
invisible = false;
|
|
||||||
}
|
}
|
||||||
if(invisible_undead) {
|
if(invisible_undead) {
|
||||||
|
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_UNDEAD);
|
||||||
BuffFadeByEffect(SE_InvisVsUndead);
|
BuffFadeByEffect(SE_InvisVsUndead);
|
||||||
BuffFadeByEffect(SE_InvisVsUndead2);
|
BuffFadeByEffect(SE_InvisVsUndead2);
|
||||||
invisible_undead = false;
|
|
||||||
}
|
}
|
||||||
if(invisible_animals){
|
if(invisible_animals){
|
||||||
|
ZeroInvisibleVars(InvisType::T_INVISIBLE_VERSE_ANIMAL);
|
||||||
|
BuffFadeByEffect(SE_ImprovedInvisAnimals);
|
||||||
BuffFadeByEffect(SE_InvisVsAnimals);
|
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.
|
bool IsCastersTarget = false; // Chance to avoid only applies to AOE spells when not targeted.
|
||||||
if (hidden || improved_hidden) {
|
if (hidden || improved_hidden) {
|
||||||
if (caster) {
|
if (caster) {
|
||||||
Mob *target = nullptr;
|
Mob *spell_target = caster->GetTarget();
|
||||||
target = caster->GetTarget();
|
if (spell_target && spell_target == this) {
|
||||||
IsCastersTarget = target && target == this;
|
IsCastersTarget = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsCastersTarget) {
|
if (!IsCastersTarget) {
|
||||||
int chance =
|
int chance = spellbonuses.NoBreakAESneak + itembonuses.NoBreakAESneak + aabonuses.NoBreakAESneak;
|
||||||
spellbonuses.NoBreakAESneak + itembonuses.NoBreakAESneak + aabonuses.NoBreakAESneak;
|
if (IsResisted) {
|
||||||
|
|
||||||
if (IsResisted)
|
|
||||||
chance *= 2;
|
chance *= 2;
|
||||||
|
}
|
||||||
if (chance && zone->random.Roll(chance))
|
if (chance && zone->random.Roll(chance)) {
|
||||||
return; // Do not drop Sneak/Hide
|
return; // Do not drop Sneak/Hide
|
||||||
}
|
}
|
||||||
|
}
|
||||||
CancelSneakHide();
|
CancelSneakHide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3622,7 +3622,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes
|
|||||||
|
|
||||||
// Prevent double invising, which made you uninvised
|
// Prevent double invising, which made you uninvised
|
||||||
// Not sure if all 3 should be stacking
|
// Not sure if all 3 should be stacking
|
||||||
|
//This is not live like behavior (~Kayen confirmed 2/2/22)
|
||||||
if (!RuleB(Spells, AllowDoubleInvis)) {
|
if (!RuleB(Spells, AllowDoubleInvis)) {
|
||||||
if (IsEffectInSpell(spell_id, SE_Invisibility))
|
if (IsEffectInSpell(spell_id, SE_Invisibility))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -108,8 +108,8 @@ struct NPCType
|
|||||||
int32 mana_regen;
|
int32 mana_regen;
|
||||||
int32 aggroradius; // added for AI improvement - neotokyo
|
int32 aggroradius; // added for AI improvement - neotokyo
|
||||||
int32 assistradius; // assist radius, defaults to aggroradis if not set
|
int32 assistradius; // assist radius, defaults to aggroradis if not set
|
||||||
uint8 see_invis; // See Invis flag added
|
uint16 see_invis; // See Invis flag added
|
||||||
bool see_invis_undead; // See Invis vs. Undead flag added
|
uint16 see_invis_undead; // See Invis vs. Undead flag added
|
||||||
bool see_hide;
|
bool see_hide;
|
||||||
bool see_improved_hide;
|
bool see_improved_hide;
|
||||||
bool qglobal;
|
bool qglobal;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user