Files
azerothcore-wotlk/src/server/game/Entities/GameObject/GameObject.h

1005 lines
43 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-GPL2
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#ifndef AZEROTHCORE_GAMEOBJECT_H
#define AZEROTHCORE_GAMEOBJECT_H
#include "Common.h"
#include "SharedDefines.h"
#include "Unit.h"
#include "Object.h"
#include "LootMgr.h"
#include "DatabaseEnv.h"
#include "G3D/Quat.h"
class GameObjectAI;
class Transport;
class StaticTransport;
class MotionTransport;
typedef void(*goEventFlag)(Player*, GameObject*, Battleground*);
#define MAX_GAMEOBJECT_QUEST_ITEMS 6
// from `gameobject_template`
struct GameObjectTemplate
{
uint32 entry;
uint32 type;
uint32 displayId;
std::string name;
std::string IconName;
std::string castBarCaption;
std::string unk1;
float size;
union // different GO types have different data field
{
//0 GAMEOBJECT_TYPE_DOOR
struct
{
uint32 startOpen; //0 used client side to determine GO_ACTIVATED means open/closed
uint32 lockId; //1 -> Lock.dbc
uint32 autoCloseTime; //2 secs till autoclose = autoCloseTime / 0x10000
uint32 noDamageImmune; //3 break opening whenever you recieve damage?
uint32 openTextID; //4 can be used to replace castBarCaption?
uint32 closeTextID; //5
uint32 ignoredByPathing; //6
} door;
//1 GAMEOBJECT_TYPE_BUTTON
struct
{
uint32 startOpen; //0
uint32 lockId; //1 -> Lock.dbc
uint32 autoCloseTime; //2 secs till autoclose = autoCloseTime / 0x10000
uint32 linkedTrap; //3
uint32 noDamageImmune; //4 isBattlegroundObject
uint32 large; //5
uint32 openTextID; //6 can be used to replace castBarCaption?
uint32 closeTextID; //7
uint32 losOK; //8
} button;
//2 GAMEOBJECT_TYPE_QUESTGIVER
struct
{
uint32 lockId; //0 -> Lock.dbc
uint32 questList; //1
uint32 pageMaterial; //2
uint32 gossipID; //3
uint32 customAnim; //4
uint32 noDamageImmune; //5
uint32 openTextID; //6 can be used to replace castBarCaption?
uint32 losOK; //7
uint32 allowMounted; //8
uint32 large; //9
} questgiver;
//3 GAMEOBJECT_TYPE_CHEST
struct
{
uint32 lockId; //0 -> Lock.dbc
uint32 lootId; //1
uint32 chestRestockTime; //2
uint32 consumable; //3
uint32 minSuccessOpens; //4 Deprecated, pre 3.0 was used for mining nodes but since WotLK all mining nodes are usable once and grant all loot with a single use
uint32 maxSuccessOpens; //5 Deprecated, pre 3.0 was used for mining nodes but since WotLK all mining nodes are usable once and grant all loot with a single use
uint32 eventId; //6 lootedEvent
uint32 linkedTrapId; //7
uint32 questId; //8 not used currently but store quest required for GO activation for player
uint32 level; //9
uint32 losOK; //10
uint32 leaveLoot; //11
uint32 notInCombat; //12
uint32 logLoot; //13
uint32 openTextID; //14 can be used to replace castBarCaption?
uint32 groupLootRules; //15
uint32 floatingTooltip; //16
} chest;
//4 GAMEOBJECT_TYPE_BINDER - empty
//5 GAMEOBJECT_TYPE_GENERIC
struct
{
uint32 floatingTooltip; //0
uint32 highlight; //1
uint32 serverOnly; //2
uint32 large; //3
uint32 floatOnWater; //4
int32 questID; //5
} _generic;
//6 GAMEOBJECT_TYPE_TRAP
struct
{
uint32 lockId; //0 -> Lock.dbc
uint32 level; //1
uint32 diameter; //2 diameter for trap activation
uint32 spellId; //3
uint32 type; //4 0 trap with no despawn after cast. 1 trap despawns after cast. 2 bomb casts on spawn.
uint32 cooldown; //5 time in secs
int32 autoCloseTime; //6
uint32 startDelay; //7
uint32 serverOnly; //8
uint32 stealthed; //9
uint32 large; //10
uint32 invisible; //11
uint32 openTextID; //12 can be used to replace castBarCaption?
uint32 closeTextID; //13
uint32 ignoreTotems; //14
} trap;
//7 GAMEOBJECT_TYPE_CHAIR
struct
{
uint32 slots; //0
uint32 height; //1
uint32 onlyCreatorUse; //2
uint32 triggeredEvent; //3
} chair;
//8 GAMEOBJECT_TYPE_SPELL_FOCUS
struct
{
uint32 focusId; //0
uint32 dist; //1
uint32 linkedTrapId; //2
uint32 serverOnly; //3
uint32 questID; //4
uint32 large; //5
uint32 floatingTooltip; //6
} spellFocus;
//9 GAMEOBJECT_TYPE_TEXT
struct
{
uint32 pageID; //0
uint32 language; //1
uint32 pageMaterial; //2
uint32 allowMounted; //3
} text;
//10 GAMEOBJECT_TYPE_GOOBER
struct
{
uint32 lockId; //0 -> Lock.dbc
int32 questId; //1
uint32 eventId; //2
uint32 autoCloseTime; //3
uint32 customAnim; //4
uint32 consumable; //5
uint32 cooldown; //6
uint32 pageId; //7
uint32 language; //8
uint32 pageMaterial; //9
uint32 spellId; //10
uint32 noDamageImmune; //11
uint32 linkedTrapId; //12
uint32 large; //13
uint32 openTextID; //14 can be used to replace castBarCaption?
uint32 closeTextID; //15
uint32 losOK; //16 isBattlegroundObject
uint32 allowMounted; //17
uint32 floatingTooltip; //18
uint32 gossipID; //19
uint32 WorldStateSetsState; //20
} goober;
//11 GAMEOBJECT_TYPE_TRANSPORT
struct
{
uint32 pauseAtTime; //0
uint32 startOpen; //1
uint32 autoCloseTime; //2 secs till autoclose = autoCloseTime / 0x10000
uint32 pause1EventID; //3
uint32 pause2EventID; //4
} transport;
//12 GAMEOBJECT_TYPE_AREADAMAGE
struct
{
uint32 lockId; //0
uint32 radius; //1
uint32 damageMin; //2
uint32 damageMax; //3
uint32 damageSchool; //4
uint32 autoCloseTime; //5 secs till autoclose = autoCloseTime / 0x10000
uint32 openTextID; //6
uint32 closeTextID; //7
} areadamage;
//13 GAMEOBJECT_TYPE_CAMERA
struct
{
uint32 lockId; //0 -> Lock.dbc
uint32 cinematicId; //1
uint32 eventID; //2
uint32 openTextID; //3 can be used to replace castBarCaption?
} camera;
//14 GAMEOBJECT_TYPE_MAPOBJECT - empty
//15 GAMEOBJECT_TYPE_MO_TRANSPORT
struct
{
uint32 taxiPathId; //0
uint32 moveSpeed; //1
uint32 accelRate; //2
uint32 startEventID; //3
uint32 stopEventID; //4
uint32 transportPhysics; //5
uint32 mapID; //6
uint32 worldState1; //7
uint32 canBeStopped; //8
} moTransport;
//16 GAMEOBJECT_TYPE_DUELFLAG - empty
//17 GAMEOBJECT_TYPE_FISHINGNODE - empty
//18 GAMEOBJECT_TYPE_SUMMONING_RITUAL
struct
{
uint32 reqParticipants; //0
uint32 spellId; //1
uint32 animSpell; //2
uint32 ritualPersistent; //3
uint32 casterTargetSpell; //4
uint32 casterTargetSpellTargets; //5
uint32 castersGrouped; //6
uint32 ritualNoTargetCheck; //7
} summoningRitual;
//19 GAMEOBJECT_TYPE_MAILBOX - empty
//20 GAMEOBJECT_TYPE_DONOTUSE - empty
//21 GAMEOBJECT_TYPE_GUARDPOST
struct
{
uint32 creatureID; //0
uint32 charges; //1
} guardpost;
//22 GAMEOBJECT_TYPE_SPELLCASTER
struct
{
uint32 spellId; //0
uint32 charges; //1
uint32 partyOnly; //2
uint32 allowMounted; //3
uint32 large; //4
} spellcaster;
//23 GAMEOBJECT_TYPE_MEETINGSTONE
struct
{
uint32 minLevel; //0
uint32 maxLevel; //1
uint32 areaID; //2
} meetingstone;
//24 GAMEOBJECT_TYPE_FLAGSTAND
struct
{
uint32 lockId; //0
uint32 pickupSpell; //1
uint32 radius; //2
uint32 returnAura; //3
uint32 returnSpell; //4
uint32 noDamageImmune; //5
uint32 openTextID; //6
uint32 losOK; //7
} flagstand;
//25 GAMEOBJECT_TYPE_FISHINGHOLE
struct
{
uint32 radius; //0 how close bobber must land for sending loot
uint32 lootId; //1
uint32 minSuccessOpens; //2
uint32 maxSuccessOpens; //3
uint32 lockId; //4 -> Lock.dbc; possibly 1628 for all?
} fishinghole;
//26 GAMEOBJECT_TYPE_FLAGDROP
struct
{
uint32 lockId; //0
uint32 eventID; //1
uint32 pickupSpell; //2
uint32 noDamageImmune; //3
uint32 openTextID; //4
} flagdrop;
//27 GAMEOBJECT_TYPE_MINI_GAME
struct
{
uint32 gameType; //0
} miniGame;
//29 GAMEOBJECT_TYPE_CAPTURE_POINT
struct
{
uint32 radius; //0
uint32 spell; //1
uint32 worldState1; //2
uint32 worldstate2; //3
uint32 winEventID1; //4
uint32 winEventID2; //5
uint32 contestedEventID1; //6
uint32 contestedEventID2; //7
uint32 progressEventID1; //8
uint32 progressEventID2; //9
uint32 neutralEventID1; //10
uint32 neutralEventID2; //11
uint32 neutralPercent; //12
uint32 worldstate3; //13
uint32 minSuperiority; //14
uint32 maxSuperiority; //15
uint32 minTime; //16
uint32 maxTime; //17
uint32 large; //18
uint32 highlight; //19
uint32 startingValue; //20
uint32 unidirectional; //21
} capturePoint;
//30 GAMEOBJECT_TYPE_AURA_GENERATOR
struct
{
uint32 startOpen; //0
uint32 radius; //1
uint32 auraID1; //2
uint32 conditionID1; //3
uint32 auraID2; //4
uint32 conditionID2; //5
uint32 serverOnly; //6
} auraGenerator;
//31 GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY
struct
{
uint32 mapID; //0
uint32 difficulty; //1
} dungeonDifficulty;
//32 GAMEOBJECT_TYPE_BARBER_CHAIR
struct
{
uint32 chairheight; //0
uint32 heightOffset; //1
} barberChair;
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
struct
{
uint32 intactNumHits; //0
uint32 creditProxyCreature; //1
uint32 state1Name; //2
uint32 intactEvent; //3
uint32 damagedDisplayId; //4
uint32 damagedNumHits; //5
uint32 empty3; //6
uint32 empty4; //7
uint32 empty5; //8
uint32 damagedEvent; //9
uint32 destroyedDisplayId; //10
uint32 empty7; //11
uint32 empty8; //12
uint32 empty9; //13
uint32 destroyedEvent; //14
uint32 empty10; //15
uint32 debuildingTimeSecs; //16
uint32 empty11; //17
uint32 destructibleData; //18
uint32 rebuildingEvent; //19
uint32 empty12; //20
uint32 empty13; //21
uint32 damageEvent; //22
uint32 empty14; //23
} building;
//34 GAMEOBJECT_TYPE_GUILDBANK - empty
//35 GAMEOBJECT_TYPE_TRAPDOOR
struct
{
uint32 whenToPause; // 0
uint32 startOpen; // 1
uint32 autoClose; // 2
} trapDoor;
// not use for specific field access (only for output with loop by all filed), also this determinate max union size
struct
{
uint32 data[MAX_GAMEOBJECT_DATA];
} raw;
};
std::string AIName;
uint32 ScriptId;
bool IsForQuests; // pussywizard
// helpers
[[nodiscard]] bool IsDespawnAtAction() const
{
switch (type)
{
case GAMEOBJECT_TYPE_CHEST:
return chest.consumable;
case GAMEOBJECT_TYPE_GOOBER:
return goober.consumable;
default:
return false;
}
}
[[nodiscard]] bool IsUsableMounted() const
{
switch (type)
{
case GAMEOBJECT_TYPE_QUESTGIVER:
return questgiver.allowMounted;
case GAMEOBJECT_TYPE_TEXT:
return text.allowMounted;
case GAMEOBJECT_TYPE_GOOBER:
return goober.allowMounted;
case GAMEOBJECT_TYPE_SPELLCASTER:
return spellcaster.allowMounted;
default:
return false;
}
}
[[nodiscard]] uint32 GetLockId() const
{
switch (type)
{
case GAMEOBJECT_TYPE_DOOR:
return door.lockId;
case GAMEOBJECT_TYPE_BUTTON:
return button.lockId;
case GAMEOBJECT_TYPE_QUESTGIVER:
return questgiver.lockId;
case GAMEOBJECT_TYPE_CHEST:
return chest.lockId;
case GAMEOBJECT_TYPE_TRAP:
return trap.lockId;
case GAMEOBJECT_TYPE_GOOBER:
return goober.lockId;
case GAMEOBJECT_TYPE_AREADAMAGE:
return areadamage.lockId;
case GAMEOBJECT_TYPE_CAMERA:
return camera.lockId;
case GAMEOBJECT_TYPE_FLAGSTAND:
return flagstand.lockId;
case GAMEOBJECT_TYPE_FISHINGHOLE:
return fishinghole.lockId;
case GAMEOBJECT_TYPE_FLAGDROP:
return flagdrop.lockId;
default:
return 0;
}
}
[[nodiscard]] bool GetDespawnPossibility() const // despawn at targeting of cast?
{
switch (type)
{
case GAMEOBJECT_TYPE_DOOR:
return door.noDamageImmune;
case GAMEOBJECT_TYPE_BUTTON:
return button.noDamageImmune;
case GAMEOBJECT_TYPE_QUESTGIVER:
return questgiver.noDamageImmune;
case GAMEOBJECT_TYPE_GOOBER:
return goober.noDamageImmune;
case GAMEOBJECT_TYPE_FLAGSTAND:
return flagstand.noDamageImmune;
case GAMEOBJECT_TYPE_FLAGDROP:
return flagdrop.noDamageImmune;
default:
return true;
}
}
[[nodiscard]] uint32 GetCharges() const // despawn at uses amount
{
switch (type)
{
//case GAMEOBJECT_TYPE_TRAP: return trap.charges;
case GAMEOBJECT_TYPE_GUARDPOST:
return guardpost.charges;
case GAMEOBJECT_TYPE_SPELLCASTER:
return spellcaster.charges;
default:
return 0;
}
}
[[nodiscard]] uint32 GetLinkedGameObjectEntry() const
{
switch (type)
{
case GAMEOBJECT_TYPE_CHEST:
return chest.linkedTrapId;
case GAMEOBJECT_TYPE_SPELL_FOCUS:
return spellFocus.linkedTrapId;
case GAMEOBJECT_TYPE_GOOBER:
return goober.linkedTrapId;
default:
return 0;
}
}
[[nodiscard]] uint32 GetAutoCloseTime() const
{
uint32 autoCloseTime = 0;
switch (type)
{
case GAMEOBJECT_TYPE_DOOR:
autoCloseTime = door.autoCloseTime;
break;
case GAMEOBJECT_TYPE_BUTTON:
autoCloseTime = button.autoCloseTime;
break;
case GAMEOBJECT_TYPE_TRAP:
autoCloseTime = trap.autoCloseTime;
break;
case GAMEOBJECT_TYPE_GOOBER:
autoCloseTime = goober.autoCloseTime;
break;
case GAMEOBJECT_TYPE_TRANSPORT:
autoCloseTime = transport.autoCloseTime;
break;
case GAMEOBJECT_TYPE_AREADAMAGE:
autoCloseTime = areadamage.autoCloseTime;
break;
default:
break;
}
return autoCloseTime /* xinef: changed to milliseconds/ IN_MILLISECONDS*/; // prior to 3.0.3, conversion was / 0x10000;
}
[[nodiscard]] uint32 GetLootId() const
{
switch (type)
{
case GAMEOBJECT_TYPE_CHEST:
return chest.lootId;
case GAMEOBJECT_TYPE_FISHINGHOLE:
return fishinghole.lootId;
default:
return 0;
}
}
[[nodiscard]] uint32 GetGossipMenuId() const
{
switch (type)
{
case GAMEOBJECT_TYPE_QUESTGIVER:
return questgiver.gossipID;
case GAMEOBJECT_TYPE_GOOBER:
return goober.gossipID;
default:
return 0;
}
}
[[nodiscard]] uint32 GetEventScriptId() const
{
switch (type)
{
case GAMEOBJECT_TYPE_GOOBER:
return goober.eventId;
case GAMEOBJECT_TYPE_CHEST:
return chest.eventId;
case GAMEOBJECT_TYPE_CAMERA:
return camera.eventID;
default:
return 0;
}
}
[[nodiscard]] uint32 GetCooldown() const // Cooldown preventing goober and traps to cast spell
{
switch (type)
{
case GAMEOBJECT_TYPE_TRAP:
return trap.cooldown;
case GAMEOBJECT_TYPE_GOOBER:
return goober.cooldown;
default:
return 0;
}
}
[[nodiscard]] bool IsLargeGameObject() const
{
switch (type)
{
case GAMEOBJECT_TYPE_BUTTON:
return button.large != 0;
case GAMEOBJECT_TYPE_QUESTGIVER:
return questgiver.large != 0;
case GAMEOBJECT_TYPE_GENERIC:
return _generic.large != 0;
case GAMEOBJECT_TYPE_TRAP:
return trap.large != 0;
case GAMEOBJECT_TYPE_SPELL_FOCUS:
return spellFocus.large != 0;
case GAMEOBJECT_TYPE_GOOBER:
return goober.large != 0;
case GAMEOBJECT_TYPE_SPELLCASTER:
return spellcaster.large != 0;
case GAMEOBJECT_TYPE_CAPTURE_POINT:
return capturePoint.large != 0;
default:
return false;
}
}
[[nodiscard]] bool IsGameObjectForQuests() const
{
return IsForQuests;
}
};
// From `gameobject_template_addon`
struct GameObjectTemplateAddon
{
uint32 entry;
uint32 faction;
uint32 flags;
uint32 mingold;
uint32 maxgold;
};
// Benchmarked: Faster than std::map (insert/find)
typedef std::unordered_map<uint32, GameObjectTemplate> GameObjectTemplateContainer;
typedef std::unordered_map<uint32, GameObjectTemplateAddon> GameObjectTemplateAddonContainer;
class OPvPCapturePoint;
struct TransportAnimation;
union GameObjectValue
{
//11 GAMEOBJECT_TYPE_TRANSPORT
struct
{
uint32 PathProgress;
TransportAnimation const* AnimationInfo;
} Transport;
//25 GAMEOBJECT_TYPE_FISHINGHOLE
struct
{
uint32 MaxOpens;
} FishingHole;
//29 GAMEOBJECT_TYPE_CAPTURE_POINT
struct
{
OPvPCapturePoint* OPvPObj;
} CapturePoint;
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
struct
{
uint32 Health;
uint32 MaxHealth;
} Building;
};
struct GameObjectLocale
{
StringVector Name;
StringVector CastBarCaption;
};
// `gameobject_addon` table
struct GameObjectAddon
{
InvisibilityType invisibilityType;
uint32 InvisibilityValue;
};
typedef std::unordered_map<uint32, GameObjectAddon> GameObjectAddonContainer;
// client side GO show states
enum GOState
{
GO_STATE_ACTIVE = 0, // show in world as used and not reset (closed door open)
GO_STATE_READY = 1, // show in world as ready (closed door close)
GO_STATE_ACTIVE_ALTERNATIVE = 2 // show in world as used in alt way and not reset (closed door open by cannon fire)
};
#define MAX_GO_STATE 3
// from `gameobject`
struct GameObjectData
{
explicit GameObjectData() : id(0), mapid(0), phaseMask(0), posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), spawntimesecs(0),
animprogress(0), go_state(GO_STATE_ACTIVE), spawnMask(0), artKit(0), dbData(true) { }
uint32 id; // entry in gamobject_template
uint16 mapid;
uint32 phaseMask;
float posX;
float posY;
float posZ;
float orientation;
G3D::Quat rotation;
int32 spawntimesecs;
uint32 animprogress;
GOState go_state;
uint8 spawnMask;
uint8 artKit;
bool dbData;
};
typedef std::vector<uint32> GameObjectQuestItemList;
typedef std::unordered_map<uint32, GameObjectQuestItemList> GameObjectQuestItemMap;
// For containers: [GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY -> ...
// For bobber: GO_NOT_READY ->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED-><deleted>
// For door(closed):[GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY(close) -> ...
// For door(open): [GO_NOT_READY]->GO_READY (open) ->GO_ACTIVATED (close)->GO_JUST_DEACTIVATED->GO_READY(open) -> ...
enum LootState
{
GO_NOT_READY = 0,
GO_READY, // can be ready but despawned, and then not possible activate until spawn
GO_ACTIVATED,
GO_JUST_DEACTIVATED
};
class Unit;
class GameObjectModel;
// 5 sec for bobber catch
#define FISHING_BOBBER_READY_TIME 5
class GameObject : public WorldObject, public GridObject<GameObject>, public MovableMapObject
{
public:
explicit GameObject();
~GameObject() override;
void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const override;
void AddToWorld() override;
void RemoveFromWorld() override;
void CleanupsBeforeDelete(bool finalCleanup = true) override;
virtual bool Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit = 0);
void Update(uint32 p_time) override;
[[nodiscard]] GameObjectTemplate const* GetGOInfo() const { return m_goInfo; }
[[nodiscard]] GameObjectTemplateAddon const* GetTemplateAddon() const;
[[nodiscard]] GameObjectData const* GetGOData() const { return m_goData; }
[[nodiscard]] GameObjectValue const* GetGOValue() const { return &m_goValue; }
[[nodiscard]] bool IsTransport() const;
[[nodiscard]] bool IsDestructibleBuilding() const;
[[nodiscard]] uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
// z_rot, y_rot, x_rot - rotation angles around z, y and x axes
void SetWorldRotationAngles(float z_rot, float y_rot, float x_rot);
void SetWorldRotation(G3D::Quat const& rot);
void SetTransportPathRotation(float qx, float qy, float qz, float qw);
[[nodiscard]] int64 GetPackedWorldRotation() const { return m_packedRotation; }
// overwrite WorldObject function for proper name localization
[[nodiscard]] std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override;
void SaveToDB();
void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
bool LoadFromDB(uint32 guid, Map* map) { return LoadGameObjectFromDB(guid, map, false); }
bool LoadGameObjectFromDB(uint32 guid, Map* map, bool addToMap = true);
void DeleteFromDB();
void SetOwnerGUID(uint64 owner)
{
// Owner already found and different than expected owner - remove object from old owner
if (owner && GetOwnerGUID() && GetOwnerGUID() != owner)
{
ABORT();
}
m_spawnedByDefault = false; // all object with owner is despawned after delay
SetUInt64Value(OBJECT_FIELD_CREATED_BY, owner);
}
[[nodiscard]] uint64 GetOwnerGUID() const { return GetUInt64Value(OBJECT_FIELD_CREATED_BY); }
[[nodiscard]] Unit* GetOwner() const;
void SetSpellId(uint32 id)
{
m_spawnedByDefault = false; // all summoned object is despawned after delay
m_spellId = id;
}
[[nodiscard]] uint32 GetSpellId() const { return m_spellId;}
[[nodiscard]] time_t GetRespawnTime() const { return m_respawnTime; }
[[nodiscard]] time_t GetRespawnTimeEx() const
{
time_t now = time(nullptr);
if (m_respawnTime > now)
return m_respawnTime;
else
return now;
}
void SetRespawnTime(int32 respawn)
{
m_respawnTime = respawn > 0 ? time(nullptr) + respawn : 0;
m_respawnDelayTime = respawn > 0 ? respawn : 0;
}
void Respawn();
[[nodiscard]] bool isSpawned() const
{
return m_respawnDelayTime == 0 ||
(m_respawnTime > 0 && !m_spawnedByDefault) ||
(m_respawnTime == 0 && m_spawnedByDefault);
}
[[nodiscard]] bool isSpawnedByDefault() const { return m_spawnedByDefault; }
void SetSpawnedByDefault(bool b) { m_spawnedByDefault = b; }
[[nodiscard]] uint32 GetRespawnDelay() const { return m_respawnDelayTime; }
void Refresh();
void Delete();
void getFishLoot(Loot* loot, Player* loot_owner);
void getFishLootJunk(Loot* loot, Player* loot_owner);
[[nodiscard]] GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
[[nodiscard]] GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
void SetGoState(GOState state);
[[nodiscard]] uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); }
void SetGoArtKit(uint8 artkit);
[[nodiscard]] uint8 GetGoAnimProgress() const { return GetByteValue(GAMEOBJECT_BYTES_1, 3); }
void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); }
static void SetGoArtKit(uint8 artkit, GameObject* go, uint32 lowguid = 0);
void SetPhaseMask(uint32 newPhaseMask, bool update) override;
void EnableCollision(bool enable);
void Use(Unit* user);
[[nodiscard]] LootState getLootState() const { return m_lootState; }
// Note: unit is only used when s = GO_ACTIVATED
void SetLootState(LootState s, Unit* unit = nullptr);
[[nodiscard]] uint16 GetLootMode() const { return m_LootMode; }
[[nodiscard]] bool HasLootMode(uint16 lootMode) const { return m_LootMode & lootMode; }
void SetLootMode(uint16 lootMode) { m_LootMode = lootMode; }
void AddLootMode(uint16 lootMode) { m_LootMode |= lootMode; }
void RemoveLootMode(uint16 lootMode) { m_LootMode &= ~lootMode; }
void ResetLootMode() { m_LootMode = LOOT_MODE_DEFAULT; }
void AddToSkillupList(uint32 PlayerGuidLow) { m_SkillupList.push_back(PlayerGuidLow); }
[[nodiscard]] bool IsInSkillupList(uint32 PlayerGuidLow) const
{
for (std::list<uint32>::const_iterator i = m_SkillupList.begin(); i != m_SkillupList.end(); ++i)
if (*i == PlayerGuidLow)
return true;
return false;
}
void ClearSkillupList() { m_SkillupList.clear(); }
void AddUniqueUse(Player* player);
void AddUse() { ++m_usetimes; }
[[nodiscard]] uint32 GetUseCount() const { return m_usetimes; }
[[nodiscard]] uint32 GetUniqueUseCount() const { return m_unique_users.size(); }
void SaveRespawnTime() override;
Loot loot;
[[nodiscard]] Player* GetLootRecipient() const;
[[nodiscard]] Group* GetLootRecipientGroup() const;
void SetLootRecipient(Unit* unit);
bool IsLootAllowedFor(Player const* player) const;
[[nodiscard]] bool HasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 lootingGroupLowGUID; // used to find group which is looting
void SetLootGenerationTime() { m_lootGenerationTime = time(nullptr); }
[[nodiscard]] uint32 GetLootGenerationTime() const { return m_lootGenerationTime; }
[[nodiscard]] bool hasQuest(uint32 quest_id) const override;
[[nodiscard]] bool hasInvolvedQuest(uint32 quest_id) const override;
bool ActivateToQuest(Player* target) const;
void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false, Unit* user = nullptr);
// 0 = use `gameobject`.`spawntimesecs`
void ResetDoorOrButton();
void TriggeringLinkedGameObject(uint32 trapEntry, Unit* target);
[[nodiscard]] bool IsNeverVisible() const override;
bool IsAlwaysVisibleFor(WorldObject const* seer) const override;
[[nodiscard]] bool IsInvisibleDueToDespawn() const override;
uint8 getLevelForTarget(WorldObject const* target) const override
{
if (Unit* owner = GetOwner())
return owner->getLevelForTarget(target);
return 1;
}
GameObject* LookupFishingHoleAround(float range);
void CastSpell(Unit* target, uint32 spell);
void SendCustomAnim(uint32 anim);
[[nodiscard]] bool IsInRange(float x, float y, float z, float radius) const;
void SendMessageToSetInRange(WorldPacket* data, float dist, bool /*self*/, bool includeMargin = false, Player const* skipped_rcvr = nullptr) override; // pussywizard!
void ModifyHealth(int32 change, Unit* attackerOrHealer = nullptr, uint32 spellId = 0);
void SetDestructibleBuildingModifyState(bool allow) { m_allowModifyDestructibleBuilding = allow; }
// sets GameObject type 33 destruction flags and optionally default health for that state
void SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker = nullptr, bool setHealth = false);
[[nodiscard]] GameObjectDestructibleState GetDestructibleState() const
{
if (HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED))
return GO_DESTRUCTIBLE_DESTROYED;
if (HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED))
return GO_DESTRUCTIBLE_DAMAGED;
return GO_DESTRUCTIBLE_INTACT;
}
void EventInform(uint32 eventId);
[[nodiscard]] virtual uint32 GetScriptId() const { return GetGOInfo()->ScriptId; }
[[nodiscard]] GameObjectAI* AI() const { return m_AI; }
[[nodiscard]] std::string GetAIName() const;
void SetDisplayId(uint32 displayid);
[[nodiscard]] uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
GameObjectModel* m_model;
void GetRespawnPosition(float& x, float& y, float& z, float* ori = nullptr) const;
void SetPosition(float x, float y, float z, float o);
void SetPosition(const Position& pos) { SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); }
[[nodiscard]] bool IsStaticTransport() const { return GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT; }
[[nodiscard]] bool IsMotionTransport() const { return GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT; }
Transport* ToTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT || GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT) return reinterpret_cast<Transport*>(this); else return nullptr; }
[[nodiscard]] Transport const* ToTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT || GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT) return reinterpret_cast<Transport const*>(this); else return nullptr; }
StaticTransport* ToStaticTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT) return reinterpret_cast<StaticTransport*>(this); else return nullptr; }
[[nodiscard]] StaticTransport const* ToStaticTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT) return reinterpret_cast<StaticTransport const*>(this); else return nullptr; }
MotionTransport* ToMotionTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<MotionTransport*>(this); else return nullptr; }
[[nodiscard]] MotionTransport const* ToMotionTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<MotionTransport const*>(this); else return nullptr; }
[[nodiscard]] float GetStationaryX() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionX(); return GetPositionX(); }
[[nodiscard]] float GetStationaryY() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionY(); return GetPositionY(); }
[[nodiscard]] float GetStationaryZ() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
[[nodiscard]] float GetStationaryO() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); }
float GetInteractionDistance();
void UpdateModelPosition();
static std::unordered_map<int, goEventFlag> gameObjectToEventFlag; // Gameobject -> event flag
protected:
bool AIM_Initialize();
void UpdateModel(); // updates model in case displayId were changed
uint32 m_spellId;
time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer
LootState m_lootState;
bool m_spawnedByDefault;
uint32 m_cooldownTime; // used as internal reaction delay time store (not state change reaction).
// For traps this: spell casting cooldown, for doors/buttons: reset time.
std::list<uint32> m_SkillupList;
uint32 m_ritualOwnerGUIDLow; // used for GAMEOBJECT_TYPE_SUMMONING_RITUAL where GO is not summoned (no owner)
std::set<uint64> m_unique_users;
uint32 m_usetimes;
typedef std::map<uint32, uint64> ChairSlotAndUser;
ChairSlotAndUser ChairListSlots;
uint32 m_DBTableGuid; ///< For new or temporary gameobjects is 0 for saved it is lowguid
GameObjectTemplate const* m_goInfo;
GameObjectData const* m_goData;
GameObjectValue m_goValue;
bool m_allowModifyDestructibleBuilding;
int64 m_packedRotation;
G3D::Quat m_worldRotation;
Position m_stationaryPosition;
uint64 m_lootRecipient;
uint32 m_lootRecipientGroup;
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
uint32 m_lootGenerationTime;
private:
void CheckRitualList();
void ClearRitualList();
void RemoveFromOwner();
void SwitchDoorOrButton(bool activate, bool alternative = false);
void UpdatePackedRotation();
//! Object distance/size - overridden from Object::_IsWithinDist. Needs to take in account proper GO size.
bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool /*is3D*/) const override
{
//! Following check does check 3d distance
dist2compare += obj->GetObjectSize();
return IsInRange(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), dist2compare);
}
GameObjectAI* m_AI;
};
#endif