[c12553] Correct DestructibleModelDataEntry and fix ingame destructible go display

This commit is contained in:
Dramacydal 2013-04-18 17:18:37 +04:00 committed by Antz
parent 456de16b5e
commit 2be2854ff2
4 changed files with 323 additions and 116 deletions

View file

@ -396,7 +396,6 @@ struct AchievementCriteriaEntry
uint32 goldInCopper; // 4
} quest_reward_money;
// ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67
struct
{
@ -535,7 +534,7 @@ struct AreaTableEntry
int32 area_level; // 10 m_ExplorationLevel
DBCString area_name; // 11 m_AreaName_lang
uint32 team; // 12 m_factionGroupMask
// 13-16 m_liquidTypeID[4]
uint32 LiquidTypeOverride[4]; // 13-16 m_liquidTypeID[4]
// 17 m_minElevation
// 18 m_ambient_multiplier
// 19 m_lightid
@ -685,9 +684,9 @@ struct ChrClassesEntry
//uint32 flags2; // 8 m_flags (0x08 HasRelicSlot)
uint32 CinematicSequence; // 9 m_cinematicSequenceID
uint32 expansion; // 10 m_required_expansion
//uint32 // 11
//uint32 // 12
//uint32 // 13
uint32 apPerStr; // 11 attack power per strength
uint32 apPerAgi; // 12 attack power per agility
uint32 rapPerAgi; // 13 ranged attack power per agility
};
struct ChrRacesEntry
@ -833,6 +832,34 @@ struct CurrencyTypesEntry
float GetPrecision() const { return HasPrecision() ? CURRENCY_PRECISION : 1.0f; }
};
struct DestructibleModelDataEntry
{
uint32 m_ID; // 0 m_ID
uint32 intactDisplayId; // 1
// uint32 unk2; // 2
// uint32 unk3; // 3
// uint32 unk4; // 4
uint32 damagedDisplayId; // 5
// uint32 unk6; // 6
// uint32 unk7; // 7
// uint32 unk8; // 8
// uint32 unk9; // 9
uint32 destroyedDisplayId; // 10
// uint32 unk11; // 11
// uint32 unk12; // 12
// uint32 unk13; // 13
// uint32 unk14; // 14
uint32 rebuildingDisplayId; // 15
// uint32 unk16; // 16
// uint32 unk17; // 17
// uint32 unk18; // 18
// uint32 unk19; // 19
//uint32 smokeDisplayId; // 20
// uint32 unk21; // 21
// uint32 unk22; // 22
// uint32 unk23; // 23
};
struct DungeonEncounterEntry
{
uint32 Id; // 0 m_ID
@ -961,15 +988,15 @@ struct FactionTemplateEntry
struct GameObjectDisplayInfoEntry
{
uint32 Displayid; // 0 m_ID
//DBCString filename; // 1
//uint32 unk1[10]; // 2-11
float minX; // 1
float minY; // 13
float minZ; // 14
float maxX; // 15
float maxY; // 16
float maxZ; // 17
uint32 Displayid; // 0 m_ID
char* filename; // 1 m_modelName
// uint32 unknown2[10]; // 2-11 m_Sound
float geoBoxMinX; // 12 m_geoBoxMinX (use first value as interact dist, mostly in hacks way)
float geoBoxMinY; // 13 m_geoBoxMinY
float geoBoxMinZ; // 14 m_geoBoxMinZ
float geoBoxMaxX; // 15 m_geoBoxMaxX
float geoBoxMaxY; // 16 m_geoBoxMaxY
float geoBoxMaxZ; // 17 m_geoBoxMaxZ
//uint32 transport; // 18
//uint32 unk; // 19
//uint32 unk1; // 20
@ -1249,6 +1276,29 @@ struct ItemSetEntry
m_target_level_max
};*/
struct LiquidTypeEntry
{
uint32 Id; // 0
//char* Name; // 1
//uint32 Flags; // 2 Water: 1|2|4|8, Magma: 8|16|32|64, Slime: 2|64|256, WMO Ocean: 1|2|4|8|512
uint32 Type; // 3 0: Water, 1: Ocean, 2: Magma, 3: Slime
//uint32 SoundId; // 4 Reference to SoundEntries.dbc
uint32 SpellId; // 5 Reference to Spell.dbc
//float MaxDarkenDepth; // 6 Only oceans got values here!
//float FogDarkenIntensity; // 7 Only oceans got values here!
//float AmbDarkenIntensity; // 8 Only oceans got values here!
//float DirDarkenIntensity; // 9 Only oceans got values here!
//uint32 LightID; // 10 Only Slime (6) and Magma (7)
//float ParticleScale; // 11 0: Slime, 1: Water/Ocean, 4: Magma
//uint32 ParticleMovement; // 12
//uint32 ParticleTexSlots; // 13
//uint32 LiquidMaterialID; // 14
//char* Texture[6]; // 15-20
//uint32 Color[2]; // 21-22
//float Unk1[18]; // 23-40 Most likely these are attributes for the shaders. Water: (23, TextureTilesPerBlock),(24, Rotation) Magma: (23, AnimationX),(24, AnimationY)
//uint32 Unk2[4]; // 41-44
};
#define MAX_LOCK_CASE 8
struct LockEntry
@ -1496,13 +1546,6 @@ struct ScalingStatValuesEntry
return spellBonus;
return 0;
}
uint32 getFeralBonus(uint32 mask) const // removed in 3.2.x?
{
if (mask & 0x00010000) // not used?
return 0;
return 0;
}
};
/*struct SkillLineCategoryEntry{
@ -1732,7 +1775,7 @@ struct SpellEffectEntry
int32 EffectMiscValueB; // 118-120 m_effectMiscValueB
float EffectPointsPerComboPoint; // 124-126 m_effectPointsPerCombo
uint32 EffectRadiusIndex; // 94-96 m_effectRadiusIndex - spellradius.dbc
//uint32 EffectRadiusMaxIndex; // 97-99 4.0.0
uint32 EffectRadiusMaxIndex; // 97-99 4.0.0
float EffectRealPointsPerLevel; // 79-81 m_effectRealPointsPerLevel
ClassFamilyMask EffectSpellClassMask; // 127-129 m_effectSpellClassMask
uint32 EffectTriggerSpell; // 121-123 m_effectTriggerSpell
@ -1745,6 +1788,14 @@ struct SpellEffectEntry
// helpers
int32 CalculateSimpleValue() const { return EffectBasePoints; }
uint32 GetRadiusIndex() const
{
if (EffectRadiusIndex != 0)
return EffectRadiusIndex;
return EffectRadiusMaxIndex;
}
};
// SpellEquippedItems.dbc
@ -1800,16 +1851,18 @@ struct SpellReagentsEntry
// SpellScaling.dbc
struct SpellScalingEntry
{
//uint32 Id; // 0 m_ID
uint32 castTimeMin; // 1
uint32 castTimeMax; // 2
uint32 castScalingMaxLevel; // 3
//uint32 Id; // 0 m_ID
int32 castTimeMin; // 1
int32 castTimeMax; // 2
int32 castScalingMaxLevel; // 3
int32 playerClass; // 4 (index * 100) + charLevel => gtSpellScaling.dbc
float coeff1[3]; // 5-7
float coeff2[3]; // 8-10
float coeff3[3]; // 11-13
float unkMult; // 14 some coefficient, mostly 1.0f
uint32 unkLevel; // 15 some level
float coefBase; // 14 some coefficient, mostly 1.0f
int32 coefLevelBase; // 15 some level
bool IsScalableEffect(SpellEffectIndex i) const { return coeff1[i] != 0.0f; };
};
// SpellShapeshift.dbc

View file

@ -21,7 +21,7 @@
const char Achievementfmt[]="niiissiiiiisii";
const char AchievementCriteriafmt[]="niiiiiiiixsiiiiixxxxxxx";
const char AreaTableEntryfmt[]="iiinixxxxxisixxxxxxxxxxxxx";
const char AreaTableEntryfmt[]="iiinixxxxxisiiiiixxxxxxxxx";
const char AreaGroupEntryfmt[]="niiiiiii";
const char AreaTriggerEntryfmt[]="nifffxxxfffff";
const char ArmorLocationfmt[]="nfffff";
@ -33,7 +33,7 @@ const char CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxx
const char CharTitlesEntryfmt[]="nxsxix";
const char ChatChannelsEntryfmt[]="iixsx";
// ChatChannelsEntryfmt, index not used (more compact store)
const char ChrClassesEntryfmt[]="nixsxxxixiixxx";
const char ChrClassesEntryfmt[]="nixsxxxixiiiii";
const char ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx";
const char ChrClassesXPowerTypesfmt[]="nii";
const char CinematicSequencesEntryfmt[]="nxxxxxxxxx";
@ -41,6 +41,7 @@ const char CreatureDisplayInfofmt[]="nxxifxxxxxxxxxxxx";
const char CreatureDisplayInfoExtrafmt[]="nixxxxxxxxxxxxxxxxxxx";
const char CreatureFamilyfmt[]="nfifiiiiixsx";
const char CreatureSpellDatafmt[]="niiiixxxx";
const char DestructibleModelDataFmt[] = "nixxxixxxxixxxxixxxxxxxx";
const char DungeonEncounterfmt[]="niiiisxx";
const char CreatureTypefmt[]="nxx";
const char CurrencyTypesfmt[]="nisxxxxiiix";
@ -50,7 +51,7 @@ const char EmotesEntryfmt[]="nxxiiixx";
const char EmotesTextEntryfmt[]="nxixxxxxxxxxxxxxxxx";
const char FactionEntryfmt[]="niiiiiiiiiiiiiiiiiiffixsxx";
const char FactionTemplateEntryfmt[]="niiiiiiiiiiiii";
const char GameObjectDisplayInfofmt[]="nxxxxxxxxxxxffffffxxx";
const char GameObjectDisplayInfofmt[]="nsxxxxxxxxxxffffffxxx";
const char GemPropertiesEntryfmt[]="nixxix";
const char GlyphPropertiesfmt[]="niii";
const char GlyphSlotfmt[]="nii";
@ -81,6 +82,7 @@ const char ItemLimitCategoryEntryfmt[]="nxii";
const char ItemRandomPropertiesfmt[]="nxiiiiis";
const char ItemRandomSuffixfmt[]="nsxiiiiiiiiii";
const char ItemSetEntryfmt[]="dsxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii";
const char LiquidTypefmt[] = "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
const char MailTemplateEntryfmt[]="nxs";
const char MapEntryfmt[]="nsiiiisissififfiiiii";
@ -110,7 +112,7 @@ const char SpellCastingRequirementsEntryfmt[]="dixxixi";
const char SpellCategoriesEntryfmt[]="diiiiii";
const char SpellClassOptionsEntryfmt[]="dxiiiix";
const char SpellCooldownsEntryfmt[]="diii";
const char SpellEffectEntryfmt[]="difiiixfiiiiiifixfiiiiiiiix";
const char SpellEffectEntryfmt[]="difiiixfiiiiiifiifiiiiiiiix";
const char SpellEquippedItemsEntryfmt[]="diii";
const char SpellInterruptsEntryfmt[]="dixixi";
const char SpellLevelsEntryfmt[]="diii";

View file

@ -39,10 +39,13 @@
#include "OutdoorPvP/OutdoorPvP.h"
#include "Util.h"
#include "ScriptMgr.h"
#include "vmap/GameObjectModel.h"
#include "SQLStorages.h"
#include <G3D/Quat.h>
GameObject::GameObject() : WorldObject(),
loot(this),
m_model(NULL),
m_goInfo(NULL),
m_displayInfo(NULL)
{
@ -54,7 +57,7 @@ GameObject::GameObject() : WorldObject(),
m_valuesCount = GAMEOBJECT_END;
m_respawnTime = 0;
m_respawnDelayTime = 25;
m_lootState = GO_NOT_READY;
m_lootState = GO_READY;
m_spawnedByDefault = true;
m_useTimes = 0;
m_spellId = 0;
@ -70,6 +73,7 @@ GameObject::GameObject() : WorldObject(),
GameObject::~GameObject()
{
delete m_model;
}
void GameObject::AddToWorld()
@ -78,7 +82,13 @@ void GameObject::AddToWorld()
if (!IsInWorld())
GetMap()->GetObjectsStore().insert<GameObject>(GetObjectGuid(), (GameObject*)this);
if (m_model)
GetMap()->InsertGameObjectModel(*m_model);
Object::AddToWorld();
// After Object::AddToWorld so that for initial state the GO is added to the world (and hence handled correctly)
UpdateCollisionState();
}
void GameObject::RemoveFromWorld()
@ -102,6 +112,9 @@ void GameObject::RemoveFromWorld()
}
}
if (m_model && GetMap()->ContainsGameObjectModel(*m_model))
GetMap()->RemoveGameObjectModel(*m_model);
GetMap()->GetObjectsStore().erase<GameObject>(GetObjectGuid(), (GameObject*)NULL);
}
@ -162,6 +175,18 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
SetGoArtKit(0); // unknown what this is
SetGoAnimProgress(animprogress);
switch (GetGoType())
{
case GAMEOBJECT_TYPE_TRAP:
case GAMEOBJECT_TYPE_FISHINGNODE:
m_lootState = GO_NOT_READY; // Initialize Traps and Fishingnode delayed in ::Update
break;
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
ForceGameObjectHealth(GetMaxHealth(), NULL);
SetUInt32Value(GAMEOBJECT_PARENTROTATION, m_goInfo->destructibleBuilding.destructibleData);
break;
}
// Notify the battleground or outdoor pvp script
if (map->IsBattleGroundOrArena())
((BattleGroundMap*)map)->GetBG()->HandleGameObjectCreate(this);
@ -191,16 +216,16 @@ void GameObject::Update(uint32 update_diff, uint32 p_time)
{
switch (GetGoType())
{
case GAMEOBJECT_TYPE_TRAP:
case GAMEOBJECT_TYPE_TRAP: // Initialized delayed to be able to use GetOwner()
{
// Arming Time for GAMEOBJECT_TYPE_TRAP (6)
Unit* owner = GetOwner();
if (owner && ((Player*)owner)->isInCombat())
if (owner && owner->isInCombat())
m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay;
m_lootState = GO_READY;
break;
}
case GAMEOBJECT_TYPE_FISHINGNODE:
case GAMEOBJECT_TYPE_FISHINGNODE: // Keep not ready for some delay
{
// fishing code (bobber ready)
if (time(NULL) > m_respawnTime - FISHING_BOBBER_READY_TIME)
@ -219,13 +244,10 @@ void GameObject::Update(uint32 update_diff, uint32 p_time)
m_lootState = GO_READY; // can be successfully open with some chance
}
return;
}
default:
m_lootState = GO_READY; // for other GO is same switched without delay to GO_READY
break;
}
}
// NO BREAK for switch (m_lootState)
break;
}
case GO_READY:
{
@ -305,32 +327,17 @@ void GameObject::Update(uint32 update_diff, uint32 p_time)
}
}
// Note: this hack with search required until GO casting not implemented
// search unfriendly creature
if (owner && goInfo->trap.charges > 0) // hunter trap
{
MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, owner, radius);
MaNGOS::UnitSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck> checker(ok, u_check);
Cell::VisitGridObjects(this, checker, radius);
if (!ok)
Cell::VisitWorldObjects(this, checker, radius);
}
else // environmental trap
{
// environmental damage spells already have around enemies targeting but this not help in case nonexistent GO casting support
// affect only players
Player* p_ok = NULL;
MaNGOS::AnyPlayerInObjectRangeCheck p_check(this, radius);
MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> checker(p_ok, p_check);
Cell::VisitWorldObjects(this, checker, radius);
ok = p_ok;
}
// Should trap trigger?
MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, radius);
MaNGOS::UnitSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck> checker(ok, u_check);
Cell::VisitAllObjects(this, checker, radius);
if (ok)
{
Unit* caster = owner ? owner : ok;
// Code below should be refactored into GO::Use, but not clear how to handle caster/victim for non AoE spells
caster->CastSpell(ok, goInfo->trap.spellId, true, NULL, NULL, GetObjectGuid());
// use template cooldown if provided
m_cooldownTime = time(NULL) + (goInfo->trap.cooldown ? goInfo->trap.cooldown : uint32(4));
@ -506,7 +513,6 @@ void GameObject::AddUniqueUse(Player* player)
m_firstUser = player->GetObjectGuid();
m_UniqueUsers.insert(player->GetObjectGuid());
}
void GameObject::Delete()
@ -522,19 +528,6 @@ void GameObject::Delete()
AddObjectToRemoveList();
}
void GameObject::getFishLoot(Loot* fishloot, Player* loot_owner)
{
fishloot->clear();
uint32 zone, subzone;
GetZoneAndAreaId(zone, subzone);
// if subzone loot exist use it
if (!fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, (subzone != zone)) && subzone != zone)
// else use zone loot (if zone diff. from subzone, must exist in like case)
fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true);
}
void GameObject::SaveToDB()
{
// this should only be used when the gameobject has already been loaded
@ -672,7 +665,6 @@ struct GameObjectRespawnDeleteWorker
uint32 i_guid;
};
void GameObject::DeleteFromDB()
{
if (!HasStaticDBSpawnData())
@ -938,6 +930,23 @@ GameObject* GameObject::LookupFishingHoleAround(float range)
return ok;
}
bool GameObject::IsCollisionEnabled() const
{
if (!isSpawned())
return false;
// TODO: Possible that this function must consider multiple checks
switch (GetGoType())
{
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
return GetGoState() != GO_STATE_ACTIVE && GetGoState() != GO_STATE_ACTIVE_ALTERNATIVE;
default:
return true;
}
}
void GameObject::ResetDoorOrButton()
{
if (m_lootState == GO_READY || m_lootState == GO_JUST_DEACTIVATED)
@ -1048,10 +1057,8 @@ void GameObject::Use(Unit* user)
// TODO: possible must be moved to loot release (in different from linked triggering)
if (GetGOInfo()->chest.eventId)
{
DEBUG_LOG("Chest ScriptStart id %u for GO %u", GetGOInfo()->chest.eventId, GetGUIDLow());
if (!sScriptMgr.OnProcessEvent(GetGOInfo()->chest.eventId, user, this, true))
GetMap()->ScriptsStart(sEventScripts, GetGOInfo()->chest.eventId, user, this);
DEBUG_LOG("Chest ScriptStart id %u for %s (opened by %s)", GetGOInfo()->chest.eventId, GetGuidStr().c_str(), user->GetGuidStr().c_str());
StartEvents_Event(GetMap(), GetGOInfo()->chest.eventId, user, this);
}
return;
@ -1200,10 +1207,8 @@ void GameObject::Use(Unit* user)
if (info->goober.eventId)
{
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Goober ScriptStart id %u for GO entry %u (GUID %u).", info->goober.eventId, GetEntry(), GetGUIDLow());
if (!sScriptMgr.OnProcessEvent(info->goober.eventId, player, this, true))
GetMap()->ScriptsStart(sEventScripts, info->goober.eventId, player, this);
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Goober ScriptStart id %u for %s (Used by %s).", info->goober.eventId, GetGuidStr().c_str(), player->GetGuidStr().c_str());
StartEvents_Event(GetMap(), info->goober.eventId, player, this);
}
// possible quest objective for active quests
@ -1250,10 +1255,7 @@ void GameObject::Use(Unit* user)
player->SendCinematicStart(info->camera.cinematicId);
if (info->camera.eventID)
{
if (!sScriptMgr.OnProcessEvent(info->camera.eventID, player, this, true))
GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this);
}
StartEvents_Event(GetMap(), info->camera.eventID, player, this);
return;
}
@ -1711,9 +1713,9 @@ bool GameObject::IsHostileTo(Unit const* unit) const
if (Unit const* targetOwner = unit->GetCharmerOrOwner())
return IsHostileTo(targetOwner);
// for not set faction case (wild object) use hostile case
// for not set faction case: be hostile towards player, not hostile towards not-players
if (!GetGOInfo()->faction)
return true;
return unit->IsControlledByPlayer();
// faction base cases
FactionTemplateEntry const* tester_faction = sFactionTemplateStore.LookupEntry(GetGOInfo()->faction);
@ -1784,10 +1786,48 @@ bool GameObject::IsFriendlyTo(Unit const* unit) const
return tester_faction->IsFriendlyTo(*target_faction);
}
void GameObject::SetLootState(LootState state)
{
m_lootState = state;
UpdateCollisionState();
}
void GameObject::SetGoState(GOState state)
{
SetByteValue(GAMEOBJECT_BYTES_1, 0, state);
UpdateCollisionState();
}
void GameObject::SetDisplayId(uint32 modelId)
{
SetUInt32Value(GAMEOBJECT_DISPLAYID, modelId);
m_displayInfo = sGameObjectDisplayInfoStore.LookupEntry(modelId);
UpdateModel();
}
void GameObject::SetPhaseMask(uint32 newPhaseMask, bool update)
{
WorldObject::SetPhaseMask(newPhaseMask, update);
UpdateCollisionState();
}
void GameObject::UpdateCollisionState() const
{
if (!m_model || !IsInWorld())
return;
m_model->enable(IsCollisionEnabled() ? GetPhaseMask() : 0);
}
void GameObject::UpdateModel()
{
if (m_model && IsInWorld() && GetMap()->ContainsGameObjectModel(*m_model))
GetMap()->RemoveGameObjectModel(*m_model);
delete m_model;
m_model = GameObjectModel::construct(this);
if (m_model)
GetMap()->InsertGameObjectModel(*m_model);
}
void GameObject::StartGroupLoot(Group* group, uint32 timer)
@ -1872,11 +1912,14 @@ void GameObject::SetLootRecipient(Unit* pUnit)
float GameObject::GetObjectBoundingRadius() const
{
// FIXME:
// 1. This is clearly hack way because GameObjectDisplayInfoEntry have 6 floats related to GO sizes, but better that use DEFAULT_WORLD_OBJECT_SIZE
// 2. In some cases this must be only interactive size, not GO size, current way can affect creature target point auto-selection in strange ways for big underground/virtual GOs
/*if (m_displayInfo)
return fabs(m_displayInfo->unknown12) * GetObjectScale();*/
if (m_displayInfo)
{
float dx = m_displayInfo->geoBoxMaxX - m_displayInfo->geoBoxMinX;
float dy = m_displayInfo->geoBoxMaxY - m_displayInfo->geoBoxMinY;
float dz = m_displayInfo->geoBoxMaxZ - m_displayInfo->geoBoxMinZ;
return (std::abs(dx) + std::abs(dy) + std::abs(dz)) / 2 * GetObjectScale();
}
return DEFAULT_WORLD_OBJECT_SIZE;
}
@ -2150,23 +2193,132 @@ void GameObject::TickCapturePoint()
}
if (eventId)
{
// Notify the battleground or outdoor pvp script
if (BattleGround* bg = (*capturingPlayers.begin())->GetBattleGround())
{
// Allow only certain events to be handled by other script engines
if (bg->HandleEvent(eventId, this))
return;
}
else if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript((*capturingPlayers.begin())->GetCachedZoneId()))
{
// Allow only certain events to be handled by other script engines
if (outdoorPvP->HandleEvent(eventId, this))
return;
}
// Send script event to SD2 and database as well - this can be used for summoning creatures, casting specific spells or spawning GOs
if (!sScriptMgr.OnProcessEvent(eventId, this, this, true))
GetMap()->ScriptsStart(sEventScripts, eventId, this, this);
}
StartEvents_Event(GetMap(), eventId, this, this, true, *capturingPlayers.begin());
}
// ////////////////////////////////////////////////////////////////////////////////////////////////
// Destructible GO handling
// ////////////////////////////////////////////////////////////////////////////////////////////////
void GameObject::DealGameObjectDamage(uint32 damage, uint32 spell, Unit* caster)
{
MANGOS_ASSERT(GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING);
MANGOS_ASSERT(spell && sSpellStore.LookupEntry(spell) && caster);
if (!damage)
return;
ForceGameObjectHealth(-int32(damage), caster);
WorldPacket data(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, 9+9+9+4+4);
data << GetPackGUID();
data << caster->GetPackGUID();
data << caster->GetCharmerOrOwnerOrSelf()->GetPackGUID();
data << uint32(damage);
data << uint32(spell);
SendMessageToSet(&data, false);
}
void GameObject::RebuildGameObject(uint32 spell, Unit* caster)
{
MANGOS_ASSERT(GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING);
MANGOS_ASSERT(caster);
ForceGameObjectHealth(0, caster);
}
void GameObject::ForceGameObjectHealth(int32 diff, Unit* caster)
{
MANGOS_ASSERT(GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING);
MANGOS_ASSERT(caster || diff >= 0);
if (diff < 0) // Taken damage
{
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DestructibleGO: %s taken damage %u dealt by %s", GetGuidStr().c_str(), uint32(-diff), caster->GetGuidStr().c_str());
if (m_useTimes > uint32(-diff))
m_useTimes += diff;
else
m_useTimes = 0;
}
else if (diff == 0 && GetMaxHealth()) // Rebuild - TODO: Rebuilding over time with special display-id?
{
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DestructibleGO: %s start rebuild by %s", GetGuidStr().c_str(), caster->GetGuidStr().c_str());
m_useTimes = GetMaxHealth();
// Start Event if exist
if (caster && m_goInfo->destructibleBuilding.rebuildingEvent)
StartEvents_Event(GetMap(), m_goInfo->destructibleBuilding.rebuildingEvent, this, caster->GetCharmerOrOwnerOrSelf(), true, caster->GetCharmerOrOwnerOrSelf());
}
else // Set to value
m_useTimes = uint32(diff);
uint32 newDisplayId = 0xFFFFFFFF; // Set to invalid -1 to track if we switched to a change state
DestructibleModelDataEntry const* destructibleInfo = sDestructibleModelDataStore.LookupEntry(m_goInfo->destructibleBuilding.destructibleData);
// Get Current State - Note about order: Important for GetMaxHealth() == 0
if (m_useTimes == GetMaxHealth()) // Full Health
{
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DestructibleGO: %s set to full health %u", GetGuidStr().c_str(), m_useTimes);
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_9 | GO_FLAG_UNK_10 | GO_FLAG_UNK_11);
newDisplayId = m_goInfo->displayId;
// Start Event if exist
if (caster && m_goInfo->destructibleBuilding.intactEvent)
StartEvents_Event(GetMap(), m_goInfo->destructibleBuilding.intactEvent, this, caster->GetCharmerOrOwnerOrSelf(), true, caster->GetCharmerOrOwnerOrSelf());
}
else if (m_useTimes == 0) // Destroyed
{
if (!HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_11)) // Was not destroyed before
{
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DestructibleGO: %s got destroyed", GetGuidStr().c_str());
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_9 | GO_FLAG_UNK_10);
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_11);
// Get destroyed DisplayId
if ((!m_goInfo->destructibleBuilding.destroyedDisplayId || m_goInfo->destructibleBuilding.destroyedDisplayId == 1) && destructibleInfo)
newDisplayId = destructibleInfo->destroyedDisplayId;
else
newDisplayId = m_goInfo->destructibleBuilding.destroyedDisplayId;
if (!newDisplayId) // No proper destroyed display ID exists, fetch damaged
{
if ((!m_goInfo->destructibleBuilding.damagedDisplayId || m_goInfo->destructibleBuilding.damagedDisplayId == 1) && destructibleInfo)
newDisplayId = destructibleInfo->damagedDisplayId;
else
newDisplayId = m_goInfo->destructibleBuilding.damagedDisplayId;
}
// Start Event if exist
if (caster && m_goInfo->destructibleBuilding.destroyedEvent)
StartEvents_Event(GetMap(), m_goInfo->destructibleBuilding.destroyedEvent, this, caster->GetCharmerOrOwnerOrSelf(), true, caster->GetCharmerOrOwnerOrSelf());
}
}
else if (m_useTimes <= m_goInfo->destructibleBuilding.damagedNumHits) // Damaged
{
if (!HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_10)) // Was not damaged before
{
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DestructibleGO: %s got damaged (health now %u)", GetGuidStr().c_str(), m_useTimes);
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_10);
// Get damaged DisplayId
if ((!m_goInfo->destructibleBuilding.damagedDisplayId || m_goInfo->destructibleBuilding.damagedDisplayId == 1) && destructibleInfo)
newDisplayId = destructibleInfo->damagedDisplayId;
else
newDisplayId = m_goInfo->destructibleBuilding.damagedDisplayId;
// Start Event if exist
if (caster && m_goInfo->destructibleBuilding.damagedEvent)
StartEvents_Event(GetMap(), m_goInfo->destructibleBuilding.damagedEvent, this, caster->GetCharmerOrOwnerOrSelf(), true, caster->GetCharmerOrOwnerOrSelf());
}
}
// Set display Id
if (newDisplayId != 0xFFFFFFFF && newDisplayId != GetDisplayId() && newDisplayId)
SetDisplayId(newDisplayId);
// Set health
SetGoAnimProgress(GetMaxHealth() ? m_useTimes * 255 / GetMaxHealth() : 255);
}

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "12552"
#define REVISION_NR "12553"
#endif // __REVISION_NR_H__