Merge remote branch 'origin/master' into 330

This commit is contained in:
tomrus88 2009-12-16 02:45:05 +03:00
commit c745c5072f
31 changed files with 1000 additions and 760 deletions

View file

@ -348,7 +348,8 @@ enum SummonPropType
SUMMON_PROP_TYPE_PHASING = 8, // something todo with DK prequest line, 2 spells in 3.0.3 "%s's Opponent"
SUMMON_PROP_TYPE_SIEGE_VEH = 9, // summon different vehicles, 14 spells in 3.0.3 "%s's Vehicle"
SUMMON_PROP_TYPE_DRAKE_VEH = 10, // summon drake (vehicle), 3 spells
SUMMON_PROP_TYPE_LIGHTWELL = 11 // summon lightwell, 6 spells in 3.0.3
SUMMON_PROP_TYPE_LIGHTWELL = 11, // summon lightwell, 6 spells in 3.0.3
SUMMON_PROP_TYPE_REPAIR_BOT = 12 // summon repir bot, 1 spells in 3.2.2a
};
// SummonProperties.dbc, col 5

View file

@ -70,7 +70,7 @@ enum GossipOptionIcon
//POI icons. Many more exist, list not complete.
enum Poi_Icon
{
ICON_POI_BLANK = 0, // Blank (not visible)
ICON_POI_BLANK = 0, // Blank (not visible), in 2.4.3 have value 15 with 1..15 values in 0..14 range
ICON_POI_GREY_AV_MINE = 1, // Grey mine lorry
ICON_POI_RED_AV_MINE = 2, // Red mine lorry
ICON_POI_BLUE_AV_MINE = 3, // Blue mine lorry

View file

@ -1026,9 +1026,12 @@ void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & recv_data )
*/
}
void WorldSession::HandleFeatherFallAck(WorldPacket &/*recv_data*/)
void WorldSession::HandleFeatherFallAck(WorldPacket &recv_data)
{
DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
// no used
recv_data.rpos(recv_data.wpos()); // prevent warnings spam
}
void WorldSession::HandleMoveUnRootAck(WorldPacket& recv_data)

View file

@ -248,8 +248,8 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
{
// transports size limited
// (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
if( movementInfo.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50 )
// (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
if( movementInfo.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 100 )
{
recv_data.rpos(recv_data.wpos()); // prevent warnings spam
return;

View file

@ -667,6 +667,12 @@ void Object::BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask *
if (!((Creature*)this)->isCanTrainingOf(target, false))
appendValue &= ~(UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS | UNIT_NPC_FLAG_TRAINER_PROFESSION);
}
if (appendValue & UNIT_NPC_FLAG_STABLEMASTER)
{
if (target->getClass() != CLASS_HUNTER)
appendValue &= ~UNIT_NPC_FLAG_STABLEMASTER;
}
}
*data << uint32(appendValue);

View file

@ -7315,6 +7315,10 @@ bool PlayerCondition::Meets(Player const * player) const
}
return false;
}
case CONDITION_RACE_CLASS:
if ((!value1 || (player->getRaceMask() & value1)) && (!value2 || (player->getClassMask() & value2)))
return true;
return false;
default:
return false;
}
@ -7468,6 +7472,27 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val
}
break;
}
case CONDITION_RACE_CLASS:
{
if (!value1 && !value2)
{
sLog.outErrorDb("Race_class condition has both values like 0, skipped");
return false;
}
if (value1 && !(value1 & RACEMASK_ALL_PLAYABLE))
{
sLog.outErrorDb("Race_class condition has invalid player class %u, skipped", value1);
return false;
}
if (value2 && !(value2 & CLASSMASK_ALL_PLAYABLE))
{
sLog.outErrorDb("Race_class condition has invalid race mask %u, skipped", value2);
return false;
}
break;
}
case CONDITION_NONE:
break;
}

View file

