Index: game/CharacterHandler.cpp =================================================================== --- game/CharacterHandler.cpp (revision 5306) +++ game/CharacterHandler.cpp (working copy) @@ -61,7 +61,7 @@ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid,account,data,name,race,class,position_x,position_y,position_z,map,orientation,taximask,cinematic,totaltime,leveltime,rest_bonus,logout_time,is_logout_resting,resettalents_cost,resettalents_time,trans_x,trans_y,trans_z,trans_o, transguid,gmstate,stable_slots,at_login,zone,online,pending_honor,last_honor_date,last_kill_date,taxi_path FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT map,instance,leader FROM character_instance WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges,stacks FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,slot,active FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid)); Index: game/Pet.cpp =================================================================== --- game/Pet.cpp (revision 5306) +++ game/Pet.cpp (working copy) @@ -1212,7 +1212,7 @@ for(int i = UNIT_FIELD_AURA; i <= UNIT_FIELD_AURASTATE; ++i) SetUInt32Value(i, 0); - QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber()); + QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges,stacks FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber()); if(result) { @@ -1226,6 +1226,7 @@ int32 maxduration = (int32)fields[4].GetUInt32(); int32 remaintime = (int32)fields[5].GetUInt32(); int32 remaincharges = (int32)fields[6].GetUInt32(); + uint32 stacks = (int32)fields[7].GetUInt32(); SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid); if(!spellproto) @@ -1265,7 +1266,9 @@ aura = new Aura(spellproto, effindex, NULL, this, NULL); if(!damage) damage = aura->GetModifier()->m_amount; - aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); + aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges,stacks); + if (stacks > 1) + aura->UpdateStackableAura( NULL, true ); AddAura(aura); } while( result->NextRow() ); @@ -1289,9 +1292,9 @@ break; if (i == 3 && !itr->second->IsPassive()) - CharacterDatabase.PExecute("INSERT INTO pet_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges) " - "VALUES ('%u', '" I64FMTD "', '%u', '%u', '%d', '%d', '%d', '%d')", - m_charmInfo->GetPetNumber(), itr->second->GetCasterGUID(),(uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(),(*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges)); + CharacterDatabase.PExecute("INSERT INTO pet_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges,stacks) " + "VALUES ('%u', '" I64FMTD "', '%u', '%u', '%d', '%d', '%d', '%d','%d')", + m_charmInfo->GetPetNumber(), itr->second->GetCasterGUID(),(uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(),(*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges),int((*itr).second->GetStackAmmount())); } } Index: game/Player.cpp =================================================================== --- game/Player.cpp (revision 5306) +++ game/Player.cpp (working copy) @@ -12997,6 +12997,7 @@ int32 maxduration = (int32)fields[4].GetUInt32(); int32 remaintime = (int32)fields[5].GetUInt32(); int32 remaincharges = (int32)fields[6].GetUInt32(); + int32 stacks = (int32)fields[7].GetUInt32(); SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid); if(!spellproto) @@ -13036,8 +13037,11 @@ aura = new Aura(spellproto, effindex, NULL, this, NULL); if(!damage) damage = aura->GetModifier()->m_amount; - aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); + aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges,stacks); + if (stacks > 1) + aura->UpdateStackableAura( NULL, true ); AddAura(aura); + } while( result->NextRow() ); @@ -13927,9 +13931,9 @@ if (i == 3) { CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u' and spell = '%u' and effect_index= '%u'",GetGUIDLow(),(uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex()); - CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges) " - "VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%d', '%d', '%d', '%d')", - GetGUIDLow(), itr->second->GetCasterGUID(), (uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(), (*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges)); + CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges,stacks) " + "VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%d', '%d', '%d', '%d', '%d')", + GetGUIDLow(), itr->second->GetCasterGUID(), (uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(), (*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges),int((*itr).second->GetStackAmmount())); } } } Index: game/SpellAuras.cpp =================================================================== --- game/SpellAuras.cpp (revision 5306) +++ game/SpellAuras.cpp (working copy) @@ -394,6 +394,11 @@ else m_procCharges = -1; + // count from 1 + m_stackAmmount = 1; + // give it some damage + m_stackDamage = damage; + m_isRemovedOnShapeLost = (m_caster_guid==m_target->GetGUID() && m_spellProto->Stances && !(m_spellProto->AttributesEx2 & 0x80000) && !(m_spellProto->Attributes & 0x10000)); } @@ -741,20 +746,8 @@ if(!m_target) return; - bool samespell = false; uint8 slot = 0xFF; - for(uint8 i = 0; i < 3; i++) - { - Aura* aura = m_target->GetAura(m_spellId, i); - if(aura) - { - samespell = true; - slot = aura->GetAuraSlot(); - break; - } - } - //if(m_spellId == 23333 || m_spellId == 23335) // for BG // m_positive = true; @@ -776,56 +769,49 @@ // passive auras (except totem auras) do not get placed in the slots if(!m_isPassive || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())) { - if(!samespell) + if (IsPositive()) { - if (IsPositive()) + for (uint8 i = 0; i < MAX_POSITIVE_AURAS; i++) { - for (uint8 i = 0; i < MAX_POSITIVE_AURAS; i++) + if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0) { - if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0) - { - slot = i; - break; - } + slot = i; + break; } } - else + } + else + { + for (uint8 i = MAX_POSITIVE_AURAS; i < MAX_AURAS; i++) { - for (uint8 i = MAX_POSITIVE_AURAS; i < MAX_AURAS; i++) + if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0) { - if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0) - { - slot = i; - break; - } + slot = i; + break; } } + } - if(slot < MAX_AURAS) - { - m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURA + slot), GetId()); + if(slot < MAX_AURAS) + { + m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURA + slot), GetId()); - uint8 flagslot = slot >> 2; - uint32 value = m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot)); + uint8 flagslot = slot >> 2; + uint32 value = m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot)); + + uint8 value1 = (slot & 3) << 3; - uint8 value1 = (slot & 3) << 3; + value &= ~((uint32)AFLAG_MASK << value1); + if (IsPositive()) + value |= ((uint32)AFLAG_POSITIVE << value1); + else + value |= ((uint32)AFLAG_NEGATIVE << value1); + m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot), value); + } - value &= ~((uint32)AFLAG_MASK << value1); - if (IsPositive()) - value |= ((uint32)AFLAG_POSITIVE << value1); - else - value |= ((uint32)AFLAG_NEGATIVE << value1); - m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot), value); - } + SetAuraSlot( slot ); + UpdateAuraDuration(); - SetAuraSlot( slot ); - UpdateAuraDuration(); - } - else - { - SetAuraSlot( slot ); - UpdateSlotCounterAndDuration(true); - } // Update Seals information if( IsSealSpell(GetId()) ) @@ -878,93 +864,99 @@ if(m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + slot)) == 0) return; - bool samespell = false; + m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURA + slot), 0); - for(uint8 i = 0; i < 3; i++) - { - Aura* aura = m_target->GetAura(m_spellId, i); - if(aura) - { - samespell = true; - break; - } - } + uint8 flagslot = slot >> 2; - // only remove icon when the last aura of the spell is removed (current aura already removed from list) - if (!samespell) - { - m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURA + slot), 0); + uint32 value = m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot)); - uint8 flagslot = slot >> 2; + uint8 aurapos = (slot & 3) << 3; + value &= ~((uint32)AFLAG_MASK << aurapos ); - uint32 value = m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot)); + m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot), value); + if( IsSealSpell(GetId()) ) + m_target->ModifyAuraState(AURA_STATE_JUDGEMENT,false); - uint8 aurapos = (slot & 3) << 3; - value &= ~((uint32)AFLAG_MASK << aurapos ); + // Conflagrate aura state + if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4)) + m_target->ModifyAuraState(AURA_STATE_IMMOLATE, false); - m_target->SetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + flagslot), value); - if( IsSealSpell(GetId()) ) - m_target->ModifyAuraState(AURA_STATE_JUDGEMENT,false); - - // Conflagrate aura state - if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4)) - m_target->ModifyAuraState(AURA_STATE_IMMOLATE, false); - - // Swiftmend aura state - if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID - && (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10)) + // Swiftmend aura state + if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID + && (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10)) + { + bool found = false; + Unit::AuraList const& RejorRegr = m_target->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); + for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) { - bool found = false; - Unit::AuraList const& RejorRegr = m_target->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); - for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) + if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID + && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) ) { - if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID - && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) ) - { - found = true; - break; - } + found = true; + break; } - if(!found) - m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, false); } - - // reset cooldown state for spells infinity/long aura (it's all self applied (?)) - int32 duration = GetDuration(GetSpellProto()); - if( caster==m_target && ( duration < 0 || uint32(duration) > GetRecoveryTime(GetSpellProto()) )) - SendCoolDownEvent(); + if(!found) + m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, false); } - else // decrease count for spell - UpdateSlotCounterAndDuration(false); + + // reset cooldown state for spells infinity/long aura (it's all self applied (?)) + int32 duration = GetDuration(GetSpellProto()); + if( caster==m_target && ( duration < 0 || uint32(duration) > GetRecoveryTime(GetSpellProto()) )) + SendCoolDownEvent(); + } -void Aura::UpdateSlotCounterAndDuration(bool add) +void Aura::ModStackAmmount(int32 val) { + // Already Full + if( (m_stackAmmount + val) > m_spellProto->StackAmount ) + { + val = m_spellProto->StackAmount - m_stackAmmount; + // nothing to change + if ( val == 0 ) + return; + } + + ApplyModifier( false, false ); + m_stackAmmount += val; + + // remove if empty + if ( m_stackAmmount <= 0 ) + { + m_target->RemoveAura(m_spellId, m_effIndex); + return; + } + // modify damage + m_modifier.m_amount += m_stackDamage * val; + ApplyModifier( true, false ); + +} + +void Aura::UpdateStackableAura(Unit* caster, bool load) +{ uint8 slot = GetAuraSlot(); if(slot >= MAX_AURAS) return; - // calculate amount of similar auras by same effect index (similar different spells) - int8 count = 0; + if ( !load ) + { + SetAuraDuration(caster->CalculateSpellDuration(m_spellProto)); - // calculate auras and update durations in case aura adding - Unit::AuraList const& aura_list = m_target->GetAurasByType(GetModifier()->m_auraname); - for(Unit::AuraList::const_iterator i = aura_list.begin();i != aura_list.end(); ++i) - { - if((*i)->m_spellId==m_spellId && (*i)->m_effIndex==m_effIndex) - { - ++count; + // If not full yet + if ( m_stackAmmount < m_spellProto->StackAmount ) + { + ApplyModifier( false, false ); + m_stackAmmount++; + // recalculate damage + m_stackDamage = caster->CalculateSpellDamage(m_spellProto,m_effIndex,m_currentBasePoints,m_target); + m_modifier.m_amount = m_stackDamage*m_stackAmmount; + ApplyModifier( true, false ); + } + } else { + m_stackDamage = (int32) m_modifier.m_amount/m_stackAmmount; + } - if(add) - (*i)->SetAuraDuration(GetAuraDuration()); - } - } - - // at aura add aura not added yet, at aura remove aura already removed - // in field stored (count-1) - if(!add) - --count; - uint32 index = slot / 4; uint32 byte = slot % 4; uint32 val = m_target->GetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+index); @@ -972,7 +964,7 @@ uint32 byte_bitpos = byte * 8; uint32 byte_mask = 0xFF << (byte * 8); - val = (val & ~byte_mask) | (count << byte_bitpos); + val = (val & ~byte_mask) | (m_stackAmmount << byte_bitpos); m_target->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+index, val); Index: game/SpellAuras.h =================================================================== --- game/SpellAuras.h (revision 5306) +++ game/SpellAuras.h (working copy) @@ -222,13 +222,14 @@ Unit* GetCaster() const; Unit* GetTarget() const { return m_target; } void SetTarget(Unit* target) { m_target = target; } - void SetLoadedState(uint64 caster_guid,int32 damage,int32 maxduration,int32 duration,int32 charges) + void SetLoadedState(uint64 caster_guid,int32 damage,int32 maxduration,int32 duration,int32 charges, uint32 stacks) { m_caster_guid = caster_guid; m_modifier.m_amount = damage; m_maxduration = maxduration; m_duration = duration; m_procCharges = charges; + m_stackAmmount = stacks; } uint8 GetAuraSlot() const { return m_auraSlot; } @@ -259,6 +260,10 @@ void SetUpdated(bool val) { m_updated = val; } void SetRemoveOnDeath(bool rod) { m_removeOnDeath = rod; } + void UpdateStackableAura(Unit* caster, bool load); + uint32 GetStackAmmount( void ) { return m_stackAmmount; } + void ModStackAmmount(int32 val); + int32 m_procCharges; // add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras @@ -295,8 +300,10 @@ uint32 m_PeriodicEventId; bool m_updated; bool m_removeOnDeath; + + uint32 m_stackAmmount; + int32 m_stackDamage; private: - void UpdateSlotCounterAndDuration(bool add); void CleanupTriggeredSpells(); float m_fearMoveAngle; Index: game/SpellEffects.cpp =================================================================== --- game/SpellEffects.cpp (revision 5306) +++ game/SpellEffects.cpp (working copy) @@ -342,20 +342,23 @@ // remove consumed poison doses Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;) + for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end();++itr) { // Deadly poison if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) && (*itr)->GetSpellProto()->SpellVisual==5100) { - --combo; - ++doses; - unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex()); + if ( combo > (*itr)->GetStackAmmount()) + combo = (*itr)->GetStackAmmount(); - itr = auras.begin(); + doses = (*itr)->GetStackAmmount(); + + if ( doses > combo) + doses = combo; + + (*itr)->ModStackAmmount(combo*(-1)); + break; } - else - ++itr; } damage *= doses; @@ -421,8 +424,13 @@ uint32 stacks = 0; Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) + { if((*itr)->GetId() == 31803) - stacks++; + { + stacks=(*itr)->GetStackAmmount(); + break; + } + } if(!stacks) //No damage if the target isn't affected by this damage = -1; @@ -3229,7 +3237,8 @@ int32 duration = GetDuration(proto); (*itr)->SetAuraDuration(duration); (*itr)->UpdateAuraDuration(); - sunder_stacks++; + sunder_stacks=(*itr)->GetStackAmmount(); + break; } } Index: game/Unit.cpp =================================================================== --- game/Unit.cpp (revision 5306) +++ game/Unit.cpp (working copy) @@ -3435,14 +3435,14 @@ // take out same spell if (i != m_Auras.end()) { - /*(*i).second->SetAuraDuration(Aur->GetAuraDuration()); - if ((*i).second->GetTarget()) - if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER ) - (*i).second->UpdateAuraDuration(); - delete Aur; - return false;*/ + if ( Aur->GetSpellProto()->StackAmount) + { + Aur->UpdateStackableAura(this, false); + delete Aur; + return false; + } // passive and persistent auras can stack with themselves any number of times - if (!Aur->IsPassive() && !Aur->IsPersistent() && m_Auras.count(spellEffectPair(Aur->GetId(), Aur->GetEffIndex())) >= Aur->GetSpellProto()->StackAmount) + if (!Aur->IsPassive() && !Aur->IsPersistent()) RemoveAura(i); } @@ -3739,13 +3739,6 @@ RemoveAura(iter); } -void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex) -{ - AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex)); - if(iter != m_Auras.end()) - RemoveAura(iter); -} - void Unit::RemoveAurasDueToSpell(uint32 spellId) { for (int i = 0; i < 3; ++i) Index: game/Unit.h =================================================================== --- game/Unit.h (revision 5306) +++ game/Unit.h (working copy) @@ -810,7 +810,6 @@ bool RemoveFirstAuraByDispel(uint32 dispel_type, Unit *pCaster); void RemoveAura(AuraMap::iterator &i, bool onDeath = false); void RemoveAura(uint32 spellId, uint32 effindex); - void RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex); void RemoveAurasDueToSpell(uint32 spellId); void RemoveAurasDueToItem(Item* castItem); void RemoveSpellsCausingAura(AuraType auraType);