[11299] Handle aura durations in SpellAuraHolder

- Unit::CalculateSpellDuration split into two functions
    - CalculateSpellDuration taking into account combo points and caster-side spell mods
    - Unit::CalculateAuraDuration taking into account target-side spell mods
- Diminishing is now applied before duration reduction mods
- Implement saving per-effect periodic timers to DB (required for auras affected by haste)
This commit is contained in:
zergtmn 2011-03-30 23:29:01 +06:00
parent 5833d74963
commit 4687fa8cb4
19 changed files with 388 additions and 379 deletions

View file

@ -21,7 +21,7 @@
DROP TABLE IF EXISTS `character_db_version`;
CREATE TABLE `character_db_version` (
`required_11117_02_characters_world` bit(1) default NULL
`required_11299_02_characters_pet_aura` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
--
@ -372,18 +372,17 @@ CREATE TABLE `character_aura` (
`caster_guid` bigint(20) unsigned NOT NULL default '0' COMMENT 'Full Global Unique Identifier',
`item_guid` int(11) unsigned NOT NULL default '0',
`spell` int(11) unsigned NOT NULL default '0',
`stackcount` int(11) NOT NULL default '1',
`remaincharges` int(11) NOT NULL default '0',
`stackcount` INT(11) UNSIGNED NOT NULL DEFAULT '1',
`remaincharges` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`basepoints0` INT(11) NOT NULL DEFAULT '0',
`basepoints1` INT(11) NOT NULL DEFAULT '0',
`basepoints2` INT(11) NOT NULL DEFAULT '0',
`maxduration0` INT(11) NOT NULL DEFAULT '0',
`maxduration1` INT(11) NOT NULL DEFAULT '0',
`maxduration2` INT(11) NOT NULL DEFAULT '0',
`remaintime0` INT(11) NOT NULL DEFAULT '0',
`remaintime1` INT(11) NOT NULL DEFAULT '0',
`remaintime2` INT(11) NOT NULL DEFAULT '0',
`effIndexMask` INT(11) NOT NULL DEFAULT '0',
`periodictime0` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`periodictime1` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`periodictime2` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`maxduration` INT(11) NOT NULL DEFAULT '0',
`remaintime` INT(11) NOT NULL DEFAULT '0',
`effIndexMask` INT(11) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`,`caster_guid`,`item_guid`,`spell`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
@ -1565,18 +1564,17 @@ CREATE TABLE `pet_aura` (
`caster_guid` bigint(20) unsigned NOT NULL default '0' COMMENT 'Full Global Unique Identifier',
`item_guid` int(11) unsigned NOT NULL default '0',
`spell` int(11) unsigned NOT NULL default '0',
`stackcount` int(11) NOT NULL default '1',
`remaincharges` int(11) NOT NULL default '0',
`stackcount` INT(11) UNSIGNED NOT NULL DEFAULT '1',
`remaincharges` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`basepoints0` INT(11) NOT NULL DEFAULT '0',
`basepoints1` INT(11) NOT NULL DEFAULT '0',
`basepoints2` INT(11) NOT NULL DEFAULT '0',
`maxduration0` INT(11) NOT NULL DEFAULT '0',
`maxduration1` INT(11) NOT NULL DEFAULT '0',
`maxduration2` INT(11) NOT NULL DEFAULT '0',
`remaintime0` INT(11) NOT NULL DEFAULT '0',
`remaintime1` INT(11) NOT NULL DEFAULT '0',
`remaintime2` INT(11) NOT NULL DEFAULT '0',
`effIndexMask` INT(11) NOT NULL DEFAULT '0',
`periodictime0` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`periodictime1` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`periodictime2` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`maxduration` INT(11) NOT NULL DEFAULT '0',
`remaintime` INT(11) NOT NULL DEFAULT '0',
`effIndexMask` INT(11) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`,`caster_guid`,`item_guid`,`spell`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System';

View file

@ -0,0 +1,16 @@
ALTER TABLE character_db_version CHANGE COLUMN required_11117_02_characters_world required_11299_01_characters_character_aura bit;
TRUNCATE TABLE character_aura;
ALTER TABLE character_aura
CHANGE COLUMN `maxduration0` `maxduration` INT(11) NOT NULL DEFAULT '0',
CHANGE COLUMN `remaintime0` `remaintime` INT(11) NOT NULL DEFAULT '0',
ADD COLUMN `periodictime0` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `basepoints2`,
ADD COLUMN `periodictime1` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `periodictime0`,
ADD COLUMN `periodictime2` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `periodictime1`,
DROP COLUMN `maxduration1`,
DROP COLUMN `maxduration2`,
DROP COLUMN `remaintime1`,
DROP COLUMN `remaintime2`,
CHANGE COLUMN `stackcount` `stackcount` INT(11) UNSIGNED NOT NULL DEFAULT '1',
CHANGE COLUMN `remaincharges` `remaincharges` INT(11) UNSIGNED NOT NULL DEFAULT '0',
CHANGE COLUMN `effIndexMask` `effIndexMask` INT(11) UNSIGNED NOT NULL DEFAULT '0';

View file

@ -0,0 +1,16 @@
ALTER TABLE character_db_version CHANGE COLUMN required_11299_01_characters_character_aura required_11299_02_characters_pet_aura bit;
TRUNCATE TABLE pet_aura;
ALTER TABLE pet_aura
CHANGE COLUMN `maxduration0` `maxduration` INT(11) NOT NULL DEFAULT '0',
CHANGE COLUMN `remaintime0` `remaintime` INT(11) NOT NULL DEFAULT '0',
ADD COLUMN `periodictime0` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `basepoints2`,
ADD COLUMN `periodictime1` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `periodictime0`,
ADD COLUMN `periodictime2` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `periodictime1`,
DROP COLUMN `maxduration1`,
DROP COLUMN `maxduration2`,
DROP COLUMN `remaintime1`,
DROP COLUMN `remaintime2`,
CHANGE COLUMN `stackcount` `stackcount` INT(11) UNSIGNED NOT NULL DEFAULT '1',
CHANGE COLUMN `remaincharges` `remaincharges` INT(11) UNSIGNED NOT NULL DEFAULT '0',
CHANGE COLUMN `effIndexMask` `effIndexMask` INT(11) UNSIGNED NOT NULL DEFAULT '0';

View file

@ -74,7 +74,7 @@ bool LoginQueryHolder::Initialize()
"health, power1, power2, power3, power4, power5, power6, power7, specCount, activeSpec, exploredZones, equipmentCache, ammoId, knownTitles, actionBars FROM characters WHERE guid = '%u'", m_guid.GetCounter());
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT groupId FROM group_member WHERE memberGuid ='%u'", m_guid.GetCounter());
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", m_guid.GetCounter());
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,item_guid,spell,stackcount,remaincharges,basepoints0,basepoints1,basepoints2,maxduration0,maxduration1,maxduration2,remaintime0,remaintime1,remaintime2,effIndexMask FROM character_aura WHERE guid = '%u'", m_guid.GetCounter());
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,item_guid,spell,stackcount,remaincharges,basepoints0,basepoints1,basepoints2,periodictime0,periodictime1,periodictime2,maxduration,remaintime,effIndexMask FROM character_aura WHERE guid = '%u'", m_guid.GetCounter());
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'", m_guid.GetCounter());
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'", m_guid.GetCounter());
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest FROM character_queststatus_daily WHERE guid = '%u'", m_guid.GetCounter());

View file

@ -164,16 +164,7 @@ inline void MaNGOS::DynamicObjectUpdater::VisitHelper(Unit* target)
if (holder)
{
if (Aura* aura = holder->GetAuraByEffectIndex(eff_index))
{
// already exists, refresh duration
if (aura->GetAuraDuration() >=0 && uint32(aura->GetAuraDuration()) < i_dynobject.GetDuration())
{
aura->SetAuraDuration(i_dynobject.GetDuration());
holder->SendAuraUpdate(false);
}
}
else
if (!holder->GetAuraByEffectIndex(eff_index))
{
PersistentAreaAura* Aur = new PersistentAreaAura(spellInfo, eff_index, NULL, holder, target, i_dynobject.GetCaster());
holder->AddAura(Aur, eff_index);
@ -182,6 +173,11 @@ inline void MaNGOS::DynamicObjectUpdater::VisitHelper(Unit* target)
Aur->ApplyModifier(true,true);
holder->SetInUse(false);
}
else if (holder->GetAuraDuration() >= 0 && uint32(holder->GetAuraDuration()) < i_dynobject.GetDuration())
{
holder->SetAuraDuration(i_dynobject.GetDuration());
holder->SendAuraUpdate(false);
}
}
else
{

View file

@ -1243,7 +1243,7 @@ void Pet::_LoadAuras(uint32 timediff)
{
RemoveAllAuras();
QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,item_guid,spell,stackcount,remaincharges,basepoints0,basepoints1,basepoints2,maxduration0,maxduration1,maxduration2,remaintime0,remaintime1,remaintime2,effIndexMask FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber());
QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,item_guid,spell,stackcount,remaincharges,basepoints0,basepoints1,basepoints2,periodictime0,periodictime1,periodictime2,maxduration,remaintime,effIndexMask FROM pet_aura WHERE guid = '%u'", m_charmInfo->GetPetNumber());
if(result)
{
@ -1255,16 +1255,18 @@ void Pet::_LoadAuras(uint32 timediff)
uint32 spellid = fields[2].GetUInt32();
uint32 stackcount = fields[3].GetUInt32();
uint32 remaincharges = fields[4].GetUInt32();
int32 damage[MAX_EFFECT_INDEX];
int32 maxduration[MAX_EFFECT_INDEX];
int32 remaintime[MAX_EFFECT_INDEX];
int32 damage[MAX_EFFECT_INDEX];
uint32 periodicTime[MAX_EFFECT_INDEX];
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
damage[i] = fields[i+5].GetInt32();
maxduration[i] = fields[i+8].GetInt32();
remaintime[i] = fields[i+11].GetInt32();
periodicTime[i] = fields[i+8].GetUInt32();
}
uint32 effIndexMask = fields[14].GetUInt32();
int32 maxduration = fields[11].GetInt32();
int32 remaintime = fields[12].GetInt32();
uint32 effIndexMask = fields[13].GetUInt32();
SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid);
if (!spellproto)
@ -1277,6 +1279,14 @@ void Pet::_LoadAuras(uint32 timediff)
if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto))
continue;
if (remaintime != -1 && !IsPositiveSpell(spellproto))
{
if (remaintime/IN_MILLISECONDS <= int32(timediff))
continue;
remaintime -= timediff*IN_MILLISECONDS;
}
// prevent wrong values of remaincharges
uint32 procCharges = spellproto->procCharges;
if (procCharges)
@ -1294,34 +1304,24 @@ void Pet::_LoadAuras(uint32 timediff)
else if (!stackcount)
stackcount = 1;
SpellAuraHolder *holder = CreateSpellAuraHolder(spellproto, this, NULL);
holder->SetLoadedState(caster_guid, ObjectGuid(HIGHGUID_ITEM, item_lowguid), stackcount, remaincharges, maxduration, remaintime);
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if ((effIndexMask & (1 << i)) == 0)
continue;
if (remaintime[i] != -1 && !IsPositiveEffect(spellproto, SpellEffectIndex(i)))
{
if (remaintime[i]/IN_MILLISECONDS <= int32(timediff))
continue;
remaintime[i] -= timediff*IN_MILLISECONDS;
}
Aura* aura = CreateAura(spellproto, SpellEffectIndex(i), NULL, holder, this);
if (!damage[i])
damage[i] = aura->GetModifier()->m_amount;
aura->SetLoadedState(damage[i], maxduration[i], remaintime[i]);
aura->SetLoadedState(damage[i], periodicTime[i]);
holder->AddAura(aura, SpellEffectIndex(i));
}
if (!holder->IsEmptyHolder())
{
holder->SetLoadedState(caster_guid, ObjectGuid(HIGHGUID_ITEM, item_lowguid), stackcount, remaincharges);
AddSpellAuraHolder(holder);
}
else
delete holder;
}
@ -1344,6 +1344,10 @@ void Pet::_SaveAuras()
if (auraHolders.empty())
return;
stmt = CharacterDatabase.CreateStatement(insAuras, "INSERT INTO pet_aura (guid, caster_guid, item_guid, spell, stackcount, remaincharges, "
"basepoints0, basepoints1, basepoints2, periodictime0, periodictime1, periodictime2, maxduration, remaintime, effIndexMask) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for(SpellAuraHolderMap::const_iterator itr = auraHolders.begin(); itr != auraHolders.end(); ++itr)
{
SpellAuraHolder *holder = itr->second;
@ -1365,16 +1369,14 @@ void Pet::_SaveAuras()
//do not save single target holders (unless they were cast by the player)
if (save && !holder->IsPassive() && !IsChanneledSpell(holder->GetSpellProto()) && (holder->GetCasterGUID() == GetGUID() || !holder->IsSingleTarget()))
{
int32 damage[MAX_EFFECT_INDEX];
int32 remaintime[MAX_EFFECT_INDEX];
int32 maxduration[MAX_EFFECT_INDEX];
int32 damage[MAX_EFFECT_INDEX];
uint32 periodicTime[MAX_EFFECT_INDEX];
uint32 effIndexMask = 0;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
damage[i] = 0;
remaintime[i] = 0;
maxduration[i] = 0;
periodicTime[i] = 0;
if (Aura *aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i)))
{
@ -1383,8 +1385,7 @@ void Pet::_SaveAuras()
continue;
damage[i] = aur->GetModifier()->m_amount;
remaintime[i] = aur->GetAuraDuration();
maxduration[i] = aur->GetAuraMaxDuration();
periodicTime[i] = aur->GetModifier()->periodictime;
effIndexMask |= (1 << i);
}
}
@ -1392,9 +1393,6 @@ void Pet::_SaveAuras()
if (!effIndexMask)
continue;
stmt = CharacterDatabase.CreateStatement(insAuras, "INSERT INTO pet_aura (guid, caster_guid, item_guid, spell, stackcount, remaincharges, basepoints0, basepoints1, basepoints2, maxduration0, maxduration1, maxduration2, remaintime0, remaintime1, remaintime2, effIndexMask) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
stmt.addUInt32(m_charmInfo->GetPetNumber());
stmt.addUInt64(holder->GetCasterGuid().GetRawValue());
stmt.addUInt32(holder->GetCastItemGuid().GetCounter());
@ -1402,15 +1400,14 @@ void Pet::_SaveAuras()
stmt.addUInt32(holder->GetStackAmount());
stmt.addUInt8(holder->GetAuraCharges());
for (int i = EFFECT_INDEX_0; i <= EFFECT_INDEX_2; ++i )
for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i)
stmt.addInt32(damage[i]);
for (int i = EFFECT_INDEX_0; i <= EFFECT_INDEX_2; ++i )
stmt.addInt32(maxduration[i]);
for (int i = EFFECT_INDEX_0; i <= EFFECT_INDEX_2; ++i )
stmt.addInt32(remaintime[i]);
for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i)
stmt.addUInt32(periodicTime[i]);
stmt.addInt32(holder->GetAuraMaxDuration());
stmt.addInt32(holder->GetAuraDuration());
stmt.addUInt32(effIndexMask);
stmt.Execute();
}

