*Backport some contents from TC2.

--HG--
branch : trunk
This commit is contained in:
megamage
2009-04-04 20:31:29 -06:00
parent 574a9bb88e
commit 9a03bb1e5f
8 changed files with 95 additions and 505 deletions

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,12 +10,12 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
@@ -74,6 +74,8 @@ Group::~Group()
for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
itr->second.save->RemoveGroup(this);
// Sub group counters clean up
if (m_subGroupsCounts)
delete[] m_subGroupsCounts;
}
@@ -302,8 +304,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
{
bool leaderChanged = _removeMember(guid);
Player *player = objmgr.GetPlayer( guid ); // FG: TODO: could be removed, its just here for consistency
if (player)
if(Player *player = objmgr.GetPlayer( guid ))
{
WorldPacket data;
@@ -1048,6 +1049,7 @@ bool Group::_removeMember(const uint64 &guid)
if (slot != m_memberSlots.end())
{
SubGroupCounterDecrease(slot->group);
m_memberSlots.erase(slot);
}
@@ -1207,6 +1209,7 @@ void Group::ChangeMembersGroup(const uint64 &guid, const uint8 &group)
if(!isRaidGroup())
return;
Player *player = objmgr.GetPlayer(guid);
if (!player)
{
uint8 prevSubGroup;
@@ -1218,6 +1221,7 @@ void Group::ChangeMembersGroup(const uint64 &guid, const uint8 &group)
SendUpdate();
}
else
// This methods handles itself groupcounter decrease
ChangeMembersGroup(player, group);
}
@@ -1366,7 +1370,7 @@ uint32 Group::CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint
void Roll::targetObjectBuildLink()
{
// called from link()
this->getTarget()->addLootValidatorRef(this);
getTarget()->addLootValidatorRef(this);
}
void Group::SetDifficulty(uint8 difficulty)

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -124,7 +124,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_YOU_NOT_LEADER);
return;
}
// not have place
if(group->IsFull())
{
@@ -203,7 +202,8 @@ void WorldSession::HandleGroupAcceptOpcode( WorldPacket & /*recv_data*/ )
// forming a new group, create it
if(!group->IsCreated())
{
if(leader) group->RemoveInvite(leader);
if( leader )
group->RemoveInvite(leader);
group->Create(group->GetLeaderGUID(), group->GetLeaderName());
objmgr.AddGroup(group);
}
@@ -533,6 +533,7 @@ void WorldSession::HandleGroupChangeSubGroupOpcode( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data,1+1);
// we will get correct pointer for group here, so we don't have to check if group is BG raid
Group *group = GetPlayer()->GetGroup();
if(!group)
return;
@@ -725,9 +726,6 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
uint32 updatedAura=player->GetUInt32Value(uint16(UNIT_FIELD_AURA + i));
*data << uint16(updatedAura);
*data << uint8(1);
//TODO: find a safe place to do this cleanup
//if(!updatedAura)
//player->UnsetAuraUpdateMask(i);
}
}
}
@@ -810,9 +808,6 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
uint32 updatedAura=pet->GetUInt32Value(uint16(UNIT_FIELD_AURA + i));
*data << uint16(updatedAura);
*data << uint8(1);
//TODO: find a safe place to do this cleanup
//if(!updatedAura)
//pet->UnsetAuraUpdateMask(i);
}
}
}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1212,18 +1212,19 @@ void Guild::LoadGuildBankFromDB()
delete result;
// 0 1 2 3
result = CharacterDatabase.PQuery("SELECT TabId, SlotId, item_guid, item_entry FROM guild_bank_item WHERE guildid='%u' ORDER BY TabId", Id);
// data needs to be at first place for Item::LoadFromDB
// 0 1 2 3 4
result = CharacterDatabase.PQuery("SELECT data, TabId, SlotId, item_guid, item_entry FROM guild_bank_item JOIN item_instance ON item_guid = guid WHERE guildid='%u' ORDER BY TabId", Id);
if(!result)
return;
do
{
Field *fields = result->Fetch();
uint8 TabId = fields[0].GetUInt8();
uint8 SlotId = fields[1].GetUInt8();
uint32 ItemGuid = fields[2].GetUInt32();
uint32 ItemEntry = fields[3].GetUInt32();
uint8 TabId = fields[1].GetUInt8();
uint8 SlotId = fields[2].GetUInt8();
uint32 ItemGuid = fields[3].GetUInt32();
uint32 ItemEntry = fields[4].GetUInt32();
if (TabId >= purchased_tabs || TabId >= GUILD_BANK_MAX_TABS)
{
@@ -1246,7 +1247,7 @@ void Guild::LoadGuildBankFromDB()
}
Item *pItem = NewItemOrBag(proto);
if(!pItem->LoadFromDB(ItemGuid, 0))
if(!pItem->LoadFromDB(ItemGuid, 0, result))
{
CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", Id, uint32(TabId), uint32(SlotId));
sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);

View File

@@ -628,8 +628,8 @@ void Map::RelocationNotify()
if(unit->m_Notified || !unit->IsInWorld() || unit->GetMapId() != GetId())
continue;
unit->m_IsInNotifyList = false;
unit->m_Notified = true;
unit->m_IsInNotifyList = false;
if(unit->GetTypeId() == TYPEID_PLAYER)
{
@@ -1480,8 +1480,8 @@ bool Map::CheckGridIntegrity(Creature* c, bool moved) const
Cell xy_cell(xy_val);
if(xy_cell != cur_cell)
{
sLog.outDebug("ERROR: %s (GUID: %u) X: %f Y: %f (%s) in grid[%u,%u]cell[%u,%u] instead grid[%u,%u]cell[%u,%u]",
(c->GetTypeId()==TYPEID_PLAYER ? "Player" : "Creature"),c->GetGUIDLow(),
sLog.outDebug("Creature (GUIDLow: %u) X: %f Y: %f (%s) in grid[%u,%u]cell[%u,%u] instead grid[%u,%u]cell[%u,%u]",
c->GetGUIDLow(),
c->GetPositionX(),c->GetPositionY(),(moved ? "final" : "original"),
cur_cell.GridX(), cur_cell.GridY(), cur_cell.CellX(), cur_cell.CellY(),
xy_cell.GridX(), xy_cell.GridY(), xy_cell.CellX(), xy_cell.CellY());
@@ -2188,12 +2188,14 @@ void BattleGroundMap::UnloadAll()
{
while(HavePlayers())
{
Player * plr = m_mapRefManager.getFirst()->getSource();
if(plr) (plr)->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
// TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator.
// just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop
// note that this remove is not needed if the code works well in other places
plr->GetMapRef().unlink();
if(Player * plr = m_mapRefManager.getFirst()->getSource())
{
plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
// TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator.
// just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop
// note that this remove is not needed if the code works well in other places
plr->GetMapRef().unlink();
}
}
Map::UnloadAll();

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -80,8 +80,8 @@ Object::Object( )
Object::~Object( )
{
if(m_objectUpdated)
ObjectAccessor::Instance().RemoveUpdateObject(this);
//if(m_objectUpdated)
// ObjectAccessor::Instance().RemoveUpdateObject(this);
if(m_uint32Values)
{
@@ -89,9 +89,11 @@ Object::~Object( )
{
///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
sLog.outError("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
//assert(0);
assert(false);
}
assert(!m_objectUpdated);
//DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
delete [] m_uint32Values;
delete [] m_uint32Values_mirror;
@@ -146,14 +148,8 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) c
/** lower flag1 **/
if(target == this) // building packet for oneself
{
flags |= UPDATEFLAG_SELF;
/*** temporary reverted - until real source of stack corruption will not found
updatetype = UPDATETYPE_CREATE_OBJECT2;
****/
}
if(flags & UPDATEFLAG_HASPOSITION)
{
// UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
@@ -571,7 +567,6 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
if( updateMask->GetBit( index ) )
{
// remove custom flag before send
if( index == UNIT_NPC_FLAGS )
*data << uint32(m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP));
// FIXME: Some values at server stored in float format but must be sent to client in uint32 format
@@ -1046,7 +1041,7 @@ void Object::RemoveByteFlag( uint16 index, uint8 offset, uint8 oldFlag )
bool Object::PrintIndexError(uint32 index, bool set) const
{
sLog.outError("ERROR: Attempt %s non-existed value field: %u (count: %u) for object typeid: %u type mask: %u",(set ? "set value to" : "get value from"),index,m_valuesCount,GetTypeId(),m_objectType);
sLog.outError("Attempt %s non-existed value field: %u (count: %u) for object typeid: %u type mask: %u",(set ? "set value to" : "get value from"),index,m_valuesCount,GetTypeId(),m_objectType);
// assert must fail after function call
return false;
@@ -1130,7 +1125,7 @@ uint32 WorldObject::GetAreaId() const
InstanceData* WorldObject::GetInstanceData()
{
Map *map = MapManager::Instance().GetMap(m_mapId, this);
Map *map = GetMap();
return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
}
@@ -1242,6 +1237,10 @@ float WorldObject::GetAngle( const float x, const float y ) const
bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
{
// always have self in arc
if(obj == this)
return true;
float arc = arcangle;
// move arc to range 0.. 2*pi
@@ -1346,13 +1345,13 @@ void Object::ForceValuesUpdateAtIndex(uint32 i)
{
m_uint32Values_mirror[i] = GetUInt32Value(i) + 1; // makes server think the field changed
if(m_inWorld)
{
{
if(!m_objectUpdated)
{
{
ObjectAccessor::Instance().AddUpdateObject(this);
m_objectUpdated = true;
}
}
}
}
namespace Trinity
@@ -1733,18 +1732,20 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float
{
if(!IsInWorld())
return NULL;
Map * map = GetMap();
if(!map)
return NULL;
GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);
if(!goinfo)
{
sLog.outErrorDb("Gameobject template %u not found in database!", entry);
return NULL;
}
Map *map = GetMap();
GameObject *go = new GameObject();
if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry,map,x,y,z,ang,rotation0,rotation1,rotation2,rotation3,100,1))
{
delete go;
return NULL;
}
go->SetRespawnTime(respawnTime);
if(GetTypeId()==TYPEID_PLAYER || GetTypeId()==TYPEID_UNIT) //not sure how to handle this
((Unit*)this)->AddGameObject(go);

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -123,6 +123,8 @@ class TRINITY_DLL_SPEC Object
if(m_inWorld)
return;
assert(m_uint32Values);
m_inWorld = true;
// synchronize values mirror with values array (changes will send in updatecreate opcode any way
@@ -133,10 +135,10 @@ class TRINITY_DLL_SPEC Object
if(!m_inWorld)
return;
// if we remove from world then sending changes not required
if(m_uint32Values)
ClearUpdateMask(true);
m_inWorld = false;
// if we remove from world then sending changes not required
ClearUpdateMask(true);
}
const uint64& GetGUID() const { return GetUInt64Value(0); }
@@ -300,8 +302,6 @@ class TRINITY_DLL_SPEC Object
uint16 GetValuesCount() const { return m_valuesCount; }
void InitValues() { _InitValues(); }
virtual bool hasQuest(uint32 /* quest_id */) const { return false; }
virtual bool hasInvolvedQuest(uint32 /* quest_id */) const { return false; }
@@ -419,7 +419,6 @@ class TRINITY_DLL_SPEC WorldObject : public Object
void GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z ) const;
void SetMapId(uint32 newMap) { m_mapId = newMap; }
uint32 GetMapId() const { return m_mapId; }
uint32 GetZoneId() const;

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -197,9 +197,9 @@ Unit::Unit()
m_ShapeShiftFormSpellId = 0;
m_canModifyStats = false;
for (int i = 0; i < MAX_SPELL_IMMUNITY; i++)
for (int i = 0; i < MAX_SPELL_IMMUNITY; ++i)
m_spellImmune[i].clear();
for (int i = 0; i < UNIT_MOD_END; i++)
for (int i = 0; i < UNIT_MOD_END; ++i)
{
m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
@@ -214,7 +214,7 @@ Unit::Unit()
m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
}
for (int i = 0; i < MAX_STATS; i++)
for (int i = 0; i < MAX_STATS; ++i)
m_createStats[i] = 0.0f;
m_attacking = NULL;
@@ -260,6 +260,10 @@ Unit::~Unit()
RemoveAllDynObjects();
if(m_charmInfo) delete m_charmInfo;
assert(!m_attacking);
assert(m_attackers.empty());
assert(m_sharedVision.empty());
}
void Unit::Update( uint32 p_time )
@@ -1109,419 +1113,6 @@ void Unit::CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castI
spell->prepare(&targets, triggeredByAura);
}
/*
void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
{
// TODO this in only generic way, check for exceptions
DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage);
// Per-damage class calculation
switch (spellInfo->DmgClass)
{
// Melee and Ranged Spells
case SPELL_DAMAGE_CLASS_RANGED:
case SPELL_DAMAGE_CLASS_MELEE:
{
// Calculate physical outcome
MeleeHitOutcome outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo);
//Used to store the Hit Outcome
cleanDamage->hitOutCome = outcome;
// Return miss/evade first (sends miss message)
switch(outcome)
{
case MELEE_HIT_EVADE:
{
SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_EVADES,0);
*damage = 0;
return;
}
case MELEE_HIT_MISS:
{
SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_NORMAL,0);
*damage = 0;
if(GetTypeId()== TYPEID_PLAYER)
((Player*)this)->UpdateWeaponSkill(BASE_ATTACK);
CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell);
return;
}
}
// Hitinfo, Victimstate
uint32 hitInfo = HITINFO_NORMALSWING;
VictimState victimState = VICTIMSTATE_NORMAL;
// Physical Damage
if ( GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NORMAL )
{
// apply spellmod to Done damage
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DAMAGE, *damage);
//Calculate armor mitigation
uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
// random durability for main hand weapon (ABSORB)
if(damageAfterArmor < *damage)
if(pVictim->GetTypeId() == TYPEID_PLAYER)
if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB)))
((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK)));
cleanDamage->damage += *damage - damageAfterArmor;
*damage = damageAfterArmor;
}
// Magical Damage
else
{
// Calculate damage bonus
*damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE);
}
// Classify outcome
switch (outcome)
{
case MELEE_HIT_BLOCK_CRIT:
case MELEE_HIT_CRIT:
{
uint32 bonusDmg = *damage;
// Apply crit_damage bonus
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, bonusDmg);
uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
bonusDmg = uint32(bonusDmg * ((*i)->GetModifierValue()+100.0f)/100.0f);
*damage += bonusDmg;
// Resilience - reduce crit damage
if (pVictim->GetTypeId()==TYPEID_PLAYER)
{
uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage);
cleanDamage->damage += resilienceReduction;
*damage -= resilienceReduction;
}
*crit = true;
hitInfo |= HITINFO_CRITICALHIT;
ModifyAuraState(AURA_STATE_CRIT, true);
StartReactiveTimer( REACTIVE_CRIT );
if(getClass()==CLASS_HUNTER)
{
ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
StartReactiveTimer( REACTIVE_HUNTER_CRIT );
}
if ( outcome == MELEE_HIT_BLOCK_CRIT )
{
uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue());
if (blocked_amount >= *damage)
{
hitInfo |= HITINFO_SWINGNOHITSOUND;
victimState = VICTIMSTATE_BLOCKS;
cleanDamage->damage += *damage; // To Help Calculate Rage
*damage = 0;
}
else
{
// To Help Calculate Rage
cleanDamage->damage += blocked_amount;
*damage = *damage - blocked_amount;
}
pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
if(pVictim->GetTypeId() == TYPEID_PLAYER)
{
// Update defense
((Player*)pVictim)->UpdateDefense();
// random durability for main hand weapon (BLOCK)
if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
}
}
break;
}
case MELEE_HIT_PARRY:
{
cleanDamage->damage += *damage; // To Help Calculate Rage
*damage = 0;
victimState = VICTIMSTATE_PARRY;
// Counter-attack ( explained in Unit::DoAttackDamage() )
if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN) )
{
// Get attack timers
float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
// Reduce attack time
if (pVictim->haveOffhandWeapon() && offtime < basetime)
{
float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
float percent60 = 3 * percent20;
if(offtime > percent20 && offtime <= percent60)
{
pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
}
else if(offtime > percent60)
{
offtime -= 2 * percent20;
pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
}
}
else
{
float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
float percent60 = 3 * percent20;
if(basetime > percent20 && basetime <= percent60)
{
pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
}
else if(basetime > percent60)
{
basetime -= 2 * percent20;
pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
}
}
}
if(pVictim->GetTypeId() == TYPEID_PLAYER)
{
// Update victim defense ?
((Player*)pVictim)->UpdateDefense();
// random durability for main hand weapon (PARRY)
if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY)))
((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND);
}
// Set parry flags
pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
// Mongoose bite - set only Counterattack here
if (pVictim->getClass() == CLASS_HUNTER)
{
pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true);
pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY );
}
else
{
pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
}
break;
}
case MELEE_HIT_DODGE:
{
if(pVictim->GetTypeId() == TYPEID_PLAYER)
((Player*)pVictim)->UpdateDefense();
cleanDamage->damage += *damage; // To Help Calculate Rage
*damage = 0;
hitInfo |= HITINFO_SWINGNOHITSOUND;
victimState = VICTIMSTATE_DODGE;
// Set dodge flags
pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
// Overpower
if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
{
((Player*)this)->AddComboPoints(pVictim, 1);
StartReactiveTimer( REACTIVE_OVERPOWER );
}
// Riposte
if (pVictim->getClass() != CLASS_ROGUE)
{
pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
}
break;
}
case MELEE_HIT_BLOCK:
{
uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue());
if (blocked_amount >= *damage)
{
hitInfo |= HITINFO_SWINGNOHITSOUND;
victimState = VICTIMSTATE_BLOCKS;
cleanDamage->damage += *damage; // To Help Calculate Rage
*damage = 0;
}
else
{
// To Help Calculate Rage
cleanDamage->damage += blocked_amount;
*damage = *damage - blocked_amount;
}
pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
if(pVictim->GetTypeId() == TYPEID_PLAYER)
{
// Update defense
((Player*)pVictim)->UpdateDefense();
// random durability for main hand weapon (BLOCK)
if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
}
break;
}
case MELEE_HIT_EVADE: // already processed early
case MELEE_HIT_MISS: // already processed early
case MELEE_HIT_GLANCING:
case MELEE_HIT_CRUSHING:
case MELEE_HIT_NORMAL:
break;
}
// do all damage=0 cases here
if(*damage == 0)
CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,outcome,spellInfo,isTriggeredSpell);
break;
}
// Magical Attacks
case SPELL_DAMAGE_CLASS_NONE:
case SPELL_DAMAGE_CLASS_MAGIC:
{
// Calculate damage bonus
*damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE);
*crit = isSpellCrit(pVictim, spellInfo, GetSpellSchoolMask(spellInfo), BASE_ATTACK);
if (*crit)
{
*damage = SpellCriticalBonus(spellInfo, *damage, pVictim);
// Resilience - reduce crit damage
if (pVictim && pVictim->GetTypeId()==TYPEID_PLAYER)
{
uint32 damage_reduction = ((Player *)pVictim)->GetSpellCritDamageReduction(*damage);
if(*damage > damage_reduction)
*damage -= damage_reduction;
else
*damage = 0;
}
cleanDamage->hitOutCome = MELEE_HIT_CRIT;
}
// spell proc all magic damage==0 case in this function
if(*damage == 0)
{
// Procflags
uint32 procAttacker = PROC_FLAG_HIT_SPELL;
uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell);
}
break;
}
}
// TODO this in only generic way, check for exceptions
DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage);
}
uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
{
if(!this || !pVictim)
return 0;
if(!isAlive() || !pVictim->isAlive())
return 0;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
if(!spellInfo)
return 0;
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL);
bool crit = false;
if (useSpellDamage)
DealFlatDamage(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell);
// If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
if(damage > 0)
{
// Calculate absorb & resists
uint32 absorb = 0;
uint32 resist = 0;
CalcAbsorbResist(pVictim,GetSpellSchoolMask(spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
//No more damage left, target absorbed and/or resisted all damage
if (damage > absorb + resist)
damage -= absorb + resist; //Remove Absorbed and Resisted from damage actually dealt
else
{
uint32 HitInfo = HITINFO_SWINGNOHITSOUND;
if (absorb)
HitInfo |= HITINFO_ABSORB;
if (resist)
{
HitInfo |= HITINFO_RESIST;
ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, GetSpellSchoolMask(spellInfo), spellInfo,isTriggeredSpell);
}
//Send resist
SendAttackStateUpdate(HitInfo, pVictim, 1, GetSpellSchoolMask(spellInfo), damage, absorb,resist,VICTIMSTATE_NORMAL,0);
return 0;
}
// Deal damage done
damage = DealDamage(pVictim, damage, &cleanDamage, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellInfo), spellInfo, true);
// Send damage log
sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist);
// Actual log sent to client
SendSpellNonMeleeDamageLog(pVictim, spellID, damage + resist, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit);
// Procflags
uint32 procAttacker = PROC_FLAG_HIT_SPELL;
uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
if (crit)
{
procAttacker |= PROC_FLAG_CRIT_SPELL;
procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
}
ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell);
return damage;
}
else
{
// all spell proc for 0 normal and magic damage called in DealFlatDamage
//Check for rage
if(cleanDamage.damage)
// Rage from damage received.
if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false);
return 0;
}
}
*/
// Obsolete func need remove, here only for comotability vs another patches
uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
{
@@ -11255,11 +10846,6 @@ uint32 Unit::GetCreatePowers( Powers power ) const
return 0;
}
void Unit::AddToWorld()
{
WorldObject::AddToWorld();
}
void Unit::RemoveFromWorld()
{
// cleanup
@@ -11274,20 +10860,23 @@ void Unit::RemoveFromWorld()
void Unit::CleanupsBeforeDelete()
{
if(m_uint32Values) // only for fully created object
{
RemoveAllAuras();
InterruptNonMeleeSpells(true);
m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
CombatStop();
ClearComboPointHolders();
DeleteThreatList();
getHostilRefManager().setOnlineOfflineState(false);
RemoveAllGameObjects();
RemoveAllDynObjects();
GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
}
RemoveFromWorld();
assert(m_uint32Values);
//A unit may be in removelist and not in world, but it is still in grid
//and may have some references during delete
RemoveAllAuras();
InterruptNonMeleeSpells(true);
m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
CombatStop();
ClearComboPointHolders();
DeleteThreatList();
getHostilRefManager().setOnlineOfflineState(false);
RemoveAllGameObjects();
RemoveAllDynObjects();
GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
if(IsInWorld())
RemoveFromWorld();
}
void Unit::UpdateCharmAI()

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,12 +22,11 @@
\ingroup u2w
*/
#include "WorldSocket.h"
#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "Log.h"
#include "Opcodes.h"
#include "WorldSocket.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Player.h"
@@ -374,7 +373,7 @@ void WorldSession::LogoutPlayer(bool Save)
// the player may not be in the world when logging out
// e.g if he got disconnected during a transfer to another map
// calls to GetMap in this case may cause crashes
if(_player->IsInWorld()) MapManager::Instance().GetMap(_player->GetMapId(), _player)->Remove(_player, false);
if(_player->IsInWorld()) _player->GetMap()->Remove(_player, false);
// RemoveFromWorld does cleanup that requires the player to be in the accessor
ObjectAccessor::Instance().RemoveObject(_player);