@ -319,11 +319,12 @@ enum ConditionType
CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active.
CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD commission aura active
CONDITION_NO_AURA = 11, // spell_id effindex
CONDITION_ACTIVE_EVENT = 12, // event_id
CONDITION_AREA_FLAG = 13 // area_flag area_flag_not
CONDITION_ACTIVE_EVENT = 12, // event_id 0
CONDITION_AREA_FLAG = 13, // area_flag area_flag_not
CONDITION_RACE_CLASS = 14, // race_mask class_mask
};
#define MAX_CONDITION 14 // maximum value in ConditionType enum
#define MAX_CONDITION 15 // maximum value in ConditionType enum
struct PlayerCondition
{

View file

@ -414,8 +414,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
<< curmana << ", "
<< GetPower(POWER_HAPPINESS) << ", '";
// save only spell slots from action bar
for(uint32 i = ACTION_BAR_INDEX_PET_SPELL_START; i < ACTION_BAR_INDEX_PET_SPELL_END; ++i)
for(uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i)
{
ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << " "
<< uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << " ";

View file

@ -324,23 +324,59 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
}
count = (recv_data.size() == 24) ? 2 : 1;
uint32 position[2];
uint32 data[2];
bool move_command = false;
for(uint8 i = 0; i < count; ++i)
{
uint32 position;
uint32 data;
recv_data >> position[i];
recv_data >> data[i];
recv_data >> position;
recv_data >> data;
uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data);
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data);
sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, uint32(act_state));
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]);
//ignore invalid position
if(position >= MAX_UNIT_ACTION_BAR_INDEX)
if(position[i] >= MAX_UNIT_ACTION_BAR_INDEX)
return;
// in the normal case, command and reaction buttons can only be moved, not removed
// at moving count ==2, at removing count == 1
// ignore attempt to remove command|reaction buttons (not possible at normal case)
if (act_state == ACT_COMMAND || act_state == ACT_REACTION)
{
if (count == 1)
return;
move_command = true;
}
}
// check swap
if (move_command)
{
uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]);
uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]);
UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]);
if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() ||
act_state_0 != actionEntry_1->GetType())
return;
uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]);
uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]);
UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]);
if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() ||
act_state_1 != actionEntry_0->GetType())
return;
}
for(uint8 i = 0; i < count; ++i)
{
uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]);
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]);
sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position[i], spell_id, uint32(act_state));
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id)))
{
@ -361,7 +397,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
((Pet*)pet)->ToggleAutocast(spell_id, false);
}
charmInfo->SetActionBar(position,spell_id,ActiveStates(act_state));
charmInfo->SetActionBar(position[i],spell_id,ActiveStates(act_state));
}
}
}

View file

