Core/GameObject: Refactored destructible building handling, properly implemented spell effect repair

This commit is contained in:
Shauren
2011-07-22 21:22:05 +02:00
parent 0a4f18fab3
commit 74e2d981ac
15 changed files with 387 additions and 359 deletions
@@ -205,6 +205,9 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
SetEntry(goinfo->entry);
// set name for logs usage, doesn't affect anything ingame
SetName(goinfo->name);
SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId);
// GAMEOBJECT_BYTES_1, index at 0, 1, 2 and 3
@@ -214,10 +217,11 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
SetGoArtKit(0); // unknown what this is
SetByteValue(GAMEOBJECT_BYTES_1, 2, artKit);
switch(goinfo->type)
switch (goinfo->type)
{
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
m_goValue->building.health = goinfo->building.intactNumHits + goinfo->building.damagedNumHits;
m_goValue->Building.Health = goinfo->building.intactNumHits + goinfo->building.damagedNumHits;
m_goValue->Building.MaxHealth = goinfo->building.intactNumHits + goinfo->building.damagedNumHits;
SetGoAnimProgress(255);
break;
case GAMEOBJECT_TYPE_TRANSPORT:
@@ -1676,88 +1680,6 @@ bool GameObject::IsInRange(float x, float y, float z, float radius) const
&& dz < info->maxZ + radius && dz > info->minZ - radius;
}
void GameObject::TakenDamage(uint32 damage, Unit *who)
{
if (!m_goValue->building.health)
return;
Player* pwho = NULL;
if (who)
{
if (who->GetTypeId() == TYPEID_PLAYER)
pwho = who->ToPlayer();
else if (who->IsVehicle() && who->GetCharmerOrOwner())
pwho = who->GetCharmerOrOwner()->ToPlayer();
}
if (m_goValue->building.health > damage)
m_goValue->building.health -= damage;
else
m_goValue->building.health = 0;
if (HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED)) // from damaged to destroyed
{
if (!m_goValue->building.health)
{
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
uint32 modelId = m_goInfo->building.destroyedDisplayId;
if (DestructibleModelDataEntry const* modelData = sDestructibleModelDataStore.LookupEntry(m_goInfo->building.destructibleData))
if (modelData->DestroyedDisplayId)
modelId = modelData->DestroyedDisplayId;
SetUInt32Value(GAMEOBJECT_DISPLAYID, modelId);
EventInform(m_goInfo->building.destroyedEvent);
if (pwho)
if (Battleground* bg = pwho->GetBattleground())
{
bg->EventPlayerDamagedGO(pwho, this, m_goInfo->building.destroyedEvent);
bg->DestroyGate(pwho, this, m_goInfo->building.destroyedEvent);
}
sScriptMgr->OnGameObjectDestroyed(this, pwho, m_goInfo->building.destroyedEvent);
}
}
else // from intact to damaged
{
if (m_goValue->building.health + damage >= m_goInfo->building.intactNumHits + m_goInfo->building.damagedNumHits)
if (pwho)
if (Battleground* bg = pwho->GetBattleground())
bg->EventPlayerDamagedGO(pwho, this, m_goInfo->building.damageEvent);
if (m_goValue->building.health <= m_goInfo->building.damagedNumHits)
{
if (!m_goInfo->building.destroyedDisplayId)
m_goValue->building.health = m_goInfo->building.damagedNumHits;
else if (!m_goValue->building.health)
m_goValue->building.health = 1;
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
uint32 modelId = m_goInfo->building.damagedDisplayId;
if (DestructibleModelDataEntry const* modelData = sDestructibleModelDataStore.LookupEntry(m_goInfo->building.destructibleData))
if (modelData->DamagedDisplayId)
modelId = modelData->DamagedDisplayId;
SetUInt32Value(GAMEOBJECT_DISPLAYID, modelId);
EventInform(m_goInfo->building.damagedEvent);
sScriptMgr->OnGameObjectDamaged(this, pwho, m_goInfo->building.damagedEvent);
if (pwho)
if (Battleground* bg = pwho->GetBattleground())
bg->EventPlayerDamagedGO(pwho, this, m_goInfo->building.damagedEvent);
}
}
SetGoAnimProgress(m_goValue->building.health*255/(m_goInfo->building.intactNumHits + m_goInfo->building.damagedNumHits));
}
void GameObject::Rebuild()
{
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_DESTROYED);
SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->displayId);
m_goValue->building.health = m_goInfo->building.intactNumHits + m_goInfo->building.damagedNumHits;
EventInform(m_goInfo->building.rebuildingEvent);
}
void GameObject::EventInform(uint32 eventId)
{
if (eventId && m_zoneScript)
@@ -1807,3 +1729,125 @@ void GameObject::UpdateRotationFields(float rotation2 /*=0.0f*/, float rotation3
SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rotation2);
SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rotation3);
}
void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, uint32 spellId /*= 0*/)
{
if (!GetGOValue()->Building.MaxHealth || !change)
return;
if (int32(GetGOValue()->Building.Health) + change <= 0)
GetGOValue()->Building.Health = 0;
else if (int32(GetGOValue()->Building.Health) + change >= int32(GetGOValue()->Building.MaxHealth))
GetGOValue()->Building.Health = GetGOValue()->Building.MaxHealth;
else
GetGOValue()->Building.Health += change;
SetGoAnimProgress(GetGOValue()->Building.Health * 255 / GetGOValue()->Building.MaxHealth);
Player* player = attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself();
// dealing damage, send packet
// TODO: is there any packet for healing?
if (change < 0 && player)
{
WorldPacket data(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, 8 + 8 + 8 + 4 + 4);
data.appendPackGUID(GetGUID());
data.appendPackGUID(attackerOrHealer->GetGUID());
data.appendPackGUID(player->GetGUID());
data << uint32(-change);
data << uint32(spellId);
player->GetSession()->SendPacket(&data);
}
if (!GetGOValue()->Building.Health)
SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED, player, false);
else if (GetGOValue()->Building.Health <= GetGOInfo()->building.damagedNumHits)
SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED, player, false);
}
void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker /*= NULL*/, bool setHealth /*= false*/)
{
// the user calling this must know he is already operating on destructible gameobject
ASSERT(GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING);
switch (state)
{
case GO_DESTRUCTIBLE_INTACT:
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_DESTROYED);
SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->displayId);
if (setHealth)
{
m_goValue->Building.Health = m_goValue->Building.MaxHealth;
SetGoAnimProgress(255);
}
break;
case GO_DESTRUCTIBLE_DAMAGED:
{
EventInform(m_goInfo->building.damagedEvent);
sScriptMgr->OnGameObjectDamaged(this, eventInvoker);
if (eventInvoker)
if (Battleground* bg = eventInvoker->GetBattleground())
bg->EventPlayerDamagedGO(eventInvoker, this, m_goInfo->building.damagedEvent);
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
uint32 modelId = m_goInfo->building.damagedDisplayId;
if (DestructibleModelDataEntry const* modelData = sDestructibleModelDataStore.LookupEntry(m_goInfo->building.destructibleData))
if (modelData->DamagedDisplayId)
modelId = modelData->DamagedDisplayId;
SetUInt32Value(GAMEOBJECT_DISPLAYID, modelId);
if (setHealth)
{
m_goValue->Building.Health = m_goInfo->building.damagedNumHits;
uint32 maxHealth = m_goValue->Building.MaxHealth;
// in this case current health is 0 anyway so just prevent crashing here
if (!maxHealth)
maxHealth = 1;
SetGoAnimProgress(m_goValue->Building.Health * 255 / maxHealth);
}
break;
}
case GO_DESTRUCTIBLE_DESTROYED:
{
sScriptMgr->OnGameObjectDestroyed(this, eventInvoker);
EventInform(m_goInfo->building.destroyedEvent);
if (eventInvoker)
{
if (Battleground* bg = eventInvoker->GetBattleground())
{
bg->EventPlayerDamagedGO(eventInvoker, this, m_goInfo->building.destroyedEvent);
bg->DestroyGate(eventInvoker, this);
}
}
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
uint32 modelId = m_goInfo->building.destroyedDisplayId;
if (DestructibleModelDataEntry const* modelData = sDestructibleModelDataStore.LookupEntry(m_goInfo->building.destructibleData))
if (modelData->DestroyedDisplayId)
modelId = modelData->DestroyedDisplayId;
SetUInt32Value(GAMEOBJECT_DISPLAYID, modelId);
if (setHealth)
{
m_goValue->Building.Health = 0;
SetGoAnimProgress(0);
}
break;
}
case GO_DESTRUCTIBLE_REBUILDING:
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_DESTROYED);
SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->displayId);
EventInform(m_goInfo->building.rebuildingEvent);
// restores to full health
if (setHealth)
{
m_goValue->Building.Health = m_goValue->Building.MaxHealth;
SetGoAnimProgress(255);
}
break;
}
}
@@ -541,12 +541,13 @@ union GameObjectValue
struct
{
OPvPCapturePoint *OPvPObj;
}capturePoint;
} CapturePoint;
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
struct
{
uint32 health;
}building;
uint32 Health;
uint32 MaxHealth;
} Building;
};
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
@@ -767,8 +768,10 @@ class GameObject : public WorldObject, public GridObject<GameObject>
void CastSpell(Unit* target, uint32 spell);
void SendCustomAnim(uint32 anim);
bool IsInRange(float x, float y, float z, float radius) const;
void TakenDamage(uint32 damage, Unit* who = NULL);
void Rebuild();
void ModifyHealth(int32 change, Unit* attackerOrHealer = NULL, uint32 spellId = 0);
// sets GameObject type 33 destruction flags and optionally default health for that state
void SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker = NULL, bool setHealth = false);
void EventInform(uint32 eventId);