rendered paste bodyIndex: src/game/DuelHandler.cpp===================================================================--- src/game/DuelHandler.cpp (revision 5734)+++ src/game/DuelHandler.cpp (working copy)@@ -73,8 +73,14 @@ if(GetPlayer()->duel->startTime != 0) { GetPlayer()->CombatStop();- if( GetPlayer()->duel->opponent )+ //force autoshot and melee cancel+ GetPlayer()->SendAttackSwingCancelAttack();+ + if( GetPlayer()->duel->opponent )+ { GetPlayer()->duel->opponent->CombatStop();+ GetPlayer()->duel->opponent->SendAttackSwingCancelAttack();+ } GetPlayer()->CastSpell(GetPlayer(), 7267, true); // beg GetPlayer()->DuelComplete(DUEL_WON); return;Index: src/game/Spell.cpp===================================================================--- src/game/Spell.cpp (revision 5734)+++ src/game/Spell.cpp (working copy)@@ -1746,6 +1746,14 @@ { m_targets = *targets; + //only intialize Auto-Repeat spell with target, further handling in Unit::_UpdateAutoRepeatspells+ if (m_autoRepeat && m_caster->m_AutoRepeatFirstCast)+ { + m_spellState = SPELL_STATE_IDLE;+ m_caster->SetCurrentCastedSpell( this );+ return;+ }+ m_spellState = SPELL_STATE_PREPARING; m_castPositionX = m_caster->GetPositionX();@@ -1800,17 +1808,13 @@ 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)+ if(m_IsTriggeredSpell || m_autoRepeat ) cast(true); else { m_caster->SetCurrentCastedSpell( this ); m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]);- SendSpellStart();+ SendSpellStart(); } } @@ -1828,6 +1832,9 @@ SendInterrupted(0); SendCastResult(SPELL_FAILED_INTERRUPTED); } break;+ + case SPELL_STATE_IDLE: //Auto-Repeat spells+ SendInterrupted(0); break; case SPELL_STATE_CASTING: {@@ -2139,9 +2146,9 @@ catrec = m_spellInfo->CategoryRecoveryTime; } - // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)+ // shoot spells (except autorepeat) use equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK) // prevent 0 cooldowns set by another way- if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351))+ if (rec <= 0 && catrec <= 0 && (cat == 76)) rec = _player->GetAttackTime(RANGED_ATTACK); // Now we have cooldown data (if found any), time to apply mods@@ -2204,23 +2211,10 @@ // update pointers based at it's GUIDs UpdatePointers(); - if(m_targets.getUnitTargetGUID())+ if(m_targets.getUnitTargetGUID() && !m_targets.getUnitTarget()) {- if(!m_targets.getUnitTarget() || !m_targets.getUnitTarget()->isAlive())- {- if(m_autoRepeat)- {- m_autoRepeat = false;- m_spellState = SPELL_STATE_FINISHED;- return;- }-- if(!m_targets.getUnitTarget())- {- cancel();- return;- }- }+ cancel();+ return; } // check if the player caster has moved before the spell finished@@ -2231,8 +2225,8 @@ // always cancel for channeled spells if( m_spellState == SPELL_STATE_CASTING ) cancel();- // don't cancel for melee, autorepeat and instant spells- else if(!m_meleeSpell && !m_autoRepeat && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))+ // don't cancel for melee and instant spells+ else if(!m_meleeSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) ) cancel(); } @@ -2289,8 +2283,8 @@ // channeled spell processed independently for quest targeting // cast at creature (or GO) quest objectives update at succesful cast channel finished- // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )- if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsMeleeSpell() )+ // ignore melee casts for speed (not exist quest for spells (hm... )+ if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsMeleeSpell() ) { for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) {Index: src/game/SpellEffects.cpp===================================================================--- src/game/SpellEffects.cpp (revision 5734)+++ src/game/SpellEffects.cpp (working copy)@@ -1209,12 +1209,17 @@ } case 37506: // Scatter Shot {- if (m_caster->GetTypeId()!=TYPEID_PLAYER)- return;-- // break Auto Shot- m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);- return;+ // break Auto Shot and "Attack"+ m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);+ m_caster->AttackStop();+ if (m_caster->GetTypeId()==TYPEID_PLAYER)+ ((Player*)m_caster)->SendAttackSwingCancelAttack(); //force autoshot cancel+ + //stop pet+ if (m_caster->GetPet() && m_caster->GetPet()->getVictim() == unitTarget )+ m_caster->GetPet()->AttackStop();+ + return; } } break;Index: src/game/SpellHandler.cpp===================================================================--- src/game/SpellHandler.cpp (revision 5734)+++ src/game/SpellHandler.cpp (working copy)@@ -722,6 +722,8 @@ Spell *spell = new Spell(_player, spellInfo, false); spell->m_cast_count = cast_count; //set count of casts+ if (spell->IsAutoRepeat()) + _player->m_AutoRepeatFirstCast = true; //set autorepeat first cast spell->prepare(&targets); } @@ -811,7 +813,6 @@ void WorldSession::HandleCancelAutoRepeatSpellOpcode( WorldPacket& /*recvPacket*/) {- // may be better send SMSG_CANCEL_AUTO_REPEAT? // cancel and prepare for deleting _player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); }Index: src/game/Unit.cpp===================================================================--- src/game/Unit.cpp (revision 5734)+++ src/game/Unit.cpp (working copy)@@ -869,10 +869,13 @@ assert(he->duel); he->SetHealth(1);- CombatStop(); // for case killed by pet+ CombatStop(); // for case killed by pet+ if (GetTypeId()==TYPEID_PLAYER)+ ((Player*)this)->SendAttackSwingCancelAttack(); // force autoshot cancel if(he->duel->opponent!=this) he->duel->opponent->CombatStop(); he->CombatStop();+ he->SendAttackSwingCancelAttack(); he->CastSpell(he, 7267, true); // beg he->DuelComplete(DUEL_WON);@@ -3403,96 +3406,98 @@ 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);- }+ //check target+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->UpdatePointers();+ if ( !(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTargetGUID() &&+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget()) )+ {+ InterruptSpell(CURRENT_AUTOREPEAT_SPELL);+ if(GetTypeId()==TYPEID_PLAYER)+ ((Player*)this)->SendAttackSwingCancelAttack(); //force autoshot cancel+ return;+ }+ - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);- }- else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) )- {- // check if we can cast- if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) == 0)- {- // 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- }- 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- {- 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);- }- }+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE )+ { + //on First cast we need a prepare animation + if(m_AutoRepeatFirstCast) m_AutoRepeatSendSpellStart =true;+ + uint8 result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true);+ // CanCast check+ if (result)+ { + // cancel wand shooting and send result+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)+ { + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);+ InterruptSpell(CURRENT_AUTOREPEAT_SPELL);+ return;+ }+ + //else...don't cancel "autoshot" and send result, if "cooldown" is over; except "moving"+ if (isAttackReady(RANGED_ATTACK) && result!= SPELL_FAILED_MOVING)+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);+ + //if interruption is during the prepare animation we additionally need to stop animation+ if (getAttackTimer(RANGED_ATTACK)<=500 && !m_AutoRepeatFirstCast)+ {+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendInterrupted(0);+ }+ //now we need again our 0.5 sec....+ m_AutoRepeatFirstCast = true;+ + }+ + //...we CanCast, now check if we are castig melee spell, or anything else + else if ( (m_currentSpells[CURRENT_MELEE_SPELL] &&+ (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&+ (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)+ ) || + IsNonMeleeSpellCasted(false, false, true)+ )+ {+ //...of course we need again time to aim ....+ m_AutoRepeatFirstCast = true;+ }+ + else //ok, nothing casting currently+ { + //handling the 0.5s+ if( m_AutoRepeatFirstCast == true && getAttackTimer(RANGED_ATTACK) < 500 ) + { + setAttackTimer(RANGED_ATTACK, 500);+ }+ + m_AutoRepeatFirstCast = false;+ + // handle graphics, 0.5sec of preparing (blizz-like) + if( getAttackTimer(RANGED_ATTACK) <= 500 && m_AutoRepeatSendSpellStart )+ {+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendSpellStart();+ m_AutoRepeatSendSpellStart = false;+ }+ // start the spell if ready+ if( isAttackReady(RANGED_ATTACK) ) + {+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));+ resetAttackTimer( RANGED_ATTACK ); + }+ }+ }+ + else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_DELAYED)+ { + //store spell information+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id);+ + m_AutoRepeatFirstCast = true;+ m_AutoRepeatSendSpellStart = true;+ + //create and intialize new spell with old target+ Spell *p_spell = new Spell(this, spellInfo, false, 0);+ p_spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));+ } } void Unit::SetCurrentCastedSpell( Spell * pSpell )@@ -3521,6 +3526,9 @@ // break autorepeat if not Auto Shot if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) InterruptSpell(CURRENT_AUTOREPEAT_SPELL);+ + //new casttime for autoshot in any case+ m_AutoRepeatFirstCast = true; } } break; @@ -3544,12 +3552,7 @@ // generic autorepeats break generic non-delayed and channeled non-delayed spells InterruptSpell(CURRENT_GENERIC_SPELL,false); InterruptSpell(CURRENT_CHANNELED_SPELL,false);- }- else- {- // special action: set first cast flag for Auto Shoot- m_AutoRepeatFirstCast = true;- }+ } } break; default:@@ -3572,12 +3575,8 @@ if(m_currentSpells[spellType] && (withDelayed || m_currentSpells[spellType]->getState() != SPELL_STATE_DELAYED) ) {- // send autorepeat cancel message for autorepeat spells- if (spellType == CURRENT_AUTOREPEAT_SPELL)- {- if(GetTypeId()==TYPEID_PLAYER)- ((Player*)this)->SendAutoRepeatCancel();- }+ // set first cast for autorepeat spells+ if (spellType == CURRENT_AUTOREPEAT_SPELL) m_AutoRepeatFirstCast = true; if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED) m_currentSpells[spellType]->cancel();@@ -3624,9 +3623,7 @@ // autorepeat spells are interrupted if they are not finished or delayed if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id==spell_id)) {- // send disable autorepeat packet in any case- if(GetTypeId()==TYPEID_PLAYER)- ((Player*)this)->SendAutoRepeatCancel();+ m_AutoRepeatFirstCast = true; if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) && (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )Index: src/game/Unit.h===================================================================--- src/game/Unit.h (revision 5734)+++ src/game/Unit.h (working copy)@@ -947,6 +947,7 @@ float m_threatModifier[MAX_SPELL_SCHOOL]; float m_modAttackSpeedPct[3];+ bool m_AutoRepeatFirstCast; // Event handler EventProcessor m_Events;@@ -1116,7 +1117,7 @@ void _UpdateSpells(uint32 time); void _UpdateAutoRepeatSpell();- bool m_AutoRepeatFirstCast;+ bool m_AutoRepeatSendSpellStart; uint32 m_attackTimer[MAX_ATTACK];