@ -2088,6 +2088,12 @@ Creature* Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask)
if (npcflagmask && !unit->HasFlag( UNIT_NPC_FLAGS, npcflagmask ))
return NULL;
if (npcflagmask == UNIT_NPC_FLAG_STABLEMASTER)
{
if (getClass() != CLASS_HUNTER)
return NULL;
}
// if a dead unit should be able to talk - the creature must be alive and have special flags
if (!unit->isAlive())
return NULL;
@ -5008,8 +5014,8 @@ void Player::SetRegularAttackTime()
{
for(int i = 0; i < MAX_ATTACK; ++i)
{
Item *tmpitem = GetWeaponForAttack(WeaponAttackType(i));
if(tmpitem && !tmpitem->IsBroken())
Item *tmpitem = GetWeaponForAttack(WeaponAttackType(i),true,false);
if (tmpitem)
{
ItemPrototype const *proto = tmpitem->GetProto();
if(proto->Delay)
@ -5215,7 +5221,7 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType)
{
case BASE_ATTACK:
{
Item *tmpitem = GetWeaponForAttack(attType,true);
Item *tmpitem = GetWeaponForAttack(attType,true,true);
if (!tmpitem)
UpdateSkill(SKILL_UNARMED,weapon_skill_gain);
@ -5226,7 +5232,7 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType)
case OFF_ATTACK:
case RANGED_ATTACK:
{
Item *tmpitem = GetWeaponForAttack(attType,true);
Item *tmpitem = GetWeaponForAttack(attType,true,true);
if (tmpitem)
UpdateSkill(tmpitem->GetSkill(),weapon_skill_gain);
break;
@ -7034,8 +7040,8 @@ void Player::UpdateEquipSpellsAtFormChange()
void Player::CastItemCombatSpell(Unit* Target, WeaponAttackType attType)
{
Item *item = GetWeaponForAttack(attType, false);
if(!item || item->IsBroken())
Item *item = GetWeaponForAttack(attType, true, false);
if(!item)
return;
ItemPrototype const *proto = item->GetProto();
@ -7355,8 +7361,8 @@ bool Player::CheckAmmoCompatibility(const ItemPrototype *ammo_proto) const
return false;
// check ranged weapon
Item *weapon = GetWeaponForAttack( RANGED_ATTACK );
if(!weapon || weapon->IsBroken() )
Item *weapon = GetWeaponForAttack( RANGED_ATTACK, true, false );
if (!weapon)
return false;
ItemPrototype const* weapon_proto = weapon->GetProto();
@ -8173,14 +8179,14 @@ void Player::SetSheath( SheathState sheathed )
break;
case SHEATH_STATE_MELEE: // prepared melee weapon
{
SetVirtualItemSlot(0,GetWeaponForAttack(BASE_ATTACK,true));
SetVirtualItemSlot(1,GetWeaponForAttack(OFF_ATTACK,true));
SetVirtualItemSlot(0,GetWeaponForAttack(BASE_ATTACK,true,true));
SetVirtualItemSlot(1,GetWeaponForAttack(OFF_ATTACK,true,true));
SetVirtualItemSlot(2,NULL);
}; break;
case SHEATH_STATE_RANGED: // prepared ranged weapon
SetVirtualItemSlot(0,NULL);
SetVirtualItemSlot(1,NULL);
SetVirtualItemSlot(2,GetWeaponForAttack(RANGED_ATTACK,true));
SetVirtualItemSlot(2,GetWeaponForAttack(RANGED_ATTACK,true,true));
break;
default:
SetVirtualItemSlot(0,NULL);
@ -8551,7 +8557,7 @@ Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const
return NULL;
}
Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable) const
Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool nonbroken, bool useable) const
{
uint16 slot;
switch (attackType)
@ -8566,10 +8572,10 @@ Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable) cons
if (!item || item->GetProto()->Class != ITEM_CLASS_WEAPON)
return NULL;
if(!useable)
return item;
if (useable && !IsUseEquipedWeapon(attackType==BASE_ATTACK))
return NULL;
if( item->IsBroken() || !IsUseEquipedWeapon(attackType==BASE_ATTACK) )
if (nonbroken && item->IsBroken())
return NULL;
return item;
@ -12491,7 +12497,7 @@ void Player::OnGossipSelect(WorldObject* pSource, uint32 gossipListId, uint32 me
uint32 Player::GetGossipTextId(WorldObject *pSource)
{
if (!pSource || pSource->GetTypeId() != TYPEID_UNIT || !((Creature*)pSource)->GetDBTableGUIDLow())
return 0;
return DEFAULT_GOSSIP_MESSAGE;
if (uint32 pos = sObjectMgr.GetNpcGossip(((Creature*)pSource)->GetDBTableGUIDLow()))
return pos;
@ -19638,7 +19644,7 @@ bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
{
Item* item = GetWeaponForAttack(attType,true);
Item* item = GetWeaponForAttack(attType,true,true);
// unarmed only with base attack
if(attType != BASE_ATTACK && !item)

View file

@ -1163,7 +1163,8 @@ class MANGOS_DLL_SPEC Player : public Unit
Item* GetItemByGuid( uint64 guid ) const;
Item* GetItemByPos( uint16 pos ) const;
Item* GetItemByPos( uint8 bag, uint8 slot ) const;
Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const;
Item* GetWeaponForAttack(WeaponAttackType attackType) const { return GetWeaponForAttack(attackType,false,false); }
Item* GetWeaponForAttack(WeaponAttackType attackType, bool nonbroken, bool useable) const;
Item* GetShield(bool useable = false) const;
static uint32 GetAttackBySlot( uint8 slot ); // MAX_ATTACK if not weapon slot
std::vector<Item *> &GetItemUpdateQueue() { return m_itemUpdateQueue; }

View file

@ -686,6 +686,9 @@ void Spell::prepareDataForTriggerSystem()
// Clearcasting trigger need do it
else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000200000000) && m_spellInfo->SpellFamilyFlags2 & 0x8)
m_canTrigger = true;
// Replenish Mana, item spell with triggered cases (Mana Agate, etc mana gems)
else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000010000000000))
m_canTrigger = true;
break;
case SPELLFAMILY_WARLOCK: // For Hellfire Effect / Rain of Fire / Seed of Corruption triggers need do it
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000800000000060))
@ -2417,11 +2420,10 @@ void Spell::cancel()
{
Unit* unit = m_caster->GetGUID()==(*ihit).targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
if( unit && unit->isAlive() )
unit->RemoveAurasDueToSpell(m_spellInfo->Id);
unit->RemoveAurasByCasterSpell(m_spellInfo->Id,m_caster->GetGUID());
}
}
m_caster->RemoveAurasDueToSpell(m_spellInfo->Id);
SendChannelUpdate(0);
SendInterrupted(0);
SendCastResult(SPELL_FAILED_INTERRUPTED);
@ -3441,6 +3443,13 @@ void Spell::SendChannelUpdate(uint32 time)
{
if(time == 0)
{
m_caster->RemoveAurasByCasterSpell(m_spellInfo->Id,m_caster->GetGUID());
if(uint64 target_guid = m_caster->GetChannelObjectGUID())
if(target_guid != m_caster->GetGUID() && IS_UNIT_GUID(target_guid))
if(Unit* target = ObjectAccessor::GetUnit(*m_caster, target_guid))
target->RemoveAurasByCasterSpell(m_spellInfo->Id,m_caster->GetGUID());
m_caster->SetChannelObjectGUID(0);
m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, 0);
}
@ -5563,8 +5572,8 @@ SpellCastResult Spell::CheckItems()
if(m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_TARGET_NOT_PLAYER;
if( m_attackType != RANGED_ATTACK )
break;
Item *pItem = ((Player*)m_caster)->GetWeaponForAttack(m_attackType);
if(!pItem || pItem->IsBroken())
Item *pItem = ((Player*)m_caster)->GetWeaponForAttack(m_attackType,true,false);
if (!pItem)
return SPELL_FAILED_EQUIPPED_ITEM;
switch(pItem->GetProto()->SubClass)

View file

@ -628,27 +628,20 @@ void Aura::Update(uint32 diff)
return;
}
// Get spell range
float radius;
SpellModOp mod;
if (m_spellProto->EffectRadiusIndex[GetEffIndex()])
// need check distance for channeled target only
if (caster->GetChannelObjectGUID() == m_target->GetGUID())
{
radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellProto->EffectRadiusIndex[GetEffIndex()]));
mod = SPELLMOD_RADIUS;
}
else
{
radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
mod = SPELLMOD_RANGE;
}
// Get spell range
float max_range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
if(Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), mod, radius, NULL);
if(Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_RANGE, max_range, NULL);
if(!caster->IsWithinDistInMap(m_target, radius))
{
m_target->RemoveAura(GetId(), GetEffIndex());
return;
if(!caster->IsWithinDistInMap(m_target, max_range))
{
m_target->RemoveAura(GetId(), GetEffIndex());
return;
}
}
}
@ -1331,7 +1324,7 @@ bool Aura::isAffectedOnSpell(SpellEntry const *spell) const
return false;
}
void Aura::ReapplyAffectedPassiveAuras( Unit* target )
void Aura::ReapplyAffectedPassiveAuras( Unit* target, bool owner_mode )
{
std::set<uint32> affectedSelf;
std::set<uint32> affectedAuraCaster;
@ -1339,16 +1332,17 @@ void Aura::ReapplyAffectedPassiveAuras( Unit* target )
for(Unit::AuraMap::const_iterator itr = target->GetAuras().begin(); itr != target->GetAuras().end(); ++itr)
{
// permanent passive or permanent area aura
if (itr->second->IsPermanent() && (itr->second->IsPassive() || itr->second->IsAreaAura()) &&
// passive spells can be affected only by own or owner spell mods)
if (itr->second->IsPermanent() && (owner_mode && itr->second->IsPassive() || itr->second->IsAreaAura()) &&
// non deleted and not same aura (any with same spell id)
!itr->second->IsDeleted() && itr->second->GetId() != GetId() &&
// and affected by aura
isAffectedOnSpell(itr->second->GetSpellProto()))
{
// only applied by self or aura caster
if(itr->second->GetCasterGUID() == target->GetGUID())
if (itr->second->GetCasterGUID() == target->GetGUID())
affectedSelf.insert(itr->second->GetId());
else if(itr->second->GetCasterGUID() == GetCasterGUID())
else if (itr->second->GetCasterGUID() == GetCasterGUID())
affectedAuraCaster.insert(itr->second->GetId());
}
}
@ -1429,25 +1423,26 @@ void Aura::HandleAddModifier(bool apply, bool Real)
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
// reapply talents to own passive persistent auras
ReapplyAffectedPassiveAuras(m_target);
ReapplyAffectedPassiveAuras(m_target, true);
// re-apply talents/passives/area auras applied to pet (it affected by player spellmods)
if(Pet* pet = m_target->GetPet())
ReapplyAffectedPassiveAuras(pet);
ReapplyAffectedPassiveAuras(pet, true);
// re-apply talents/passives/area auras applied to totems (it affected by player spellmods)
for(int i = 0; i < MAX_TOTEM; ++i)
if(m_target->m_TotemSlot[i])
if(Creature* totem = m_target->GetMap()->GetCreature(m_target->m_TotemSlot[i]))
ReapplyAffectedPassiveAuras(totem);
ReapplyAffectedPassiveAuras(totem, true);
// re-apply talents/passives/area auras applied to group members (it affected by player spellmods)
if (Group* group = ((Player*)m_target)->GetGroup())
for(GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
if (Player* member = itr->getSource())
if (member != m_target && member->IsInMap(m_target))
ReapplyAffectedPassiveAuras(member);
ReapplyAffectedPassiveAuras(member, false);
}
void Aura::HandleAddTargetTrigger(bool apply, bool /*Real*/)
{
// Use SpellModifier structure for check
@ -5295,7 +5290,7 @@ void Aura::HandleAuraModCritPercent(bool apply, bool Real)
if(Real)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i),true,false))
((Player*)m_target)->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply);
}
@ -5495,7 +5490,7 @@ void Aura::HandleModDamageDone(bool apply, bool Real)
if(Real && m_target->GetTypeId() == TYPEID_PLAYER)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i),true,false))
((Player*)m_target)->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
}
@ -5578,7 +5573,7 @@ void Aura::HandleModDamagePercentDone(bool apply, bool Real)
if(Real && m_target->GetTypeId() == TYPEID_PLAYER)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i),true,false))
((Player*)m_target)->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
}
@ -5897,7 +5892,7 @@ void Aura::HandleShapeshiftBoosts(bool apply)
void Aura::HandleSpellSpecificBoosts(bool apply)
{
bool cast_at_remove = false; // if spell must be casted at aura remove
bool cast_at_remove = false; // if spell must be casted at last aura from stack remove
uint32 spellId1 = 0;
uint32 spellId2 = 0;
uint32 spellId3 = 0;
@ -5905,9 +5900,21 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
// Illusionary Barrier
if(GetId() == 57350 && !apply && m_target->getPowerType() == POWER_MANA)
{
cast_at_remove = true;
spellId1 = 60242; // Darkmoon Card: Illusion
}
else
return;
break;
}
case SPELLFAMILY_MAGE:
{
// Ice Barrier
// Ice Barrier (non stacking from one caster)
if (m_spellProto->SpellIconID == 32)
{
if (!apply && (m_removeMode == AURA_REMOVE_BY_DISPEL || (m_removeMode == AURA_REMOVE_BY_DEFAULT && !GetModifier()->m_amount)))
@ -5954,7 +5961,7 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
break;
}
case SPELLFAMILY_WARLOCK:
// Fear
// Fear (non stacking)
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000040000000000))
{
if(!apply)
@ -6632,7 +6639,11 @@ void Aura::PeriodicTick()
// send critical in hit info for threat calculation
if (isCrit)
{
cleanDamage.hitOutCome = MELEE_HIT_CRIT;
// Resilience - reduce crit damage
pdamage -= m_target->GetSpellCritDamageReduction(pdamage);
}
// only from players
// FIXME: need use SpellDamageBonus instead?

View file

@ -352,7 +352,7 @@ class MANGOS_DLL_SPEC Aura
void PeriodicDummyTick();
bool IsCritFromAbilityAura(Unit* caster, uint32& damage);
void ReapplyAffectedPassiveAuras(Unit* target);
void ReapplyAffectedPassiveAuras(Unit* target, bool owner_mode);
Modifier m_modifier;
SpellModifier *m_spellmod;

View file

@ -2223,10 +2223,10 @@ void Spell::EffectTriggerSpell(uint32 effIndex)
// main hand weapon required
if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
{
Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK, true, false);
// skip spell if no weapon in slot or broken
if (!item || item->IsBroken() )
if (!item)
return;
// skip spell if weapon not fit to triggered spell
@ -2237,10 +2237,10 @@ void Spell::EffectTriggerSpell(uint32 effIndex)
// offhand hand weapon required
if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
{
Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK, true, false);
// skip spell if no weapon in slot or broken
if (!item || item->IsBroken() )
if (!item)
return;
// skip spell if weapon not fit to triggered spell
@ -3442,6 +3442,7 @@ void Spell::EffectSummonType(uint32 i)
break;
}
case SUMMON_PROP_TYPE_CRITTER:
case SUMMON_PROP_TYPE_REPAIR_BOT:
{
EffectSummonCritter(i, summon_prop->FactionId);
break;
@ -4586,7 +4587,7 @@ void Spell::EffectWeaponDmg(uint32 i)
// Whirlwind, single only spell with 2 weapon white damage apply if have
if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x00000400000000)))
{
if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK, true, true))
spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
}
// Devastate bonus and sunder armor refresh
@ -4646,7 +4647,7 @@ void Spell::EffectWeaponDmg(uint32 i)
// Fan of Knives
else if (m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0004000000000000)))
{
Item* weapon = ((Player*)m_caster)->GetWeaponForAttack(m_attackType,true);
Item* weapon = ((Player*)m_caster)->GetWeaponForAttack(m_attackType,true,true);
if (weapon && weapon->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
totalDamagePercentMod *= 1.5f; // 150% to daggers
}
@ -4821,13 +4822,13 @@ void Spell::EffectWeaponDmg(uint32 i)
// take ammo
if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
{
Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
Item *pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK, true, false);
// wands don't have ammo
if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
if (!pItem || pItem->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
return;
if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
if (pItem->GetProto()->InventoryType == INVTYPE_THROWN)
{
if(pItem->GetMaxStackCount()==1)
{

View file

@ -483,7 +483,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
break;
}
} break;
case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from bas point sign (negative -> negative)
case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from base point sign (negative -> negative)
case SPELL_AURA_MOD_STAT:
case SPELL_AURA_MOD_SKILL:
case SPELL_AURA_MOD_HEALING_PCT:
@ -496,8 +496,10 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
return false;
break;
case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
case SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT:
case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
if(spellproto->CalculateSimpleValue(effIndex) > 0)
return true; // some expected positive spells have SPELL_ATTR_EX_NEGATIVE
return true; // some expected positive spells have SPELL_ATTR_EX_NEGATIVE or unclear target modes
break;
case SPELL_AURA_ADD_TARGET_TRIGGER:
return true;
@ -573,6 +575,8 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
// some spells negative
switch(spellproto->Id)
{
case 802: // Mutate Bug, wrongly negative by target modes
return true;
case 36900: // Soul Split: Evil!
case 36901: // Soul Split: Good
case 36893: // Transporter Malfunction (decrease size case)

File diff suppressed because it is too large Load diff

View file

@ -1247,7 +1247,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void RemoveAurasByCasterSpell(uint32 spellId, uint32 effindex, uint64 casterGUID);
void RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer);
void RemoveAurasDueToSpellByCancel(uint32 spellId);
void RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo);
// removing unknown aura stacks by diff reasons and selections
void RemoveNotOwnSingleTargetAuras(uint32 newPhase = 0x0);
@ -1618,6 +1617,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 m_lastManaUseTimer;
private:
void CleanupDeletedAuars();
bool IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent );
bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);