View file

@ -4544,10 +4544,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
if (SpellAuraHolder* holder = GetSpellAuraHolder(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS))
{
for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
if(Aura* Aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i)))
Aur->SetAuraDuration(delta*IN_MILLISECONDS);
holder->SetAuraDuration(delta*IN_MILLISECONDS);
holder->SendAuraUpdate(false);
}
}
@ -15931,7 +15928,7 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
{
//RemoveAllAuras(); -- some spells casted before aura load, for example in LoadSkills, aura list explicitly cleaned early
//QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,item_guid,spell,stackcount,remaincharges,basepoints0,basepoints1,basepoints2,maxduration0,maxduration1,maxduration2,remaintime0,remaintime1,remaintime2,effIndexMask FROM character_aura WHERE guid = '%u'",GetGUIDLow());
//QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,item_guid,spell,stackcount,remaincharges,basepoints0,basepoints1,basepoints2,periodictime0,periodictime1,periodictime2,maxduration,remaintime,effIndexMask FROM character_aura WHERE guid = '%u'",GetGUIDLow());
if(result)
{
@ -15943,16 +15940,18 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
uint32 spellid = fields[2].GetUInt32();
uint32 stackcount = fields[3].GetUInt32();
uint32 remaincharges = fields[4].GetUInt32();
int32 damage[MAX_EFFECT_INDEX];
int32 maxduration[MAX_EFFECT_INDEX];
int32 remaintime[MAX_EFFECT_INDEX];
int32 damage[MAX_EFFECT_INDEX];
uint32 periodicTime[MAX_EFFECT_INDEX];
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
damage[i] = fields[i+5].GetInt32();
maxduration[i] = fields[i+8].GetInt32();
remaintime[i] = fields[i+11].GetInt32();
periodicTime[i] = fields[i+8].GetUInt32();
}
uint32 effIndexMask = fields[14].GetUInt32();
int32 maxduration = fields[11].GetInt32();
int32 remaintime = fields[12].GetInt32();
uint32 effIndexMask = fields[13].GetUInt32();
SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid);
if (!spellproto)
@ -15961,6 +15960,14 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
continue;
}
if (remaintime != -1 && !IsPositiveSpell(spellproto))
{
if (remaintime/IN_MILLISECONDS <= int32(timediff))
continue;
remaintime -= timediff*IN_MILLISECONDS;
}
// prevent wrong values of remaincharges
if (spellproto->procCharges)
{
@ -15978,24 +15985,18 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
stackcount = 1;
SpellAuraHolder *holder = CreateSpellAuraHolder(spellproto, this, NULL);
holder->SetLoadedState(caster_guid, ObjectGuid(HIGHGUID_ITEM, item_lowguid), stackcount, remaincharges, maxduration, remaintime);
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if ((effIndexMask & (1 << i)) == 0)
continue;
if (remaintime[i] != -1 && !IsPositiveEffect(spellproto, SpellEffectIndex(i)))
{
if (remaintime[i]/IN_MILLISECONDS <= int32(timediff))
continue;
remaintime[i] -= timediff*IN_MILLISECONDS;
}
Aura* aura = CreateAura(spellproto, SpellEffectIndex(i), NULL, holder, this);
if (!damage[i])
damage[i] = aura->GetModifier()->m_amount;
aura->SetLoadedState(damage[i], maxduration[i], remaintime[i]);
aura->SetLoadedState(damage[i], periodicTime[i]);
holder->AddAura(aura, SpellEffectIndex(i));
}
@ -16005,7 +16006,6 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
if (caster_guid != GetObjectGuid() && holder->IsSingleTarget())
holder->SetIsSingleTarget(false);
holder->SetLoadedState(caster_guid, ObjectGuid(HIGHGUID_ITEM, item_lowguid), stackcount, remaincharges);
AddSpellAuraHolder(holder);
DETAIL_LOG("Added auras from spellid %u", spellproto->Id);
}
@ -17355,9 +17355,9 @@ void Player::_SaveAuras()
if (auraHolders.empty())
return;
stmt = CharacterDatabase.CreateStatement(insertAuras, "INSERT INTO character_aura (guid, caster_guid, item_guid, spell, stackcount, "
"remaincharges, basepoints0,basepoints1, basepoints2, maxduration0, maxduration1, maxduration2, remaintime0, remaintime1, remaintime2, effIndexMask) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
stmt = CharacterDatabase.CreateStatement(insertAuras, "INSERT INTO character_aura (guid, caster_guid, item_guid, spell, stackcount, remaincharges, "
"basepoints0, basepoints1, basepoints2, periodictime0, periodictime1, periodictime2, maxduration, remaintime, effIndexMask) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for(SpellAuraHolderMap::const_iterator itr = auraHolders.begin(); itr != auraHolders.end(); ++itr)
{
@ -17366,16 +17366,14 @@ void Player::_SaveAuras()
//do not save single target holders (unless they were cast by the player)
if (!holder->IsPassive() && !IsChanneledSpell(holder->GetSpellProto()) && (holder->GetCasterGUID() == GetGUID() || !holder->IsSingleTarget()))
{
int32 damage[MAX_EFFECT_INDEX];
int32 remaintime[MAX_EFFECT_INDEX];
int32 maxduration[MAX_EFFECT_INDEX];
int32 damage[MAX_EFFECT_INDEX];
uint32 periodicTime[MAX_EFFECT_INDEX];
uint32 effIndexMask = 0;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
damage[i] = 0;
remaintime[i] = 0;
maxduration[i] = 0;
periodicTime[i] = 0;
if (Aura *aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i)))
{
@ -17384,8 +17382,7 @@ void Player::_SaveAuras()
continue;
damage[i] = aur->GetModifier()->m_amount;
remaintime[i] = aur->GetAuraDuration();
maxduration[i] = aur->GetAuraMaxDuration();
periodicTime[i] = aur->GetModifier()->periodictime;
effIndexMask |= (1 << i);
}
}
@ -17399,12 +17396,15 @@ void Player::_SaveAuras()
stmt.addUInt32(holder->GetId());
stmt.addUInt32(holder->GetStackAmount());
stmt.addUInt8(holder->GetAuraCharges());
for (int k = 0; k < MAX_EFFECT_INDEX; ++k)
stmt.addInt32(damage[k]);
for (int k = 0; k < MAX_EFFECT_INDEX; ++k)
stmt.addInt32(maxduration[k]);
for (int k = 0; k < MAX_EFFECT_INDEX; ++k)
stmt.addInt32(remaintime[k]);
for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i)
stmt.addInt32(damage[i]);
for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i)
stmt.addUInt32(periodicTime[i]);
stmt.addInt32(holder->GetAuraMaxDuration());
stmt.addInt32(holder->GetAuraDuration());
stmt.addUInt32(effIndexMask);
stmt.Execute();
}

