diff --git a/zone/aa.cpp b/zone/aa.cpp index b1fadf5e8..f175ba9ba 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1181,6 +1181,11 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) { if (!IsCastWhileInvis(rank->spell)) CommonBreakInvisible(); + + if (spells[rank->spell].sneak && (!hidden || (hidden && (Timer::GetCurrentTime() - tmHidden) < 4000))) { + Message_StringID(13, SNEAK_RESTRICT); + return; + } // Bards can cast instant cast AAs while they are casting another song if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) { if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 0b6221c2a..e05cc4f8c 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -7911,6 +7911,7 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app) } else hidden = true; + tmHidden = Timer::GetCurrentTime(); } if (GetClass() == ROGUE){ auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct)); diff --git a/zone/effects.cpp b/zone/effects.cpp index e2d9d4075..53cead938 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -630,17 +630,6 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { if(r == MAX_PP_DISCIPLINES) return(false); //not found. - //Check the disc timer - pTimerType DiscTimer = pTimerDisciplineReuseStart + spells[spell_id].EndurTimerIndex; - if(!p_timers.Expired(&database, DiscTimer)) { - /*char val1[20]={0};*/ //unused - /*char val2[20]={0};*/ //unused - uint32 remain = p_timers.GetRemainingTime(DiscTimer); - //Message_StringID(0, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2)); - Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60)); - return(false); - } - //make sure we can use it.. if(!IsValidSpell(spell_id)) { Message(13, "This tome contains invalid knowledge."); @@ -667,6 +656,23 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { return(false); } + // sneak attack discs require you to be hidden for 4 seconds before use + if (spell.sneak && (!hidden || (hidden && (Timer::GetCurrentTime() - tmHidden) < 4000))) { + Message_StringID(13, SNEAK_RESTRICT); + return false; + } + + //Check the disc timer + pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.EndurTimerIndex; + if(!p_timers.Expired(&database, DiscTimer)) { + /*char val1[20]={0};*/ //unused + /*char val2[20]={0};*/ //unused + uint32 remain = p_timers.GetRemainingTime(DiscTimer); + //Message_StringID(0, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2)); + Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60)); + return(false); + } + if(spell.recast_time > 0) { uint32 reduced_recast = spell.recast_time / 1000; diff --git a/zone/mob.cpp b/zone/mob.cpp index fbc82e63f..a39dcfa99 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -108,7 +108,8 @@ Mob::Mob(const char* in_name, m_TargetLocation(glm::vec3()), m_TargetV(glm::vec3()), flee_timer(FLEE_CHECK_TIMER), - m_Position(position) + m_Position(position), + tmHidden(-1) { targeted = 0; tar_ndx=0; diff --git a/zone/mob.h b/zone/mob.h index 94a251394..9d874c33b 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -762,6 +762,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; diff --git a/zone/spells.cpp b/zone/spells.cpp index 95e4fed06..6b875c96f 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3392,11 +3392,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r if(spelltar->IsClient() && spelltar->CastToClient()->IsHoveringForRespawn()) return false; - if (spells[spell_id].sneak && IsClient() && !CastToClient()->sneaking){ - Message_StringID(13, SNEAK_RESTRICT); - return false;//Fail Safe, this can cause a zone crash certain situations if you try to apply sneak effects when not sneaking. - } - if(IsDetrimentalSpell(spell_id) && !IsAttackAllowed(spelltar) && !IsResurrectionEffects(spell_id)) { if(!IsClient() || !CastToClient()->GetGM()) { Message_StringID(MT_SpellFailure, SPELL_NO_HOLD);