Index: game/Spell.cpp =================================================================== --- game/Spell.cpp (revision 6055) +++ game/Spell.cpp (working copy) @@ -328,7 +328,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_powerCost = 0; // setup to correct value in Spell::prepare, don't must be used before. @@ -339,7 +339,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++) @@ -1835,10 +1835,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 @@ -1971,6 +1967,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) { @@ -2275,7 +2285,7 @@ m_timer -= difftime; } - if(m_timer == 0 && !m_meleeSpell) + if(m_timer == 0 && !m_meleeSpell && !m_autoRepeat) cast(); } break; case SPELL_STATE_CASTING: @@ -2395,13 +2405,6 @@ } } - if (IsMeleeAttackResetSpell()) - { - m_caster->resetAttackTimer(BASE_ATTACK); - if(m_caster->haveOffhandWeapon()) - m_caster->resetAttackTimer(OFF_ATTACK); - } - // Clear combo at finish state if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo)) ((Player*)m_caster)->ClearComboPoints(); Index: game/Unit.cpp =================================================================== --- game/Unit.cpp (revision 6055) +++ game/Unit.cpp (working copy) @@ -3059,96 +3059,65 @@ void Unit::_UpdateAutoRepeatSpell() { - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED) + if ( m_AutoRepeatFirstCast ) { - //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 ( getAttackTimer(RANGED_ATTACK) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime() ) + setAttackTimer(RANGED_ATTACK,m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetCastTime()); + + m_AutoRepeatFirstCast = false; + return; + } - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE); - } - else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) ) + if (isAttackReady(RANGED_ATTACK)) { - // check if we can cast - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) == 0) - { - // check movement in player case + if(!IsNonMeleeSpellCasted(false,false,true)) 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)) - { - // wee need clear target list before recasting - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CleanupTargetList(); - 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 ) Index: game/Spell.cpp =================================================================== --- game/Spell.cpp (revision 6055) +++ game/Spell.cpp (working copy) @@ -328,7 +328,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_powerCost = 0; // setup to correct value in Spell::prepare, don't must be used before. @@ -339,7 +339,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++) @@ -1835,10 +1835,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 @@ -1971,6 +1967,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) { @@ -2275,7 +2285,7 @@ m_timer -= difftime; } - if(m_timer == 0 && !m_meleeSpell) + if(m_timer == 0 && !m_meleeSpell && !m_autoRepeat) cast(); } break; case SPELL_STATE_CASTING: @@ -2395,13 +2405,6 @@ } } - if (IsMeleeAttackResetSpell()) - { - m_caster->resetAttackTimer(BASE_ATTACK); - if(m_caster->haveOffhandWeapon()) - m_caster->resetAttackTimer(OFF_ATTACK); - } - // Clear combo at finish state if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo)) ((Player*)m_caster)->ClearComboPoints(); Index: game/Unit.cpp =================================================================== --- game/Unit.cpp (revision 6055) +++ game/Unit.cpp (working copy) @@ -3059,96 +3059,66 @@ void Unit::_UpdateAutoRepeatSpell() { - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED) + if ( m_AutoRepeatFirstCast ) { - //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 ( getAttackTimer(RANGED_ATTACK) < 500 ) + setAttackTimer(RANGED_ATTACK,500); + + m_AutoRepeatFirstCast = false; + return; + } - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE); - } - else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) ) + 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,500); + 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)) - { - // wee need clear target list before recasting - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CleanupTargetList(); - 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,500); + } + } + // 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) < 500 ) + setAttackTimer(RANGED_ATTACK,500); + } + } + } void Unit::SetCurrentCastedSpell( Spell * pSpell )