View file

@ -1577,7 +1577,7 @@ class MANGOS_DLL_SPEC Player : public Unit
ObjectGuid const& GetSelectionGuid( ) const { return m_curSelectionGuid; }
void SetSelectionGuid(ObjectGuid guid) { m_curSelectionGuid = guid; SetTargetGuid(guid); }
uint8 GetComboPoints() { return m_comboPoints; }
uint8 GetComboPoints() const { return m_comboPoints; }
ObjectGuid const& GetComboTargetGuid() const { return m_comboTargetGuid; }
void AddComboPoints(Unit* target, int8 count);

View file

@ -1150,7 +1150,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
((Creature*)m_caster)->AI()->SpellHitTarget(unit, m_spellInfo);
}
void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
void Spell::DoSpellHitOnUnit(Unit *unit, uint32 effectMask)
{
if (!unit || !effectMask)
return;
@ -1264,9 +1264,12 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
CastPreCastSpells(unit);
if (IsSpellAppliesAura(m_spellInfo, effectMask))
spellAuraHolder = CreateSpellAuraHolder(m_spellInfo, unit, realCaster, m_CastItem);
{
m_spellAuraHolder = CreateSpellAuraHolder(m_spellInfo, unit, realCaster, m_CastItem);
m_spellAuraHolder->setDiminishGroup(m_diminishGroup);
}
else
spellAuraHolder = NULL;
m_spellAuraHolder = NULL;
for(int effectNumber = 0; effectNumber < MAX_EFFECT_INDEX; ++effectNumber)
{
@ -1287,13 +1290,39 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
}
// now apply all created auras
if (spellAuraHolder)
if (m_spellAuraHolder)
{
// normally shouldn't happen
if (!spellAuraHolder->IsEmptyHolder())
unit->AddSpellAuraHolder(spellAuraHolder);
if (!m_spellAuraHolder->IsEmptyHolder())
{
int32 duration = m_spellAuraHolder->GetAuraMaxDuration();
int32 originalDuration = duration;
if (duration > 0)
{
int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup, m_spellInfo);
unit->ApplyDiminishingToDuration(m_diminishGroup, duration, m_caster, m_diminishLevel, limitduration);
// Fully diminished
if (duration == 0)
{
delete m_spellAuraHolder;
return;
}
}
duration = unit->CalculateAuraDuration(m_spellInfo, effectMask, duration, m_caster);
if (duration != originalDuration)
{
m_spellAuraHolder->SetAuraMaxDuration(duration);
m_spellAuraHolder->SetAuraDuration(duration);
}
unit->AddSpellAuraHolder(m_spellAuraHolder);
}
else
delete spellAuraHolder;
delete m_spellAuraHolder;
}
}
@ -2771,7 +2800,7 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
if(triggeredByAura)
{
SendChannelUpdate(0);
triggeredByAura->SetAuraDuration(0);
triggeredByAura->GetHolder()->SetAuraDuration(0);
}
SendCastResult(result);
finish(false);
@ -3126,12 +3155,10 @@ void Spell::handle_immediate()
// start channeling if applicable
if(IsChanneledSpell(m_spellInfo))
{
int32 duration = GetSpellDuration(m_spellInfo);
if (duration)
int32 duration = CalculateSpellDuration(m_spellInfo, m_caster);
if (duration > 0)
{
// Apply duration mod
if(Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
m_spellState = SPELL_STATE_CASTING;
SendChannelStart(duration);
}
@ -5694,7 +5721,7 @@ SpellCastResult Spell::CheckCasterAuras() const
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (GetSpellMechanicMask(itr->second->GetSpellProto(), i) & mechanic_immune)
if (GetSpellMechanicMask(itr->second->GetSpellProto(), 1 << i) & mechanic_immune)
continue;
if (GetSpellSchoolMask(itr->second->GetSpellProto()) & school_immune)
continue;

View file

@ -542,7 +542,7 @@ class Spell
Unit* unitTarget;
Item* itemTarget;
GameObject* gameObjTarget;
SpellAuraHolder* spellAuraHolder; // spell aura holder for current target, created only if spell has aura applying effect
SpellAuraHolder* m_spellAuraHolder; // spell aura holder for current target, created only if spell has aura applying effect
int32 damage;
// this is set in Spell Hit, but used in Apply Aura handler

View file

@ -282,9 +282,9 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE implemented in Unit::SpellDamageBonusTaken
&Aura::HandleAuraModIncreaseMaxHealth, //230 Commanding Shout
&Aura::HandleNoImmediateEffect, //231 SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE
&Aura::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateSpellDuration
&Aura::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateAuraDuration
&Aura::HandleNULL, //233 set model id to the one of the creature with id m_modifier.m_miscvalue
&Aura::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateSpellDuration
&Aura::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateAuraDuration
&Aura::HandleAuraModDispelResist, //235 SPELL_AURA_MOD_DISPEL_RESIST implement in Unit::MagicSpellHitResult
&Aura::HandleAuraControlVehicle, //236 SPELL_AURA_CONTROL_VEHICLE
&Aura::HandleModSpellDamagePercentFromAttackPower, //237 SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER implemented in Unit::SpellBaseDamageBonusDone
@ -295,8 +295,8 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING (only 2 test spels in 3.2.2a)
&Aura::HandleNULL, //243 faction reaction override spells
&Aura::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE
&Aura::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS implemented in Unit::CalculateSpellDuration
&Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL implemented in Unit::CalculateSpellDuration
&Aura::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS implemented in Unit::CalculateAuraDuration
&Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL implemented in Unit::CalculateAuraDuration
&Aura::HandleNULL, //247 target to become a clone of the caster
&Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleAuraConvertRune, //249 SPELL_AURA_CONVERT_RUNE
@ -372,33 +372,24 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
static AuraType const frozenAuraTypes[] = { SPELL_AURA_MOD_ROOT, SPELL_AURA_MOD_STUN, SPELL_AURA_NONE };
Aura::Aura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 *currentBasePoints, SpellAuraHolder *holder, Unit *target, Unit *caster, Item* castItem) :
m_spellmod(NULL),
m_timeCla(1000), m_periodicTimer(0), m_periodicTick(0), m_removeMode(AURA_REMOVE_BY_DEFAULT),
m_spellmod(NULL), m_periodicTimer(0), m_periodicTick(0), m_removeMode(AURA_REMOVE_BY_DEFAULT),
m_effIndex(eff), m_positive(false), m_isPeriodic(false), m_isAreaAura(false),
m_isPersistent(false), m_in_use(0), m_spellAuraHolder(holder)
{
MANGOS_ASSERT(target);
MANGOS_ASSERT(spellproto && spellproto == sSpellStore.LookupEntry( spellproto->Id ) && "`info` must be pointer to sSpellStore element");
m_currentBasePoints = currentBasePoints ? *currentBasePoints : spellproto->CalculateSimpleValue(eff);
bool isPassive = IsPassiveSpell(GetSpellProto());
bool isPermanent = false;
m_positive = IsPositiveEffect(spellproto, m_effIndex);
m_applyTime = time(NULL);
int32 damage;
if (!caster)
{
damage = m_currentBasePoints;
m_maxduration = target->CalculateSpellDuration(spellproto, m_effIndex, target);
}
else
{
damage = caster->CalculateSpellDamage(target, spellproto, m_effIndex, &m_currentBasePoints);
m_maxduration = caster->CalculateSpellDuration(spellproto, m_effIndex, target);
damage = caster->CalculateSpellDamage(target, spellproto, m_effIndex, &m_currentBasePoints);
if (!damage && castItem && castItem->GetItemSuffixFactor())
{
@ -427,32 +418,19 @@ m_isPersistent(false), m_in_use(0), m_spellAuraHolder(holder)
}
}
if (m_maxduration == -1 || (isPassive && spellproto->DurationIndex == 0))
isPermanent = true;
Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
if (!isPermanent && modOwner)
{
modOwner->ApplySpellMod(spellproto->Id, SPELLMOD_DURATION, m_maxduration);
// Get zero duration aura after - need set m_maxduration > 0 for apply/remove aura work
if (m_maxduration<=0)
m_maxduration = 1;
}
m_duration = m_maxduration;
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Aura: construct Spellid : %u, Aura : %u Duration : %d Target : %d Damage : %d", spellproto->Id, spellproto->EffectApplyAuraName[eff], m_maxduration, spellproto->EffectImplicitTargetA[eff],damage);
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Aura: construct Spellid : %u, Aura : %u Target : %d Damage : %d", spellproto->Id, spellproto->EffectApplyAuraName[eff], spellproto->EffectImplicitTargetA[eff], damage);
SetModifier(AuraType(spellproto->EffectApplyAuraName[eff]), damage, spellproto->EffectAmplitude[eff], spellproto->EffectMiscValue[eff]);
Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
// Apply periodic time mod
if(modOwner && m_modifier.periodictime)
if (modOwner && m_modifier.periodictime)
modOwner->ApplySpellMod(spellproto->Id, SPELLMOD_ACTIVATION_TIME, m_modifier.periodictime);
// Start periodic on next tick or at aura apply
if (!(spellproto->AttributesEx5 & SPELL_ATTR_EX5_START_PERIODIC_AT_APPLY))
m_periodicTimer += m_modifier.periodictime;
m_periodicTimer = m_modifier.periodictime;
}
Aura::~Aura()
@ -569,34 +547,7 @@ void Aura::SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue)
void Aura::Update(uint32 diff)
{
if (m_duration > 0)
{
m_duration -= diff;
if (m_duration < 0)
m_duration = 0;
m_timeCla -= diff;
// GetEffIndex()==0 prevent double/triple apply manaPerSecond/manaPerSecondPerLevel to same spell with many auras
// all spells with manaPerSecond/manaPerSecondPerLevel have aura in effect 0
if (GetEffIndex() == EFFECT_INDEX_0 && m_timeCla <= 0)
{
if(Unit* caster = GetCaster())
{
Powers powertype = Powers(GetSpellProto()->powerType);
int32 manaPerSecond = GetSpellProto()->manaPerSecond + GetSpellProto()->manaPerSecondPerLevel * caster->getLevel();
m_timeCla = 1*IN_MILLISECONDS;
if (manaPerSecond)
{
if(powertype==POWER_HEALTH)
caster->ModifyHealth(-manaPerSecond);
else
caster->ModifyPower(powertype,-manaPerSecond);
}
}
}
}
if(m_isPeriodic && (m_duration >= 0 || GetHolder()->IsPassive() || GetHolder()->IsPermanent()))
if (m_isPeriodic)
{
m_periodicTimer -= diff;
if(m_periodicTimer <= 0) // tick also at m_periodicTimer==0 to prevent lost last tick in case max m_duration == (max m_periodicTimer)*N
@ -776,8 +727,9 @@ void AreaAura::Update(uint32 diff)
addedToExisting = false;
}
holder->SetAuraDuration(GetAuraDuration());
AreaAura *aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, holder, (*tIter), caster, NULL);
aur->SetAuraDuration(GetAuraDuration());
holder->AddAura(aur, m_effIndex);
if (addedToExisting)
@ -1991,7 +1943,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
// max duration is 2 minutes, but expected to be random duration
// real time randomness is unclear, using max 30 seconds here
// see further down for expire of this aura
SetAuraDuration(rand()%30*IN_MILLISECONDS);
GetHolder()->SetAuraDuration(urand(1, 30)*IN_MILLISECONDS);
return;
}
// Gender spells
@ -4371,10 +4323,10 @@ void Aura::HandleModStealth(bool apply, bool Real)
// Overkill
else if ((*i)->GetId() == 58426 && GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000400000))
{
if (Aura* aura = target->GetAura(58427, EFFECT_INDEX_0))
if (SpellAuraHolder* holder = target->GetSpellAuraHolder(58427))
{
aura->SetAuraMaxDuration(20*IN_MILLISECONDS);
aura->GetHolder()->RefreshHolder();
holder->SetAuraMaxDuration(20*IN_MILLISECONDS);
holder->RefreshHolder();
}
}
}
@ -8174,20 +8126,6 @@ void Aura::HandleAuraModAllCritChance(bool apply, bool Real)
((Player*)target)->UpdateAllSpellCritChances();
}
void Aura::SetAuraMaxDuration(int32 duration)
{
m_maxduration = duration;
// possible overwrite persistent state
if (duration > 0)
{
if (!(GetHolder()->IsPassive() && GetSpellProto()->DurationIndex == 0))
GetHolder()->SetPermanent(false);
GetHolder()->SetAuraFlags(GetHolder()->GetAuraFlags() | AFLAG_DURATION);
}
}
bool Aura::IsLastAuraOnHolder()
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
@ -8203,9 +8141,9 @@ bool Aura::HasMechanic(uint32 mechanic) const
}
SpellAuraHolder::SpellAuraHolder(SpellEntry const* spellproto, Unit *target, WorldObject *caster, Item *castItem) :
m_target(target), m_castItemGuid(castItem ? castItem->GetObjectGuid() : ObjectGuid()),
m_spellProto(spellproto), m_target(target), m_castItemGuid(castItem ? castItem->GetObjectGuid() : ObjectGuid()),
m_auraSlot(MAX_AURAS), m_auraFlags(AFLAG_NONE), m_auraLevel(1), m_procCharges(0),
m_stackAmount(1), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE),
m_stackAmount(1), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE), m_timeCla(1000),
m_permanent(false), m_isRemovedOnShapeLost(true), m_deleted(false), m_in_use(0)
{
MANGOS_ASSERT(target);
@ -8216,29 +8154,33 @@ m_permanent(false), m_isRemovedOnShapeLost(true), m_deleted(false), m_in_use(0)
else
{
// remove this assert when not unit casters will be supported
MANGOS_ASSERT(caster->GetObjectGuid().IsUnit())
MANGOS_ASSERT(caster->isType(TYPEMASK_UNIT))
m_casterGuid = caster->GetObjectGuid();
}
m_applyTime = time(NULL);
m_spellProto = spellproto;
m_isPassive = IsPassiveSpell(GetId());
m_isDeathPersist = IsDeathPersistentSpell(m_spellProto);
m_applyTime = time(NULL);
m_isPassive = IsPassiveSpell(spellproto);
m_isDeathPersist = IsDeathPersistentSpell(spellproto);
m_isSingleTarget = IsSingleTargetSpell(spellproto);
if (GetSpellMaxDuration(m_spellProto) == -1 || (m_isPassive && m_spellProto->DurationIndex == 0))
m_permanent = true;
m_procCharges = spellproto->procCharges;
m_isRemovedOnShapeLost = (GetCasterGuid() == m_target->GetObjectGuid() &&
m_spellProto->Stances &&
!(m_spellProto->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) &&
!(m_spellProto->Attributes & SPELL_ATTR_NOT_SHAPESHIFT));
Player* modOwner = caster && caster->GetObjectGuid().IsUnit() ? ((Unit*)caster)->GetSpellModOwner() : NULL;
Unit* unitCaster = caster && caster->isType(TYPEMASK_UNIT) ? (Unit*)caster : NULL;
m_procCharges = m_spellProto->procCharges;
if(modOwner)
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
m_duration = m_maxDuration = CalculateSpellDuration(spellproto, unitCaster);
if (m_maxDuration == -1 || (m_isPassive && spellproto->DurationIndex == 0))
m_permanent = true;
if (unitCaster)
{
if (Player* modOwner = unitCaster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
}
// some custom stack values at aura holder create
switch (m_spellProto->Id)
@ -8697,23 +8639,8 @@ void SpellAuraHolder::BuildUpdatePacket(WorldPacket& data) const
if(auraFlags & AFLAG_DURATION)
{
// take highest - to display icon even if stun fades
uint32 max_duration = 0;
uint32 duration = 0;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (Aura *aura = m_auras[i])
{
if (uint32(aura->GetAuraMaxDuration()) > max_duration)
{
max_duration = aura->GetAuraMaxDuration();
duration = aura->GetAuraDuration();
}
}
}
data << uint32(max_duration);
data << uint32(duration);
data << uint32(GetAuraMaxDuration());
data << uint32(GetAuraDuration());
}
}
@ -9403,6 +9330,33 @@ SpellAuraHolder::~SpellAuraHolder()
void SpellAuraHolder::Update(uint32 diff)
{
if (m_duration > 0)
{
m_duration -= diff;
if (m_duration < 0)
m_duration = 0;
m_timeCla -= diff;
if (m_timeCla <= 0)
{
if (Unit* caster = GetCaster())
{
Powers powertype = Powers(GetSpellProto()->powerType);
int32 manaPerSecond = GetSpellProto()->manaPerSecond + GetSpellProto()->manaPerSecondPerLevel * caster->getLevel();
m_timeCla = 1*IN_MILLISECONDS;
if (manaPerSecond)
{
if (powertype == POWER_HEALTH)
caster->ModifyHealth(-manaPerSecond);
else
caster->ModifyPower(powertype, -manaPerSecond);
}
}
}
}
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (Aura *aura = m_auras[i])
aura->UpdateAura(diff);
@ -9437,13 +9391,26 @@ void SpellAuraHolder::Update(uint32 diff)
void SpellAuraHolder::RefreshHolder()
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (Aura *aura = m_auras[i])
aura->SetAuraDuration(aura->GetAuraMaxDuration());
SetAuraDuration(GetAuraMaxDuration());
SendAuraUpdate(false);
}
void SpellAuraHolder::SetAuraMaxDuration(int32 duration)
{
m_maxDuration = duration;
// possible overwrite persistent state
if (duration > 0)
{
if (!(IsPassive() && GetSpellProto()->DurationIndex == 0))
SetPermanent(false);
SetAuraFlags(GetAuraFlags() | AFLAG_DURATION);
}
else
SetAuraFlags(GetAuraFlags() & ~AFLAG_DURATION);
}
bool SpellAuraHolder::HasMechanic(uint32 mechanic) const
{
if (mechanic == m_spellProto->Mechanic)

View file

@ -108,10 +108,15 @@ class MANGOS_DLL_SPEC SpellAuraHolder
void Update(uint32 diff);
void RefreshHolder();
bool IsSingleTarget() const {return m_isSingleTarget; }
bool IsSingleTarget() const { return m_isSingleTarget; }
void SetIsSingleTarget(bool val) { m_isSingleTarget = val; }
void UnregisterSingleCastHolder();
int32 GetAuraMaxDuration() const { return m_maxDuration; }
void SetAuraMaxDuration(int32 duration);
int32 GetAuraDuration() const { return m_duration; }
void SetAuraDuration(int32 duration) { m_duration = duration; }
uint8 GetAuraSlot() const { return m_auraSlot; }
void SetAuraSlot(uint8 slot) { m_auraSlot = slot; }
uint8 GetAuraFlags() const { return m_auraFlags; }
@ -140,12 +145,14 @@ class MANGOS_DLL_SPEC SpellAuraHolder
void SetVisibleAura(bool remove) { m_target->SetVisibleAura(m_auraSlot, remove ? 0 : GetId()); }
void SetRemoveMode(AuraRemoveMode mode) { m_removeMode = mode; }
void SetLoadedState(ObjectGuid const& casterGUID, ObjectGuid const& itemGUID, uint32 stackAmount, uint32 charges)
void SetLoadedState(ObjectGuid const& casterGUID, ObjectGuid const& itemGUID, uint32 stackAmount, uint32 charges, int32 maxduration, int32 duration)
{
m_casterGuid = casterGUID;
m_casterGuid = casterGUID;
m_castItemGuid = itemGUID;
m_procCharges = charges;
m_stackAmount = stackAmount;
m_procCharges = charges;
m_stackAmount = stackAmount;
SetAuraMaxDuration(maxduration);
SetAuraDuration(duration);
}
bool HasMechanic(uint32 mechanic) const;
@ -165,6 +172,9 @@ class MANGOS_DLL_SPEC SpellAuraHolder
uint8 m_auraLevel; // Aura level (store caster level for correct show level dep amount)
uint32 m_procCharges; // Aura charges (0 for infinite)
uint32 m_stackAmount; // Aura stack amount
int32 m_maxDuration; // Max aura duration
int32 m_duration; // Current time
int32 m_timeCla; // Timer for power per sec calculation
AuraRemoveMode m_removeMode:8; // Store info for know remove aura reason
DiminishingGroup m_AuraDRGroup:8; // Diminishing
@ -380,22 +390,24 @@ class MANGOS_DLL_SPEC Aura
SpellEffectIndex GetEffIndex() const{ return m_effIndex; }
int32 GetBasePoints() const { return m_currentBasePoints; }
int32 GetAuraMaxDuration() const { return m_maxduration; }
void SetAuraMaxDuration(int32 duration);
int32 GetAuraDuration() const { return m_duration; }
void SetAuraDuration(int32 duration) { m_duration = duration; }
int32 GetAuraMaxDuration() const { return GetHolder()->GetAuraMaxDuration(); }
int32 GetAuraDuration() const { return GetHolder()->GetAuraDuration(); }
time_t GetAuraApplyTime() const { return m_applyTime; }
uint32 GetAuraTicks() const { return m_periodicTick; }
uint32 GetAuraMaxTicks() const { return m_maxduration > 0 && m_modifier.periodictime > 0 ? m_maxduration / m_modifier.periodictime : 0; }
uint32 GetAuraMaxTicks() const
{
int32 maxDuration = GetAuraMaxDuration();
return maxDuration > 0 && m_modifier.periodictime > 0 ? maxDuration / m_modifier.periodictime : 0;
}
uint32 GetStackAmount() const { return GetHolder()->GetStackAmount(); }
void SetLoadedState(int32 damage,int32 maxduration,int32 duration)
void SetLoadedState(int32 damage, uint32 periodicTime)
{
m_modifier.m_amount = damage;
SetAuraMaxDuration(maxduration);
SetAuraDuration(duration);
m_modifier.periodictime = periodicTime;
if(uint32 maxticks = GetAuraMaxTicks())
m_periodicTick = maxticks - m_duration / m_modifier.periodictime;
m_periodicTick = maxticks - GetAuraDuration() / m_modifier.periodictime;
}
bool IsPositive() { return m_positive; }
@ -458,9 +470,6 @@ class MANGOS_DLL_SPEC Aura
time_t m_applyTime;
int32 m_currentBasePoints; // cache SpellEntry::CalculateSimpleValue and use for set custom base points
int32 m_maxduration; // Max aura duration
int32 m_duration; // Current time
int32 m_timeCla; // Timer for power per sec calcultion
int32 m_periodicTimer; // Timer for periodic auras
uint32 m_periodicTick; // Tick count pass (including current if use in tick code) from aura apply, used for some tick count dependent aura effects

View file

@ -3521,7 +3521,7 @@ void Spell::EffectApplyAura(SpellEffectIndex eff_idx)
Unit* caster = GetAffectiveCaster();
if(!caster)
{
// FIXME: currently we can't have auras applied explIcitly by gameobjects
// FIXME: currently we can't have auras applied explicitly by gameobjects
// so for auras from wild gameobjects (no owner) target used
if (m_originalCasterGUID.IsGameObject())
caster = unitTarget;
@ -3531,28 +3531,8 @@ void Spell::EffectApplyAura(SpellEffectIndex eff_idx)
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[eff_idx]);
Aura* Aur = CreateAura(m_spellInfo, eff_idx, &m_currentBasePoints[eff_idx], spellAuraHolder, unitTarget, caster, m_CastItem);
// Now Reduce spell duration using data received at spell hit
int32 duration = Aur->GetAuraMaxDuration();
int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup,m_spellInfo);
unitTarget->ApplyDiminishingToDuration(m_diminishGroup, duration, m_caster, m_diminishLevel,limitduration);
spellAuraHolder->setDiminishGroup(m_diminishGroup);
// if Aura removed and deleted, do not continue.
if(duration== 0 && !(spellAuraHolder->IsPermanent()))
{
delete Aur;
return;
}
if(duration != Aur->GetAuraMaxDuration())
{
Aur->SetAuraMaxDuration(duration);
Aur->SetAuraDuration(duration);
}
spellAuraHolder->AddAura(Aur, eff_idx);
Aura* aur = CreateAura(m_spellInfo, eff_idx, &m_currentBasePoints[eff_idx], m_spellAuraHolder, unitTarget, caster, m_CastItem);
m_spellAuraHolder->AddAura(aur, eff_idx);
}
void Spell::EffectUnlearnSpecialization(SpellEffectIndex eff_idx)
@ -4383,8 +4363,8 @@ void Spell::EffectApplyAreaAura(SpellEffectIndex eff_idx)
if (!unitTarget->isAlive())
return;
AreaAura* Aur = new AreaAura(m_spellInfo, eff_idx, &m_currentBasePoints[eff_idx], spellAuraHolder, unitTarget, m_caster, m_CastItem);
spellAuraHolder->AddAura(Aur, eff_idx);
AreaAura* Aur = new AreaAura(m_spellInfo, eff_idx, &m_currentBasePoints[eff_idx], m_spellAuraHolder, unitTarget, m_caster, m_CastItem);
m_spellAuraHolder->AddAura(Aur, eff_idx);
}
void Spell::EffectSummonType(SpellEffectIndex eff_idx)
@ -4525,10 +4505,7 @@ void Spell::DoSummon(SpellEffectIndex eff_idx)
uint32 level = m_caster->getLevel();
Pet* spawnCreature = new Pet(SUMMON_PET);
int32 duration = GetSpellDuration(m_spellInfo);
if (duration > 0)
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
int32 duration = CalculateSpellDuration(m_spellInfo, m_caster);
if (m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
{
@ -4980,10 +4957,7 @@ void Spell::DoSummonGuardian(SpellEffectIndex eff_idx, uint32 forceFaction)
float center_z = m_targets.m_destZ;
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[eff_idx]));
int32 duration = GetSpellDuration(m_spellInfo);
if (duration > 0)
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
int32 duration = CalculateSpellDuration(m_spellInfo, m_caster);
int32 amount = damage > 0 ? damage : 1;
@ -7654,10 +7628,7 @@ void Spell::DoSummonTotem(SpellEffectIndex eff_idx, uint8 slot_dbc)
pTotem->SetOwner(m_caster);
pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initialized
int32 duration=GetSpellDuration(m_spellInfo);
if (duration > 0)
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
int32 duration = CalculateSpellDuration(m_spellInfo, m_caster);
pTotem->SetDuration(duration);
if (damage) // if not spell info, DB values used

