Merge pull request #463 from KayenEQ/Development

Invisible/Hide mechanics when cast on
This commit is contained in:
KayenEQ 2015-10-10 15:42:19 -04:00
commit b923c69f39
11 changed files with 102 additions and 8 deletions

View File

@ -1,5 +1,12 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 10/10/2015 ==
Kayen: Updated mechanics to be consistent with live regarding how invisible breaks when the client is the target of a spell.
Invisible will drop whenever a client is hit with a detrimental spell, regardless of if resisted, if it does damage or AOE.
Hide skill now also follows the same rules as above.
Implemented support for Rogue AA - Nerves of Steel which gives a chance for hide NOT to break
when client is hit with an AOE spell.
== 09/25/2015 ==
Uleat: Implemented 'Inventory Snapshot' feature to track online player inventories at timed intervals.
rules:

View File

@ -478,7 +478,7 @@ typedef enum {
#define SE_GateToHomeCity 322 // implemented
#define SE_DefensiveProc 323 // implemented
#define SE_HPToMana 324 // implemented
//#define SE_NoBreakAESneak 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell.
#define SE_NoBreakAESneak 325 // implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell.
#define SE_SpellSlotIncrease 326 // *not implemented as bonus - increases your spell slot availability
#define SE_MysticalAttune 327 // implemented - increases amount of buffs that a player can have
#define SE_DelayDeath 328 // implemented - increases how far you can fall below 0 hp before you die

View File

@ -1382,7 +1382,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
if (damage > 0 && HasSkillProcSuccess() && other && other->GetHP() > 0)
TrySkillProc(other, skillinuse, 0, true, Hand);
CommonBreakInvisible();
CommonBreakInvisibleFromCombat();
if(GetTarget())
TriggerDefensiveProcs(weapon, other, Hand, damage);
@ -1940,7 +1940,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
MeleeLifeTap(damage);
CommonBreakInvisible();
CommonBreakInvisibleFromCombat();
//I doubt this works...
if (!GetTarget())
@ -4487,7 +4487,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, int32 &damage, SkillUseTypes s
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
}
void Mob::CommonBreakInvisible()
void Mob::CommonBreakInvisibleFromCombat()
{
//break invis when you attack
if(invisible) {

View File

@ -1452,6 +1452,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
newbon->TradeSkillMastery = base1;
break;
case SE_NoBreakAESneak:
if (newbon->NoBreakAESneak < base1)
newbon->NoBreakAESneak = base1;
break;
// to do
case SE_PetDiscipline:
break;
@ -3189,6 +3194,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break;
}
case SE_NoBreakAESneak:
if (new_bonus->NoBreakAESneak < effect_value)
new_bonus->NoBreakAESneak = effect_value;
break;
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) {

View File

@ -878,6 +878,7 @@ public:
void SetFilter(eqFilterType filter_id, eqFilterMode value) { ClientFilters[filter_id]=value; }
void BreakInvis();
void BreakSneakWhenCastOn(Mob* caster, bool IsResisted);
void LeaveGroup();
bool Hungry() const {if (GetGM()) return false; return m_pp.hunger_level <= 3000;}

View File

@ -471,6 +471,7 @@ struct StatBonuses {
uint16 ReduceFallDamage; // reduce fall damage by percent
int32 ReduceTradeskillFail[HIGHEST_SKILL+1]; // Reduces chance for trade skills to fail by percent.
uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill.
int16 NoBreakAESneak; // Percent value
};
typedef struct

View File

@ -164,7 +164,8 @@ public:
virtual inline bool IsBerserk() { return false; } // only clients
void RogueEvade(Mob *other);
void CommonOutgoingHitSuccess(Mob* defender, int32 &damage, SkillUseTypes skillInUse);
void CommonBreakInvisible();
void BreakInvisibleSpells();
void CommonBreakInvisibleFromCombat();
bool HasDied();
virtual bool CheckDualWield();
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, int special = 0);

View File

