Index: game/GameObject.cpp =================================================================== --- game/GameObject.cpp (revision 5648) +++ game/GameObject.cpp (working copy) @@ -195,6 +195,13 @@ return; } + if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP) + { + Unit* owner = GetOwner(); + if (!owner || owner->isInCombat()) + m_cooldownTime = time(NULL) + GetGOInfo()->trap._data6[1]; + } + m_lootState = GO_READY; // for other GOis same switched without delay to GO_READY // NO BREAK case GO_READY: Index: game/Spell.cpp =================================================================== --- game/Spell.cpp (revision 5648) +++ game/Spell.cpp (working copy) @@ -323,7 +323,7 @@ m_triggeredByAuraSpell = NULL; m_autoRepeat = false; - if( m_spellInfo->AttributesEx2 == 0x000020 ) //Auto Shot & Shoot + if( m_spellInfo->AttributesEx2 == 0x000020 && !triggered) //Auto Shot & Shoot m_autoRepeat = true; m_casttime = 0; // setup to correct value in Spell::prepare, don't must be used before. @@ -333,7 +333,7 @@ m_meleeSpell = false; - m_rangedShoot = ((m_spellInfo->Attributes & 18) == 18); + m_rangedShoot = (m_spellInfo->Attributes & 2); if( m_spellInfo->StartRecoveryTime == 0 && !m_autoRepeat && !m_rangedShoot ) { for (int i = 0; i < 3; i++) @@ -1734,6 +1734,14 @@ // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail) m_casttime = GetSpellCastTime(sCastTimesStore.LookupEntry(m_spellInfo->CastingTimeIndex)); + if (m_rangedShoot && !m_IsTriggeredSpell) + { + m_casttime = int32(m_casttime*m_caster->m_modAttackSpeedPct[RANGED_ATTACK]); + + if (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) + m_casttime += 500; + } + if(Player* modOwner = m_caster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_CASTING_TIME, m_casttime,this); @@ -1750,10 +1758,6 @@ m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); } - // do first cast of autorepeat spell with recovery time delay (like after any autocast) - if(IsAutoRepeat()) - m_spellState = SPELL_STATE_FINISHED; - if(m_IsTriggeredSpell) cast(true); else @@ -1887,6 +1891,20 @@ UpdatePointers(); // pointers can be invalidate at triggered spell casting } + if (IsMeleeAttackResetSpell()) + { + if ( m_rangedShoot ) + { + m_caster->resetAttackTimer(RANGED_ATTACK); + } + else + { + m_caster->resetAttackTimer(BASE_ATTACK); + if(m_caster->haveOffhandWeapon()) + m_caster->resetAttackTimer(OFF_ATTACK); + } + } + // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells if (m_spellInfo->speed > 0.0f) { @@ -2183,7 +2201,9 @@ cancel(); // don't cancel for melee, autorepeat and instant spells else if(!m_meleeSpell && !m_autoRepeat && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) + { cancel(); + } } switch(m_spellState) @@ -2198,7 +2218,7 @@ m_timer -= difftime; } - if(m_timer == 0 && !m_meleeSpell) + if(m_timer == 0 && !m_meleeSpell && !m_autoRepeat) cast(); } break; case SPELL_STATE_CASTING: @@ -2324,12 +2344,20 @@ } } - if (IsMeleeAttackResetSpell()) - { - m_caster->resetAttackTimer(BASE_ATTACK); - if(m_caster->haveOffhandWeapon()) - m_caster->resetAttackTimer(OFF_ATTACK); - } + // Bestial Wrath: Try to find Beast Within + if (m_spellInfo->Id == 19574) + { + Unit::AuraList const& BWDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator i = BWDummy.begin(); i != BWDummy.end(); ++i) + { + // Beast Within + if ((*i)->GetSpellProto()->Id == 34692) + { + m_caster->CastSpell(m_caster,34471,true,NULL,(*i)); + break; + } + } + } // Clear combo at finish state if(m_caster->GetTypeId() == TYPEID_PLAYER) @@ -3724,11 +3752,11 @@ case SPELL_AURA_MOD_FEAR: return SPELL_FAILED_FLEEING; case SPELL_AURA_MOD_SILENCE: - if((GetSpellSchoolMask(m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL)==0) + if(m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MAGIC) return SPELL_FAILED_SILENCED; break; case SPELL_AURA_MOD_PACIFY: - if(GetSpellSchoolMask(m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL) + if(m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE||m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_RANGED) return SPELL_FAILED_PACIFIED; break; } Index: game/SpellAuras.cpp =================================================================== --- game/SpellAuras.cpp (revision 5648) +++ game/SpellAuras.cpp (working copy) @@ -2995,9 +2995,33 @@ { uint32 mechanic = 1 << m_modifier.m_miscvalue; - //immune movement impairement and loss of control - if(GetId()==42292) - mechanic=0x9967da6; + // Manualy set + switch(GetId()) + { + //immune movement impairement and loss of control + case 42292: + mechanic=0x9967da6; + break; + case 34471: + case 19574: + mechanic=0x41066CA6; + // need to also add immunities due to this spell + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_CHARM,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_FEAR,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_POLYMORPH,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_CONFUSED,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_BANISH,apply); + //m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,30,apply); // 2.4 SAP + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_ROOT,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_SLEEP,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_SNARE,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_KNOCKOUT,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_FREEZE,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_HORROR,apply); + break; + default: + break; + } if(apply) { Index: game/Unit.cpp =================================================================== --- game/Unit.cpp (revision 5648) +++ game/Unit.cpp (working copy) @@ -1339,6 +1339,9 @@ if( spellProto->Effect[effect_idx]==SPELL_EFFECT_PERSISTENT_AREA_AURA && SpellHitResult(pVictim,spellProto,false)!=SPELL_MISS_NONE) return; + + if (pVictim->IsImmunedToSpellDamage(spellProto,false)) + return; uint32 absorb=0; uint32 resist=0; @@ -1398,6 +1401,9 @@ SpellHitResult(pVictim,spellProto,false)!=SPELL_MISS_NONE) return; + if (pVictim->IsImmunedToSpellDamage(spellProto,false)) + return; + uint32 absorb=0; uint32 resist=0; CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); @@ -1570,6 +1576,9 @@ SpellHitResult(pVictim,spellProto,false)!=SPELL_MISS_NONE) return; + if (pVictim->IsImmunedToSpell(spellProto,false)) + return; + // ignore non positive values (can be result apply spellmods to aura damage uint32 pdamage = mod->m_amount > 0 ? mod->m_amount : 0; @@ -1674,6 +1683,10 @@ } case SPELL_AURA_POWER_BURN_MANA: { + + if (pVictim->IsImmunedToSpell(spellProto,false)) + return; + int32 pdamage = mod->m_amount > 0 ? mod->m_amount : 0; Powers powerType = Powers(mod->m_miscvalue); @@ -3389,94 +3402,65 @@ void Unit::_UpdateAutoRepeatSpell() { - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED) - { - //Auto Shot & Shoot - if( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->AttributesEx2 == 0x000020 && GetTypeId() == TYPEID_PLAYER ) - { - // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) - { - // Shoot - resetAttackTimer( RANGED_ATTACK ); - } - else - { - // Auto Shoot - if (m_AutoRepeatFirstCast) - { - // first cast only with recovery time (not less) - if (getAttackTimer( RANGED_ATTACK ) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime) - setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime); - m_AutoRepeatFirstCast = false; - } - else - { - // second or further casts - resetAttackTimer( RANGED_ATTACK ); - } - } - } - else - { - setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime); - } + if ( m_AutoRepeatFirstCast ) + { + if ( getAttackTimer(RANGED_ATTACK) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime() ) + setAttackTimer(RANGED_ATTACK,m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime()); - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE); - } - else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) ) + m_AutoRepeatFirstCast = false; + return; + } + + if (isAttackReady(RANGED_ATTACK)) { - // check if we can cast - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) == 0) + if(!IsNonMeleeSpellCasted(false,false,true)) { - // check movement in player case if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) { // cancel wand shooting if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) InterruptSpell(CURRENT_AUTOREPEAT_SPELL); // ELSE delay auto-repeat ranged weapon until player movement stop + // this will setup 0.5s cast time + setAttackTimer(RANGED_ATTACK,m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime()); + return; } - else - // recheck range and req. items (ammo and gun, etc) - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckRange(true) == 0 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckItems() == 0 ) - { - // check, if we are casting melee spell (it blocks autorepeat) - if ( ! (m_currentSpells[CURRENT_MELEE_SPELL] && - (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) && - (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)) ) - { - // check, if we are casting something else, if no then run autorepeat spell - if (!IsNonMeleeSpellCasted(false, false, true)) - { - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_PREPARING); - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->ReSetTimer(); - } - } - } - else - { + + // Check if able to cast + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckRange(true) != 0 || + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckItems() != 0 || + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) != 0) + { InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - } - } - else - { - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - } - } - else if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_PREPARING) - { - // check, if some other incomplete spell exists (including melee) or ranged attack is not ready - if ( m_currentSpells[CURRENT_MELEE_SPELL] || - m_currentSpells[CURRENT_GENERIC_SPELL] || - m_currentSpells[CURRENT_CHANNELED_SPELL] || - !isAttackReady(RANGED_ATTACK) ) - { - // some other spell is here or ranged attack is not ready, break us to idle state - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->finish(false); - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE); - } - } + return; + } + + // we want to shoot + Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true, 0); + spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets)); + // all went good, reset attack + resetAttackTimer(RANGED_ATTACK); + } + // Attack Ready, but something prevents us from castubg + else + { + // this will setup 0.5s cast time + setAttackTimer(RANGED_ATTACK,m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime()); + } + } + // Ranged Attack not ready yet + else + { + // moving, cancel wand shoot + if ( GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving() ) + { + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + + if ( getAttackTimer(RANGED_ATTACK) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime() ) + setAttackTimer(RANGED_ATTACK,m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime()); + } + } } void Unit::SetCurrentCastedSpell( Spell * pSpell ) @@ -6571,6 +6555,7 @@ InterruptSpell(CURRENT_MELEE_SPELL); + if( GetTypeId()==TYPEID_UNIT ) { // reset call assistance @@ -7549,7 +7534,7 @@ if(itr->type == spellInfo->Dispel) return true; - if( !(spellInfo->AttributesEx & 0x10000)) // unaffected by school immunity + if(!(spellInfo->AttributesEx & 0x10000) && spellInfo->Id != 42292) // unaffected by school immunity { // not have spells with charges currently SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];