View file

@ -26,6 +26,7 @@
#include "Spell.h"
#include "BattleGroundMgr.h"
#include "MapManager.h"
#include "Unit.h"
SpellMgr::SpellMgr()
{
@ -61,6 +62,29 @@ int32 GetSpellMaxDuration(SpellEntry const *spellInfo)
return (du->Duration[2] == -1) ? -1 : abs(du->Duration[2]);
}
int32 CalculateSpellDuration(SpellEntry const *spellInfo, Unit const* caster)
{
int32 duration = GetSpellDuration(spellInfo);
if (duration != -1 && caster)
{
int32 maxduration = GetSpellMaxDuration(spellInfo);
if (duration != maxduration && caster->GetTypeId() == TYPEID_PLAYER)
duration += int32((maxduration - duration) * ((Player*)caster)->GetComboPoints() / 5);
if (Player* modOwner = caster->GetSpellModOwner())
{
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration);
if (duration < 0)
duration = 0;
}
}
return duration;
}
uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
{
if (spell)
@ -847,6 +871,11 @@ bool IsPositiveSpell(uint32 spellId)
if (!spellproto)
return false;
return IsPositiveSpell(spellproto);
}
bool IsPositiveSpell(SpellEntry const *spellproto)
{
// spells with at least one negative effect are considered negative
// some self-applied spells have negative effects but in self casting case negative check ignored.
for (int i = 0; i < MAX_EFFECT_INDEX; ++i)

View file

@ -108,6 +108,7 @@ inline float GetSpellMaxRange(SpellRangeEntry const *range, bool friendly = fals
inline uint32 GetSpellRecoveryTime(SpellEntry const *spellInfo) { return spellInfo->RecoveryTime > spellInfo->CategoryRecoveryTime ? spellInfo->RecoveryTime : spellInfo->CategoryRecoveryTime; }
int32 GetSpellDuration(SpellEntry const *spellInfo);
int32 GetSpellMaxDuration(SpellEntry const *spellInfo);
int32 CalculateSpellDuration(SpellEntry const *spellInfo, Unit const* caster = NULL);
uint16 GetSpellAuraMaxTicks(SpellEntry const* spellInfo);
WeaponAttackType GetWeaponAttackType(SpellEntry const *spellInfo);
@ -240,6 +241,7 @@ inline bool IsNonCombatSpell(SpellEntry const *spellInfo)
}
bool IsPositiveSpell(uint32 spellId);
bool IsPositiveSpell(SpellEntry const *spellproto);
bool IsPositiveEffect(SpellEntry const *spellInfo, SpellEffectIndex effIndex);
bool IsPositiveTarget(uint32 targetA, uint32 targetB);
@ -463,13 +465,21 @@ inline SpellSchoolMask GetSpellSchoolMask(SpellEntry const* spellInfo)
return SpellSchoolMask(spellInfo->SchoolMask);
}
inline uint32 GetSpellMechanicMask(SpellEntry const* spellInfo, int32 effect)
inline uint32 GetSpellMechanicMask(SpellEntry const* spellInfo, uint32 effectMask)
{
uint32 mask = 0;
if (spellInfo->Mechanic)
mask |= 1 << (spellInfo->Mechanic - 1);
if (spellInfo->EffectMechanic[effect])
mask |= 1 << (spellInfo->EffectMechanic[effect] - 1);
for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (!(effectMask & (1 << i)))
continue;
if (spellInfo->EffectMechanic[i])
mask |= 1 << (spellInfo->EffectMechanic[i]-1);
}
return mask;
}