@ -805,7 +805,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
}
CheckIncreaseSkill(SkillArchery, GetTarget(), -15);
CommonBreakInvisible();
CommonBreakInvisibleFromCombat();
}
void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime,
@ -1237,7 +1237,7 @@ void NPC::RangedAttack(Mob* other)
DoRangedAttackDmg(other);
CommonBreakInvisible();
CommonBreakInvisibleFromCombat();
}
}
@ -1433,7 +1433,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
//consume ammo
DeleteItemInInventory(ammo_slot, 1, true);
CheckIncreaseSkill(SkillThrowing, GetTarget());
CommonBreakInvisible();
CommonBreakInvisibleFromCombat();
}
void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* AmmoItem, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime, uint32 range_id, int AmmoSlot, float speed)

View File

@ -6707,3 +6707,67 @@ void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster)
SetSpellPowerDistanceMod(static_cast<int>(mod));
}
}
void Mob::BreakInvisibleSpells()
{
if(invisible) {
BuffFadeByEffect(SE_Invisibility);
BuffFadeByEffect(SE_Invisibility2);
invisible = false;
}
if(invisible_undead) {
BuffFadeByEffect(SE_InvisVsUndead);
BuffFadeByEffect(SE_InvisVsUndead2);
invisible_undead = false;
}
if(invisible_animals){
BuffFadeByEffect(SE_InvisVsAnimals);
invisible_animals = false;
}
}
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();
if (target && target == this){
IsCastersTarget = true;
}
}
if (!IsCastersTarget){
int chance = spellbonuses.NoBreakAESneak + itembonuses.NoBreakAESneak + aabonuses.NoBreakAESneak;
if (IsResisted)
chance *= 2;
if(chance && (zone->random.Roll(chance)))
return; // Do not drop Sneak/Hide
}
//TODO: The skill buttons should reset when this occurs. Not sure how to force that yet. - Kayen
hidden = false;
improved_hidden = false;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer;
sa_out->spawn_id = GetID();
sa_out->type = 0x03;
sa_out->parameter = 0;
entity_list.QueueClients(this, outapp, false);
safe_delete(outapp);
Message_StringID(MT_Skills,NO_LONGER_HIDDEN);
//Sneaking alone will not be disabled from spells, only hide+sneak.
if (sneaking){
sneaking = false;
SendAppearancePacket(AT_Sneak, 0);
Message_StringID(MT_Skills,STOP_SNEAKING);
}
}
}

View File

@ -3679,6 +3679,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
// not all unresistable, so changing this to only check certain spells
if(IsResistableSpell(spell_id))
{
spelltar->BreakInvisibleSpells(); //Any detrimental spell cast on you will drop invisible (can be AOE, non damage ect).
if (IsCharmSpell(spell_id) || IsMezSpell(spell_id) || IsFearSpell(spell_id))
spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust, true, false, false, level_override);
else
@ -3712,6 +3714,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
}
}
if (spelltar->IsClient())
spelltar->CastToClient()->BreakSneakWhenCastOn(this, true);
spelltar->CheckNumHitsRemaining(NumHit::IncomingSpells);
CheckNumHitsRemaining(NumHit::OutgoingSpells);
@ -3719,6 +3724,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
return false;
}
}
if (spelltar->IsClient()){
spelltar->CastToClient()->BreakSneakWhenCastOn(this, false);
}
}
else
{

View File

@ -384,6 +384,8 @@
#define TARGET_PLAYER_FOR_GUILD_STATUS 12260
#define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite <name> to invite someone to your group.
#define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself.
#define NO_LONGER_HIDDEN 12337 //You are no longer hidden.
#define STOP_SNEAKING 12338 //You stop sneaking
#define NOT_IN_CONTROL 12368 //You do not have control of yourself right now.
#define ALREADY_CASTING 12442 //You are already casting a spell!
#define SHIMMERS_BRIEFLY 12444 //Your %1 shimmers briefly.