View file

@ -45,18 +45,20 @@ alter table creature_movement add `wpguid` int(11) default '0';
//-----------------------------------------------//
void WaypointMovementGenerator<Creature>::LoadPath(Creature &c)
{
sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow());
sLog.outDetail("LoadPath: loading waypoint path for creature %u, %u", c.GetGUIDLow(), c.GetDBTableGUIDLow());
i_path = sWaypointMgr.GetPath(c.GetDBTableGUIDLow());
if(!i_path)
if (!i_path)
{
sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %d) doesn't have waypoint path",
sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path",
c.GetName(), c.GetEntry(), c.GetDBTableGUIDLow());
return;
}
uint32 node_count = i_path->size();
i_hasDone.resize(node_count);
for(uint32 i = 0; i < node_count-1; ++i)
i_hasDone[i] = false;
@ -78,22 +80,23 @@ void WaypointMovementGenerator<Creature>::Initialize()
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
if(!&creature)
if (!&creature)
return true;
// Waypoint movement can be switched on/off
// This is quite handy for escort quests and other stuff
if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED | UNIT_STAT_DIED))
if (creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED | UNIT_STAT_DIED))
return true;
// prevent a crash at empty waypoint path.
if(!i_path || i_path->empty())
if (!i_path || i_path->empty())
return true;
// i_path was modified by chat commands for example
if(i_path->size() != i_hasDone.size())
if (i_path->size() != i_hasDone.size())
i_hasDone.resize(i_path->size());
if(i_currentNode >= i_path->size())
if (i_currentNode >= i_path->size())
i_currentNode = 0;
CreatureTraveller traveller(creature);
@ -104,56 +107,67 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
// creature has been stopped in middle of the waypoint segment
if (!i_destinationHolder.HasArrived() && creature.IsStopped())
{
if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it
// Timer has elapsed, meaning this part controlled it
if (i_nextMoveTime.Passed())
{
SetStoppedByPlayer(false);
// Now we re-set destination to same node and start travel
creature.addUnitState(UNIT_STAT_ROAMING);
if (creature.canFly())
creature.AddMonsterMoveFlag(MONSTER_MOVE_FLY);
// Now we re-set destination to same node and start travel
const WaypointNode &node = i_path->at(i_currentNode);
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
}
else // if( !i_nextMoveTime.Passed())
{ // unexpected end of timer && creature stopped && not at end of segment
{
// unexpected end of timer && creature stopped && not at end of segment
if (!IsStoppedByPlayer())
{ // Put 30 seconds delay
{
// Put 30 seconds delay
i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
SetStoppedByPlayer(true); // Mark we did it
SetStoppedByPlayer(true); // Mark we did it
}
}
return true; // Abort here this update
return true; // Abort here this update
}
if( creature.IsStopped())
if (creature.IsStopped())
{
uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
if (!i_hasDone[idx])
{
if (i_path->at(idx).orientation !=100)
if (i_path->at(idx).orientation != 100)
creature.SetOrientation(i_path->at(idx).orientation);
if(WaypointBehavior *behavior = i_path->at(idx).behavior)
if (WaypointBehavior *behavior = i_path->at(idx).behavior)
{
if(behavior->emote != 0)
creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote);
if(behavior->spell != 0)
creature.CastSpell(&creature,behavior->spell, false);
if(behavior->model1 != 0)
if (behavior->emote != 0)
creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, behavior->emote);
if (behavior->spell != 0)
creature.CastSpell(&creature, behavior->spell, false);
if (behavior->model1 != 0)
creature.SetDisplayId(behavior->model1);
if(behavior->textid[0])
if (behavior->textid[0])
{
// Not only one text is set
if( behavior->textid[1] )
if (behavior->textid[1])
{
// Select one from max 5 texts (0 and 1 laready checked)
// Select one from max 5 texts (0 and 1 already checked)
int i = 2;
for( ; i < MAX_WAYPOINT_TEXT; ++i )
if( !behavior->textid[i] )
for(; i < MAX_WAYPOINT_TEXT; ++i)
{
if (!behavior->textid[i])
break;
}
creature.Say(behavior->textid[rand() % i], 0, 0);
}
@ -167,37 +181,46 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
} // HasDone == false
} // i_creature.IsStopped()
if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player
// This is at the end of waypoint segment or has been stopped by player
if (i_nextMoveTime.Passed())
{
if( creature.IsStopped() ) // If stopped then begin a new move segment
// If stopped then begin a new move segment
if (creature.IsStopped())
{
creature.addUnitState(UNIT_STAT_ROAMING);
if (creature.canFly())
creature.AddMonsterMoveFlag(MONSTER_MOVE_FLY);
const WaypointNode &node = i_path->at(i_currentNode);
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
if (i_path->at(idx).orientation !=100)
if (i_path->at(idx).orientation != 100)
creature.SetOrientation(i_path->at(idx).orientation);
if(WaypointBehavior *behavior = i_path->at(idx).behavior )
if (WaypointBehavior *behavior = i_path->at(idx).behavior)
{
i_hasDone[idx] = false;
if(behavior->model2 != 0)
if (behavior->model2 != 0)
creature.SetDisplayId(behavior->model2);
creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
}
}
else // If not stopped then stop it and set the reset of TimeTracker to waittime
else
{
// If not stopped then stop it and set the reset of TimeTracker to waittime
creature.StopMoving();
SetStoppedByPlayer(false);
i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
++i_currentNode;
if( i_currentNode >= i_path->size() )
if (i_currentNode >= i_path->size())
i_currentNode = 0;
}
}
@ -206,7 +229,7 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
{
if(unit.AI())
if (unit.AI())
unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
}