View file

@ -3489,31 +3489,11 @@ void Unit::_UpdateSpells( uint32 time )
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();)
{
SpellAuraHolder *holder = iter->second;
if (holder)
{
if (!(holder->IsPermanent() || holder->IsPassive()) )
{
bool removedAura = false;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (Aura *aura = holder->GetAuraByEffectIndex(SpellEffectIndex(i)))
{
if (!aura->GetAuraDuration())
{
RemoveSingleAuraFromSpellAuraHolder(holder, aura->GetEffIndex(), AURA_REMOVE_BY_EXPIRE);
removedAura = true;
break;
}
}
}
if (!removedAura)
++iter;
else
iter = m_spellAuraHolders.begin();
}
else
++iter;
if (!(holder->IsPermanent() || holder->IsPassive()) && holder->GetAuraDuration() == 0)
{
RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_EXPIRE);
iter = m_spellAuraHolders.begin();
}
else
++iter;
@ -4505,6 +4485,14 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit
SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
SpellAuraHolder *new_holder = CreateSpellAuraHolder(spellProto, stealer, this);
// set its duration and maximum duration
// max duration 2 minutes (in msecs)
int32 dur = holder->GetAuraDuration();
int32 max_dur = 2*MINUTE*IN_MILLISECONDS;
int32 new_max_dur = max_dur > dur ? dur : max_dur;
new_holder->SetAuraMaxDuration(new_max_dur);
new_holder->SetAuraDuration(new_max_dur);
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
Aura *aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i));
@ -4517,14 +4505,6 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit
// some different constructors
Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), &basePoints, new_holder, stealer, this);
// set its duration and maximum duration
// max duration 2 minutes (in msecs)
int32 dur = aur->GetAuraDuration();
int32 max_dur = 2*MINUTE*IN_MILLISECONDS;
int32 new_max_dur = max_dur > dur ? dur : max_dur;
new_aur->SetAuraMaxDuration( new_max_dur );
new_aur->SetAuraDuration( new_max_dur );
// set periodic to do at least one tick (for case when original aura has been at last tick preparing)
int32 periodic = aur->GetModifier()->periodictime;
new_aur->GetModifier()->periodictime = periodic < new_max_dur ? periodic : new_max_dur;
@ -4885,22 +4865,19 @@ void Unit::DelaySpellAuraHolder(uint32 spellId, int32 delaytime, uint64 casterGU
SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId);
for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second; ++iter)
{
if (casterGUID != iter->second->GetCasterGUID())
SpellAuraHolder* holder = iter->second;
if (casterGUID != holder->GetCasterGUID())
continue;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (Aura *aur = iter->second->GetAuraByEffectIndex(SpellEffectIndex(i)))
{
if (aur->GetAuraDuration() < delaytime)
aur->SetAuraDuration(0);
else
aur->SetAuraDuration(aur->GetAuraDuration() - delaytime);
if (holder->GetAuraDuration() < delaytime)
holder->SetAuraDuration(0);
else
holder->SetAuraDuration(holder->GetAuraDuration() - delaytime);
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u, EffectIndex %u partially interrupted on unit %u, new duration: %u ms",spellId, i, GetGUIDLow(), aur->GetAuraDuration());
}
}
iter->second->SendAuraUpdate(false);
holder->SendAuraUpdate(false);
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u partially interrupted on %s, new duration: %u ms", spellId, GetObjectGuid().GetString().c_str(), holder->GetAuraDuration());
}
}
@ -8729,50 +8706,45 @@ int32 Unit::CalculateSpellDamage(Unit const* target, SpellEntry const* spellProt
return value;
}
int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, SpellEffectIndex effect_index, Unit const* target)
int32 Unit::CalculateAuraDuration(SpellEntry const* spellProto, uint32 effectMask, int32 duration, Unit const* caster)
{
Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
if (duration <= 0)
return duration;
uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
int32 mechanicMod = 0;
uint32 mechanicMask = GetSpellMechanicMask(spellProto, effectMask);
int32 minduration = GetSpellDuration(spellProto);
int32 maxduration = GetSpellMaxDuration(spellProto);
int32 duration;
if( minduration != -1 && minduration != maxduration )
duration = minduration + int32((maxduration - minduration) * comboPoints / 5);
else
duration = minduration;
if (duration > 0)
for(int32 mechanic = MECHANIC_CHARM; mechanic <= MECHANIC_ENRAGED; ++mechanic)
{
int32 mechanic = GetEffectMechanic(spellProto, effect_index);
// Find total mod value (negative bonus)
int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic);
// Modify from SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL aura for negative effects (stack always ?)
if (!IsPositiveEffect(spellProto, effect_index))
durationMod_always+=target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel);
// Find max mod (negative bonus)
int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
if (!(mechanicMask & (1 << (mechanic-1))))
continue;
if (!IsPositiveSpell(spellProto->Id))
durationMod_always += target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS, spellProto->DmgClass);
int32 stackingMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic);
int32 nonStackingMod = GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
int32 durationMod = 0;
// Select strongest negative mod
if (durationMod_always > durationMod_not_stack)
durationMod = durationMod_not_stack;
else
durationMod = durationMod_always;
if (durationMod != 0)
duration = int32(int64(duration) * (100+durationMod) /100);
if (duration < 0) duration = 0;
mechanicMod = std::min(mechanicMod, std::min(stackingMod, nonStackingMod));
}
if (duration > 0 && unitPlayer && target == this)
int32 dispelMod = 0;
int32 dmgClassMod = 0;
if (!IsPositiveSpell(spellProto))
{
dispelMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel);
dmgClassMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS, spellProto->DmgClass);
}
int32 durationMod = std::min(mechanicMod, std::min(dispelMod, dmgClassMod));
if (durationMod != 0)
{
duration = int32(int64(duration) * (100+durationMod) / 100);
if (duration < 0)
duration = 0;
}
if (caster == this)
{
switch(spellProto->SpellFamilyName)
{
@ -9838,7 +9810,7 @@ SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
return SPELL_SCHOOL_MASK_NORMAL;
}
Player* Unit::GetSpellModOwner()
Player* Unit::GetSpellModOwner() const
{
if(GetTypeId()==TYPEID_PLAYER)
return (Player*)this;

View file

@ -1519,7 +1519,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
}
bool isCharmedOwnedByPlayerOrPlayer() const { return GetCharmerOrOwnerOrOwnGuid().IsPlayer(); }
Player* GetSpellModOwner();
Player* GetSpellModOwner() const;
Unit* GetOwner() const;
Pet* GetPet() const;
@ -1909,7 +1909,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 CalcNotIgnoreAbsorbDamage( uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const* spellInfo = NULL);
uint32 CalcNotIgnoreDamageRedunction( uint32 damage, SpellSchoolMask damageSchoolMask);
int32 CalculateSpellDuration(SpellEntry const* spellProto, SpellEffectIndex effect_index, Unit const* target);
int32 CalculateAuraDuration(SpellEntry const* spellProto, uint32 effectMask, int32 duration, Unit const* caster);
float CalculateLevelPenalty(SpellEntry const* spellProto) const;
void addFollower(FollowerReference* pRef) { m_FollowingRefManager.insertFirst(pRef); }

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11298"
#define REVISION_NR "11299"
#endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_11117_02_characters_world"
#define REVISION_DB_CHARACTERS "required_11299_02_characters_pet_aura"
#define REVISION_DB_MANGOS "required_11234_01_mangos_command"
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
#endif // __REVISION_SQL_H__