mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-28 16:16:27 +00:00
Refactoring part 2 [W.I.P]
This commit is contained in:
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Corpse.h"
|
||||
#include "Player.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "GossipDef.h"
|
||||
#include "World.h"
|
||||
|
||||
Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type)
|
||||
{
|
||||
m_objectType |= TYPEMASK_CORPSE;
|
||||
m_objectTypeId = TYPEID_CORPSE;
|
||||
|
||||
m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_POSITION);
|
||||
|
||||
m_valuesCount = CORPSE_END;
|
||||
|
||||
m_time = time(NULL);
|
||||
|
||||
lootRecipient = NULL;
|
||||
}
|
||||
|
||||
Corpse::~Corpse()
|
||||
{
|
||||
}
|
||||
|
||||
void Corpse::AddToWorld()
|
||||
{
|
||||
///- Register the corpse for guid lookup
|
||||
if (!IsInWorld())
|
||||
sObjectAccessor->AddObject(this);
|
||||
|
||||
Object::AddToWorld();
|
||||
}
|
||||
|
||||
void Corpse::RemoveFromWorld()
|
||||
{
|
||||
///- Remove the corpse from the accessor
|
||||
if (IsInWorld())
|
||||
sObjectAccessor->RemoveObject(this);
|
||||
|
||||
Object::RemoveFromWorld();
|
||||
}
|
||||
|
||||
bool Corpse::Create(uint32 guidlow, Map* map)
|
||||
{
|
||||
SetMap(map);
|
||||
Object::_Create(guidlow, 0, HIGHGUID_CORPSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Corpse::Create(uint32 guidlow, Player* owner)
|
||||
{
|
||||
ASSERT(owner);
|
||||
|
||||
Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
|
||||
|
||||
if (!IsPositionValid())
|
||||
{
|
||||
sLog->outError("Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
|
||||
guidlow, owner->GetName().c_str(), owner->GetPositionX(), owner->GetPositionY());
|
||||
return false;
|
||||
}
|
||||
|
||||
//we need to assign owner's map for corpse
|
||||
//in other way we will get a crash in Corpse::SaveToDB()
|
||||
SetMap(owner->GetMap());
|
||||
|
||||
WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetPhaseMask());
|
||||
|
||||
SetObjectScale(1);
|
||||
SetUInt64Value(CORPSE_FIELD_OWNER, owner->GetGUID());
|
||||
|
||||
_gridCoord = Trinity::ComputeGridCoord(GetPositionX(), GetPositionY());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Corpse::SaveToDB()
|
||||
{
|
||||
// prevent DB data inconsistence problems and duplicates
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
DeleteFromDB(trans);
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE);
|
||||
stmt->setUInt32(0, GetGUIDLow()); // corpseGuid
|
||||
stmt->setUInt32(1, GUID_LOPART(GetOwnerGUID())); // guid
|
||||
stmt->setFloat (2, GetPositionX()); // posX
|
||||
stmt->setFloat (3, GetPositionY()); // posY
|
||||
stmt->setFloat (4, GetPositionZ()); // posZ
|
||||
stmt->setFloat (5, GetOrientation()); // orientation
|
||||
stmt->setUInt16(6, GetMapId()); // mapId
|
||||
stmt->setUInt32(7, GetUInt32Value(CORPSE_FIELD_DISPLAY_ID)); // displayId
|
||||
stmt->setString(8, _ConcatFields(CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END)); // itemCache
|
||||
stmt->setUInt32(9, GetUInt32Value(CORPSE_FIELD_BYTES_1)); // bytes1
|
||||
stmt->setUInt32(10, GetUInt32Value(CORPSE_FIELD_BYTES_2)); // bytes2
|
||||
stmt->setUInt32(11, GetUInt32Value(CORPSE_FIELD_GUILD)); // guildId
|
||||
stmt->setUInt8 (12, GetUInt32Value(CORPSE_FIELD_FLAGS)); // flags
|
||||
stmt->setUInt8 (13, GetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS)); // dynFlags
|
||||
stmt->setUInt32(14, uint32(m_time)); // time
|
||||
stmt->setUInt8 (15, GetType()); // corpseType
|
||||
stmt->setUInt32(16, GetInstanceId()); // instanceId
|
||||
stmt->setUInt32(17, GetPhaseMask()); // phaseMask
|
||||
trans->Append(stmt);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void Corpse::DeleteFromDB(SQLTransaction& trans)
|
||||
{
|
||||
PreparedStatement* stmt = NULL;
|
||||
if (GetType() == CORPSE_BONES)
|
||||
{
|
||||
// Only specific bones
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE);
|
||||
stmt->setUInt32(0, GetGUIDLow());
|
||||
}
|
||||
else
|
||||
{
|
||||
// all corpses (not bones)
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_CORPSES);
|
||||
stmt->setUInt32(0, GUID_LOPART(GetOwnerGUID()));
|
||||
}
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields)
|
||||
{
|
||||
uint32 ownerGuid = fields[17].GetUInt32();
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
||||
// SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, guildId, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0
|
||||
float posX = fields[0].GetFloat();
|
||||
float posY = fields[1].GetFloat();
|
||||
float posZ = fields[2].GetFloat();
|
||||
float o = fields[3].GetFloat();
|
||||
uint32 mapId = fields[4].GetUInt16();
|
||||
|
||||
Object::_Create(guid, 0, HIGHGUID_CORPSE);
|
||||
|
||||
SetObjectScale(1.0f);
|
||||
SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, fields[5].GetUInt32());
|
||||
_LoadIntoDataField(fields[6].GetCString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END);
|
||||
SetUInt32Value(CORPSE_FIELD_BYTES_1, fields[7].GetUInt32());
|
||||
SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32());
|
||||
SetUInt32Value(CORPSE_FIELD_GUILD, fields[9].GetUInt32());
|
||||
SetUInt32Value(CORPSE_FIELD_FLAGS, fields[10].GetUInt8());
|
||||
SetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS, fields[11].GetUInt8());
|
||||
SetUInt64Value(CORPSE_FIELD_OWNER, MAKE_NEW_GUID(ownerGuid, 0, HIGHGUID_PLAYER));
|
||||
|
||||
m_time = time_t(fields[12].GetUInt32());
|
||||
|
||||
uint32 instanceId = fields[14].GetUInt32();
|
||||
uint32 phaseMask = fields[15].GetUInt32();
|
||||
|
||||
// place
|
||||
SetLocationInstanceId(instanceId);
|
||||
SetLocationMapId(mapId);
|
||||
SetPhaseMask(phaseMask, false);
|
||||
Relocate(posX, posY, posZ, o);
|
||||
|
||||
if (!IsPositionValid())
|
||||
{
|
||||
sLog->outError("Corpse (guid: %u, owner: %u) is not created, given coordinates are not valid (X: %f, Y: %f, Z: %f)",
|
||||
GetGUIDLow(), GUID_LOPART(GetOwnerGUID()), posX, posY, posZ);
|
||||
return false;
|
||||
}
|
||||
|
||||
_gridCoord = Trinity::ComputeGridCoord(GetPositionX(), GetPositionY());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Corpse::IsExpired(time_t t) const
|
||||
{
|
||||
if (m_type == CORPSE_BONES)
|
||||
return m_time < t - 60 * MINUTE;
|
||||
else
|
||||
return m_time < t - 3 * DAY;
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_CORPSE_H
|
||||
#define AZEROTHCORE_CORPSE_H
|
||||
|
||||
#include "Object.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GridDefines.h"
|
||||
#include "LootMgr.h"
|
||||
|
||||
enum CorpseType
|
||||
{
|
||||
CORPSE_BONES = 0,
|
||||
CORPSE_RESURRECTABLE_PVE = 1,
|
||||
CORPSE_RESURRECTABLE_PVP = 2
|
||||
};
|
||||
#define MAX_CORPSE_TYPE 3
|
||||
|
||||
// Value equal client resurrection dialog show radius.
|
||||
#define CORPSE_RECLAIM_RADIUS 39
|
||||
|
||||
enum CorpseFlags
|
||||
{
|
||||
CORPSE_FLAG_NONE = 0x00,
|
||||
CORPSE_FLAG_BONES = 0x01,
|
||||
CORPSE_FLAG_UNK1 = 0x02,
|
||||
CORPSE_FLAG_UNK2 = 0x04,
|
||||
CORPSE_FLAG_HIDE_HELM = 0x08,
|
||||
CORPSE_FLAG_HIDE_CLOAK = 0x10,
|
||||
CORPSE_FLAG_LOOTABLE = 0x20
|
||||
};
|
||||
|
||||
class Corpse : public WorldObject, public GridObject<Corpse>
|
||||
{
|
||||
public:
|
||||
explicit Corpse(CorpseType type = CORPSE_BONES);
|
||||
~Corpse();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create(uint32 guidlow, Map* map);
|
||||
bool Create(uint32 guidlow, Player* owner);
|
||||
|
||||
void SaveToDB();
|
||||
bool LoadCorpseFromDB(uint32 guid, Field* fields);
|
||||
|
||||
void DeleteFromDB(SQLTransaction& trans);
|
||||
|
||||
uint64 GetOwnerGUID() const { return GetUInt64Value(CORPSE_FIELD_OWNER); }
|
||||
|
||||
time_t const& GetGhostTime() const { return m_time; }
|
||||
void ResetGhostTime() { m_time = time(NULL); }
|
||||
CorpseType GetType() const { return m_type; }
|
||||
|
||||
GridCoord const& GetGridCoord() const { return _gridCoord; }
|
||||
void SetGridCoord(GridCoord const& gridCoord) { _gridCoord = gridCoord; }
|
||||
|
||||
Loot loot; // remove insignia ONLY at BG
|
||||
Player* lootRecipient;
|
||||
|
||||
bool IsExpired(time_t t) const;
|
||||
|
||||
private:
|
||||
CorpseType m_type;
|
||||
time_t m_time;
|
||||
GridCoord _gridCoord; // gride for corpse position for fast search
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,818 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_CREATURE_H
|
||||
#define AZEROTHCORE_CREATURE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Unit.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "ItemPrototype.h"
|
||||
#include "LootMgr.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Cell.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
class SpellInfo;
|
||||
|
||||
class CreatureAI;
|
||||
class Quest;
|
||||
class Player;
|
||||
class WorldSession;
|
||||
class CreatureGroup;
|
||||
|
||||
enum CreatureFlagsExtra
|
||||
{
|
||||
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
|
||||
CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
|
||||
CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
|
||||
CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
|
||||
CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
|
||||
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
|
||||
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
|
||||
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
|
||||
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
|
||||
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
|
||||
CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
|
||||
CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
|
||||
CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills
|
||||
CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre
|
||||
CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // Creature is subject to all diminishing returns as player are
|
||||
CREATURE_FLAG_EXTRA_KNOCKBACK_IMMUNE= 0x00200000, // pussywizard: set mostly for dungeon bosses and their summons
|
||||
CREATURE_FLAG_EXTRA_AVOID_AOE = 0x00400000, // pussywizard: ignored by aoe attacks (for icc blood prince council npc - Dark Nucleus)
|
||||
CREATURE_FLAG_EXTRA_NO_DODGE = 0x00800000, // xinef: target cannot dodge
|
||||
CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
|
||||
CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000 // creature ignore pathfinding
|
||||
};
|
||||
|
||||
#define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \
|
||||
CREATURE_FLAG_EXTRA_NO_PARRY | CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN | CREATURE_FLAG_EXTRA_NO_BLOCK | \
|
||||
CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \
|
||||
CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \
|
||||
CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \
|
||||
CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_KNOCKBACK_IMMUNE | CREATURE_FLAG_EXTRA_AVOID_AOE | \
|
||||
CREATURE_FLAG_EXTRA_NO_DODGE | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING)
|
||||
|
||||
|
||||
#define MAX_AGGRO_RESET_TIME 10 // in seconds
|
||||
|
||||
#define MAX_KILL_CREDIT 2
|
||||
#define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS
|
||||
#define PET_FOCUS_REGEN_INTERVAL 4 * IN_MILLISECONDS
|
||||
|
||||
#define MAX_CREATURE_QUEST_ITEMS 6
|
||||
|
||||
#define MAX_EQUIPMENT_ITEMS 3
|
||||
|
||||
// from `creature_template` table
|
||||
struct CreatureTemplate
|
||||
{
|
||||
uint32 Entry;
|
||||
uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
|
||||
uint32 KillCredit[MAX_KILL_CREDIT];
|
||||
uint32 Modelid1;
|
||||
uint32 Modelid2;
|
||||
uint32 Modelid3;
|
||||
uint32 Modelid4;
|
||||
std::string Name;
|
||||
std::string SubName;
|
||||
std::string IconName;
|
||||
uint32 GossipMenuId;
|
||||
uint8 minlevel;
|
||||
uint8 maxlevel;
|
||||
uint32 expansion;
|
||||
uint32 faction;
|
||||
uint32 npcflag;
|
||||
float speed_walk;
|
||||
float speed_run;
|
||||
float scale;
|
||||
uint32 rank;
|
||||
float mindmg;
|
||||
float maxdmg;
|
||||
uint32 dmgschool;
|
||||
uint32 attackpower;
|
||||
float dmg_multiplier;
|
||||
uint32 baseattacktime;
|
||||
uint32 rangeattacktime;
|
||||
uint32 unit_class; // enum Classes. Note only 4 classes are known for creatures.
|
||||
uint32 unit_flags; // enum UnitFlags mask values
|
||||
uint32 unit_flags2; // enum UnitFlags2 mask values
|
||||
uint32 dynamicflags;
|
||||
uint32 family; // enum CreatureFamily values (optional)
|
||||
uint32 trainer_type;
|
||||
uint32 trainer_spell;
|
||||
uint32 trainer_class;
|
||||
uint32 trainer_race;
|
||||
float minrangedmg;
|
||||
float maxrangedmg;
|
||||
uint32 rangedattackpower;
|
||||
uint32 type; // enum CreatureType values
|
||||
uint32 type_flags; // enum CreatureTypeFlags mask values
|
||||
uint32 lootid;
|
||||
uint32 pickpocketLootId;
|
||||
uint32 SkinLootId;
|
||||
int32 resistance[MAX_SPELL_SCHOOL];
|
||||
uint32 spells[CREATURE_MAX_SPELLS];
|
||||
uint32 PetSpellDataId;
|
||||
uint32 VehicleId;
|
||||
uint32 mingold;
|
||||
uint32 maxgold;
|
||||
std::string AIName;
|
||||
uint32 MovementType;
|
||||
uint32 InhabitType;
|
||||
float HoverHeight;
|
||||
float ModHealth;
|
||||
float ModMana;
|
||||
float ModArmor;
|
||||
bool RacialLeader;
|
||||
uint32 questItems[MAX_CREATURE_QUEST_ITEMS];
|
||||
uint32 movementId;
|
||||
bool RegenHealth;
|
||||
uint32 MechanicImmuneMask;
|
||||
uint32 flags_extra;
|
||||
uint32 ScriptID;
|
||||
WorldPacket queryData; // pussywizard
|
||||
uint32 GetRandomValidModelId() const;
|
||||
uint32 GetFirstValidModelId() const;
|
||||
|
||||
// helpers
|
||||
SkillType GetRequiredLootSkill() const
|
||||
{
|
||||
if (type_flags & CREATURE_TYPEFLAGS_HERBLOOT)
|
||||
return SKILL_HERBALISM;
|
||||
else if (type_flags & CREATURE_TYPEFLAGS_MININGLOOT)
|
||||
return SKILL_MINING;
|
||||
else if (type_flags & CREATURE_TYPEFLAGS_ENGINEERLOOT)
|
||||
return SKILL_ENGINEERING;
|
||||
else
|
||||
return SKILL_SKINNING; // normal case
|
||||
}
|
||||
|
||||
bool IsTameable(bool exotic) const
|
||||
{
|
||||
if (type != CREATURE_TYPE_BEAST || family == 0 || (type_flags & CREATURE_TYPEFLAGS_TAMEABLE) == 0)
|
||||
return false;
|
||||
|
||||
// if can tame exotic then can tame any temable
|
||||
return exotic || (type_flags & CREATURE_TYPEFLAGS_EXOTIC) == 0;
|
||||
}
|
||||
|
||||
void InitializeQueryData();
|
||||
};
|
||||
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
typedef UNORDERED_MAP<uint32, CreatureTemplate> CreatureTemplateContainer;
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
// Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage).
|
||||
struct CreatureBaseStats
|
||||
{
|
||||
uint32 BaseHealth[MAX_EXPANSIONS];
|
||||
uint32 BaseMana;
|
||||
uint32 BaseArmor;
|
||||
uint32 AttackPower;
|
||||
uint32 RangedAttackPower;
|
||||
float BaseDamage[MAX_EXPANSIONS];
|
||||
|
||||
// Helpers
|
||||
|
||||
uint32 GenerateHealth(CreatureTemplate const* info) const
|
||||
{
|
||||
return uint32(ceil(BaseHealth[info->expansion] * info->ModHealth));
|
||||
}
|
||||
|
||||
uint32 GenerateMana(CreatureTemplate const* info) const
|
||||
{
|
||||
// Mana can be 0.
|
||||
if (!BaseMana)
|
||||
return 0;
|
||||
|
||||
return uint32(ceil(BaseMana * info->ModMana));
|
||||
}
|
||||
|
||||
uint32 GenerateArmor(CreatureTemplate const* info) const
|
||||
{
|
||||
return uint32(ceil(BaseArmor * info->ModArmor));
|
||||
}
|
||||
|
||||
float GenerateBaseDamage(CreatureTemplate const* info) const
|
||||
{
|
||||
return BaseDamage[info->expansion];
|
||||
}
|
||||
|
||||
static CreatureBaseStats const* GetBaseStats(uint8 level, uint8 unitClass);
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint16, CreatureBaseStats> CreatureBaseStatsContainer;
|
||||
|
||||
struct CreatureLocale
|
||||
{
|
||||
StringVector Name;
|
||||
StringVector SubName;
|
||||
};
|
||||
|
||||
struct GossipMenuItemsLocale
|
||||
{
|
||||
StringVector OptionText;
|
||||
StringVector BoxText;
|
||||
};
|
||||
|
||||
struct PointOfInterestLocale
|
||||
{
|
||||
StringVector IconName;
|
||||
};
|
||||
|
||||
struct EquipmentInfo
|
||||
{
|
||||
uint32 ItemEntry[MAX_EQUIPMENT_ITEMS];
|
||||
};
|
||||
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
typedef UNORDERED_MAP<uint8, EquipmentInfo> EquipmentInfoContainerInternal;
|
||||
typedef UNORDERED_MAP<uint32, EquipmentInfoContainerInternal> EquipmentInfoContainer;
|
||||
|
||||
// from `creature` table
|
||||
struct CreatureData
|
||||
{
|
||||
CreatureData() : id(0), mapid(0), phaseMask(0), displayid(0), equipmentId(0),
|
||||
posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), spawntimesecs(0),
|
||||
spawndist(0.0f), currentwaypoint(0), curhealth(0), curmana(0), movementType(0),
|
||||
spawnMask(0), npcflag(0), unit_flags(0), dynamicflags(0), dbData(true), overwrittenZ(false) { }
|
||||
uint32 id; // entry in creature_template
|
||||
uint16 mapid;
|
||||
uint32 phaseMask;
|
||||
uint32 displayid;
|
||||
int8 equipmentId;
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float orientation;
|
||||
uint32 spawntimesecs;
|
||||
float spawndist;
|
||||
uint32 currentwaypoint;
|
||||
uint32 curhealth;
|
||||
uint32 curmana;
|
||||
uint8 movementType;
|
||||
uint8 spawnMask;
|
||||
uint32 npcflag;
|
||||
uint32 unit_flags; // enum UnitFlags mask values
|
||||
uint32 dynamicflags;
|
||||
bool dbData;
|
||||
bool overwrittenZ;
|
||||
};
|
||||
|
||||
struct CreatureModelInfo
|
||||
{
|
||||
float bounding_radius;
|
||||
float combat_reach;
|
||||
uint8 gender;
|
||||
uint32 modelid_other_gender;
|
||||
};
|
||||
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
typedef UNORDERED_MAP<uint16, CreatureModelInfo> CreatureModelContainer;
|
||||
|
||||
enum InhabitTypeValues
|
||||
{
|
||||
INHABIT_GROUND = 1,
|
||||
INHABIT_WATER = 2,
|
||||
INHABIT_AIR = 4,
|
||||
INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR
|
||||
};
|
||||
|
||||
// Enums used by StringTextData::Type (CreatureEventAI)
|
||||
enum ChatType
|
||||
{
|
||||
CHAT_TYPE_SAY = 0,
|
||||
CHAT_TYPE_YELL = 1,
|
||||
CHAT_TYPE_TEXT_EMOTE = 2,
|
||||
CHAT_TYPE_BOSS_EMOTE = 3,
|
||||
CHAT_TYPE_WHISPER = 4,
|
||||
CHAT_TYPE_BOSS_WHISPER = 5,
|
||||
CHAT_TYPE_ZONE_YELL = 6,
|
||||
CHAT_TYPE_END = 255
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
// `creature_addon` table
|
||||
struct CreatureAddon
|
||||
{
|
||||
uint32 path_id;
|
||||
uint32 mount;
|
||||
uint32 bytes1;
|
||||
uint32 bytes2;
|
||||
uint32 emote;
|
||||
std::vector<uint32> auras;
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32, CreatureAddon> CreatureAddonContainer;
|
||||
|
||||
// Vendors
|
||||
struct VendorItem
|
||||
{
|
||||
VendorItem(uint32 _item, int32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost)
|
||||
: item(_item), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost) {}
|
||||
|
||||
uint32 item;
|
||||
uint32 maxcount; // 0 for infinity item amount
|
||||
uint32 incrtime; // time for restore items amount if maxcount != 0
|
||||
uint32 ExtendedCost;
|
||||
|
||||
//helpers
|
||||
bool IsGoldRequired(ItemTemplate const* pProto) const { return pProto->Flags2 & ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD || !ExtendedCost; }
|
||||
};
|
||||
typedef std::vector<VendorItem*> VendorItemList;
|
||||
|
||||
struct VendorItemData
|
||||
{
|
||||
VendorItemList m_items;
|
||||
|
||||
VendorItem* GetItem(uint32 slot) const
|
||||
{
|
||||
if (slot >= m_items.size())
|
||||
return NULL;
|
||||
|
||||
return m_items[slot];
|
||||
}
|
||||
bool Empty() const { return m_items.empty(); }
|
||||
uint8 GetItemCount() const { return m_items.size(); }
|
||||
void AddItem(uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost)
|
||||
{
|
||||
m_items.push_back(new VendorItem(item, maxcount, ptime, ExtendedCost));
|
||||
}
|
||||
bool RemoveItem(uint32 item_id);
|
||||
VendorItem const* FindItemCostPair(uint32 item_id, uint32 extendedCost) const;
|
||||
void Clear()
|
||||
{
|
||||
for (VendorItemList::const_iterator itr = m_items.begin(); itr != m_items.end(); ++itr)
|
||||
delete (*itr);
|
||||
m_items.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct VendorItemCount
|
||||
{
|
||||
explicit VendorItemCount(uint32 _item, uint32 _count)
|
||||
: itemId(_item), count(_count), lastIncrementTime(time(NULL)) {}
|
||||
|
||||
uint32 itemId;
|
||||
uint32 count;
|
||||
time_t lastIncrementTime;
|
||||
};
|
||||
|
||||
typedef std::list<VendorItemCount> VendorItemCounts;
|
||||
|
||||
struct TrainerSpell
|
||||
{
|
||||
TrainerSpell() : spell(0), spellCost(0), reqSkill(0), reqSkillValue(0), reqLevel(0)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
learnedSpell[i] = 0;
|
||||
}
|
||||
|
||||
uint32 spell;
|
||||
uint32 spellCost;
|
||||
uint32 reqSkill;
|
||||
uint32 reqSkillValue;
|
||||
uint32 reqLevel;
|
||||
uint32 learnedSpell[3];
|
||||
|
||||
// helpers
|
||||
bool IsCastable() const { return learnedSpell[0] != spell; }
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32 /*spellid*/, TrainerSpell> TrainerSpellMap;
|
||||
|
||||
struct TrainerSpellData
|
||||
{
|
||||
TrainerSpellData() : trainerType(0) {}
|
||||
~TrainerSpellData() { spellList.clear(); }
|
||||
|
||||
TrainerSpellMap spellList;
|
||||
uint32 trainerType; // trainer type based at trainer spells, can be different from creature_template value.
|
||||
// req. for correct show non-prof. trainers like weaponmaster, allowed values 0 and 2.
|
||||
TrainerSpell const* Find(uint32 spell_id) const;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, time_t> CreatureSpellCooldowns;
|
||||
|
||||
// max different by z coordinate for creature aggro reaction
|
||||
#define CREATURE_Z_ATTACK_RANGE 3
|
||||
|
||||
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
|
||||
|
||||
class Creature : public Unit, public GridObject<Creature>, public MovableMapObject
|
||||
{
|
||||
public:
|
||||
|
||||
explicit Creature(bool isWorldObject = false);
|
||||
virtual ~Creature();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
void SetObjectScale(float scale);
|
||||
void SetDisplayId(uint32 modelId);
|
||||
|
||||
void DisappearAndDie();
|
||||
|
||||
bool Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint32 vehId, float x, float y, float z, float ang, const CreatureData* data = NULL);
|
||||
bool LoadCreaturesAddon(bool reload = false);
|
||||
void SelectLevel(bool changelevel = true);
|
||||
void LoadEquipment(int8 id = 1, bool force = false);
|
||||
|
||||
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
|
||||
|
||||
void Update(uint32 time); // overwrited Unit::Update
|
||||
void GetRespawnPosition(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
|
||||
|
||||
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
|
||||
uint32 GetCorpseDelay() const { return m_corpseDelay; }
|
||||
bool IsRacialLeader() const { return GetCreatureTemplate()->RacialLeader; }
|
||||
bool IsCivilian() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
|
||||
bool IsTrigger() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
|
||||
bool IsGuard() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_GUARD; }
|
||||
bool CanWalk() const { return GetCreatureTemplate()->InhabitType & INHABIT_GROUND; }
|
||||
bool CanSwim() const { return (GetCreatureTemplate()->InhabitType & INHABIT_WATER) || IS_PLAYER_GUID(GetOwnerGUID()); }
|
||||
bool CanFly() const { return GetCreatureTemplate()->InhabitType & INHABIT_AIR; }
|
||||
|
||||
void SetReactState(ReactStates st) { m_reactState = st; }
|
||||
ReactStates GetReactState() const { return m_reactState; }
|
||||
bool HasReactState(ReactStates state) const { return (m_reactState == state); }
|
||||
void InitializeReactState();
|
||||
|
||||
///// TODO RENAME THIS!!!!!
|
||||
bool isCanInteractWithBattleMaster(Player* player, bool msg) const;
|
||||
bool isCanTrainingAndResetTalentsOf(Player* player) const;
|
||||
bool CanCreatureAttack(Unit const* victim, bool skipDistCheck = false) const;
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo);
|
||||
|
||||
bool HasMechanicTemplateImmunity(uint32 mask) const;
|
||||
// redefine Unit::IsImmunedToSpell
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const;
|
||||
// redefine Unit::IsImmunedToSpellEffect
|
||||
bool isElite() const
|
||||
{
|
||||
if (IsPet())
|
||||
return false;
|
||||
|
||||
uint32 rank = GetCreatureTemplate()->rank;
|
||||
return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE;
|
||||
}
|
||||
|
||||
bool isWorldBoss() const
|
||||
{
|
||||
if (IsPet())
|
||||
return false;
|
||||
|
||||
return GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_BOSS;
|
||||
}
|
||||
|
||||
bool IsDungeonBoss() const;
|
||||
bool IsImmuneToKnockback() const;
|
||||
bool IsAvoidingAOE() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_AVOID_AOE; }
|
||||
|
||||
uint8 getLevelForTarget(WorldObject const* target) const; // overwrite Unit::getLevelForTarget for boss level support
|
||||
|
||||
bool IsInEvadeMode() const { return HasUnitState(UNIT_STATE_EVADE); }
|
||||
|
||||
bool AIM_Initialize(CreatureAI* ai = NULL);
|
||||
void Motion_Initialize();
|
||||
|
||||
CreatureAI* AI() const { return (CreatureAI*)i_AI; }
|
||||
|
||||
bool SetWalk(bool enable);
|
||||
bool SetDisableGravity(bool disable, bool packetOnly = false);
|
||||
bool SetSwim(bool enable);
|
||||
bool SetCanFly(bool enable, bool packetOnly = false);
|
||||
bool SetWaterWalking(bool enable, bool packetOnly = false);
|
||||
bool SetFeatherFall(bool enable, bool packetOnly = false);
|
||||
bool SetHover(bool enable, bool packetOnly = false);
|
||||
|
||||
uint32 GetShieldBlockValue() const
|
||||
{
|
||||
return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20));
|
||||
}
|
||||
|
||||
SpellSchoolMask GetMeleeDamageSchoolMask() const { return m_meleeDamageSchoolMask; }
|
||||
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
|
||||
|
||||
void _AddCreatureSpellCooldown(uint32 spell_id, uint32 end_time);
|
||||
virtual void AddSpellCooldown(uint32 spell_id, uint32 /*itemid*/, uint32 end_time, bool needSendToClient = false, bool forceSendToSpectator = false);
|
||||
virtual bool HasSpellCooldown(uint32 spell_id) const;
|
||||
uint32 GetSpellCooldown(uint32 spell_id) const;
|
||||
void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs);
|
||||
bool IsSpellProhibited(SpellSchoolMask idSchoolMask) const;
|
||||
|
||||
bool HasSpell(uint32 spellID) const;
|
||||
|
||||
bool UpdateEntry(uint32 entry, const CreatureData* data=NULL, bool changelevel=true );
|
||||
bool UpdateStats(Stats stat);
|
||||
bool UpdateAllStats();
|
||||
void UpdateResistances(uint32 school);
|
||||
void UpdateArmor();
|
||||
void UpdateMaxHealth();
|
||||
void UpdateMaxPower(Powers power);
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false);
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage);
|
||||
|
||||
void SetCanDualWield(bool value);
|
||||
int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
|
||||
uint8 GetCurrentEquipmentId() { return m_equipmentId; }
|
||||
void SetCurrentEquipmentId(uint8 id) { m_equipmentId = id; }
|
||||
|
||||
float GetSpellDamageMod(int32 Rank);
|
||||
|
||||
VendorItemData const* GetVendorItems() const;
|
||||
uint32 GetVendorItemCurrentCount(VendorItem const* vItem);
|
||||
uint32 UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count);
|
||||
|
||||
TrainerSpellData const* GetTrainerSpells() const;
|
||||
|
||||
CreatureTemplate const* GetCreatureTemplate() const { return m_creatureInfo; }
|
||||
CreatureData const* GetCreatureData() const { return m_creatureData; }
|
||||
CreatureAddon const* GetCreatureAddon() const;
|
||||
|
||||
std::string GetAIName() const;
|
||||
std::string GetScriptName() const;
|
||||
uint32 GetScriptId() const;
|
||||
|
||||
// override WorldObject function for proper name localization
|
||||
std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const;
|
||||
|
||||
void setDeathState(DeathState s, bool despawn = false); // override virtual Unit::setDeathState
|
||||
|
||||
bool LoadFromDB(uint32 guid, Map* map) { return LoadCreatureFromDB(guid, map, false, true); }
|
||||
bool LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap = true, bool gridLoad = false);
|
||||
void SaveToDB();
|
||||
// overriden in Pet
|
||||
virtual void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
|
||||
virtual void DeleteFromDB(); // overriden in Pet
|
||||
|
||||
Loot loot;
|
||||
uint64 GetLootRecipientGUID() const { return m_lootRecipient; }
|
||||
Player* GetLootRecipient() const;
|
||||
Group* GetLootRecipientGroup() const;
|
||||
bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
|
||||
bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party.
|
||||
bool CanGeneratePickPocketLoot() const { return lootPickPocketRestoreTime == 0 || lootPickPocketRestoreTime < time(NULL); }
|
||||
void SetPickPocketLootTime() { lootPickPocketRestoreTime = time(NULL) + MINUTE + GetCorpseDelay() + GetRespawnTime(); }
|
||||
void ResetPickPocketLootTime() { lootPickPocketRestoreTime = 0; }
|
||||
|
||||
void SetLootRecipient (Unit* unit, bool withGroup = true);
|
||||
void AllLootRemovedFromCorpse();
|
||||
|
||||
uint16 GetLootMode() const { return m_LootMode; }
|
||||
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; }
|
||||
|
||||
SpellInfo const* reachWithSpellAttack(Unit* victim);
|
||||
SpellInfo const* reachWithSpellCure(Unit* victim);
|
||||
|
||||
uint32 m_spells[CREATURE_MAX_SPELLS];
|
||||
CreatureSpellCooldowns m_CreatureSpellCooldowns;
|
||||
uint32 m_ProhibitSchoolTime[7];
|
||||
|
||||
bool CanStartAttack(Unit const* u) const;
|
||||
float GetAggroRange(Unit const* target) const;
|
||||
|
||||
void SendAIReaction(AiReaction reactionType);
|
||||
|
||||
Unit* SelectNearestTarget(float dist = 0, bool playerOnly = false) const;
|
||||
Unit* SelectNearestTargetInAttackDistance(float dist) const;
|
||||
|
||||
void DoFleeToGetAssistance();
|
||||
void CallForHelp(float fRadius);
|
||||
void CallAssistance();
|
||||
void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; }
|
||||
void SetNoSearchAssistance(bool val) { m_AlreadySearchedAssistance = val; }
|
||||
bool HasSearchedAssistance() { return m_AlreadySearchedAssistance; }
|
||||
bool CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const;
|
||||
bool _IsTargetAcceptable(const Unit* target) const;
|
||||
bool _CanDetectFeignDeathOf(const Unit* target) const; // pussywizard
|
||||
|
||||
// pussywizard: updated at faction change, disable move in line of sight if actual faction is not hostile to anyone
|
||||
void UpdateMoveInLineOfSightState();
|
||||
bool IsMoveInLineOfSightDisabled() { return m_moveInLineOfSightDisabled; }
|
||||
bool IsMoveInLineOfSightStrictlyDisabled() { return m_moveInLineOfSightStrictlyDisabled; }
|
||||
|
||||
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
|
||||
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
|
||||
|
||||
void RemoveCorpse(bool setSpawnTime = true, bool skipVisibility = false);
|
||||
|
||||
void DespawnOrUnsummon(uint32 msTimeToDespawn = 0);
|
||||
|
||||
time_t const& GetRespawnTime() const { return m_respawnTime; }
|
||||
time_t GetRespawnTimeEx() const;
|
||||
void SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? time(NULL) + respawn : 0; }
|
||||
void Respawn(bool force = false);
|
||||
void SaveRespawnTime();
|
||||
|
||||
uint32 GetRespawnDelay() const { return m_respawnDelay; }
|
||||
void SetRespawnDelay(uint32 delay) { m_respawnDelay = delay; }
|
||||
|
||||
float GetRespawnRadius() const { return m_respawnradius; }
|
||||
void SetRespawnRadius(float dist) { m_respawnradius = dist; }
|
||||
|
||||
uint32 m_groupLootTimer; // (msecs)timer used for group loot
|
||||
uint32 lootingGroupLowGUID; // used to find group which is looting corpse
|
||||
|
||||
void SendZoneUnderAttackMessage(Player* attacker);
|
||||
|
||||
void SetInCombatWithZone();
|
||||
|
||||
bool hasQuest(uint32 quest_id) const;
|
||||
bool hasInvolvedQuest(uint32 quest_id) const;
|
||||
|
||||
bool isRegeneratingHealth() { return m_regenHealth; }
|
||||
void SetRegeneratingHealth(bool c) { m_regenHealth = c; }
|
||||
virtual uint8 GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; }
|
||||
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
|
||||
{
|
||||
if (pos >= MAX_SPELL_CHARM || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED)
|
||||
return 0;
|
||||
else
|
||||
return m_charmInfo->GetCharmSpell(pos)->GetAction();
|
||||
}
|
||||
|
||||
void SetPosition(float x, float y, float z, float o);
|
||||
void SetPosition(const Position &pos) { SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); }
|
||||
|
||||
void SetHomePosition(float x, float y, float z, float o) { m_homePosition.Relocate(x, y, z, o); }
|
||||
void SetHomePosition(const Position &pos) { m_homePosition.Relocate(pos); }
|
||||
void GetHomePosition(float& x, float& y, float& z, float& ori) const { m_homePosition.GetPosition(x, y, z, ori); }
|
||||
Position const& GetHomePosition() const { return m_homePosition; }
|
||||
|
||||
void SetTransportHomePosition(float x, float y, float z, float o) { m_transportHomePosition.Relocate(x, y, z, o); }
|
||||
void SetTransportHomePosition(const Position &pos) { m_transportHomePosition.Relocate(pos); }
|
||||
void GetTransportHomePosition(float& x, float& y, float& z, float& ori) const { m_transportHomePosition.GetPosition(x, y, z, ori); }
|
||||
Position const& GetTransportHomePosition() const { return m_transportHomePosition; }
|
||||
|
||||
uint32 GetWaypointPath() const { return m_path_id; }
|
||||
void LoadPath(uint32 pathid) { m_path_id = pathid; }
|
||||
|
||||
uint32 GetCurrentWaypointID() const { return m_waypointID; }
|
||||
void UpdateWaypointID(uint32 wpID){ m_waypointID = wpID; }
|
||||
|
||||
void SearchFormation();
|
||||
CreatureGroup* GetFormation() const { return m_formation; }
|
||||
void SetFormation(CreatureGroup* formation) { m_formation = formation; }
|
||||
|
||||
Unit* SelectVictim();
|
||||
|
||||
void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; }
|
||||
bool IsReputationGainDisabled() const { return DisableReputationGain; }
|
||||
bool IsDamageEnoughForLootingAndReward() const { return m_PlayerDamageReq == 0; }
|
||||
void LowerPlayerDamageReq(uint32 unDamage)
|
||||
{
|
||||
if (m_PlayerDamageReq)
|
||||
m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0;
|
||||
}
|
||||
void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; }
|
||||
uint32 m_PlayerDamageReq;
|
||||
|
||||
uint32 GetOriginalEntry() const { return m_originalEntry; }
|
||||
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
|
||||
|
||||
static float _GetDamageMod(int32 Rank);
|
||||
|
||||
float m_SightDistance, m_CombatDistance;
|
||||
|
||||
bool m_isTempWorldObject; //true when possessed
|
||||
|
||||
// Handling caster facing during spellcast
|
||||
void SetTarget(uint64 guid);
|
||||
void FocusTarget(Spell const* focusSpell, WorldObject const* target);
|
||||
void ReleaseFocus(Spell const* focusSpell);
|
||||
|
||||
// Part of Evade mechanics
|
||||
time_t GetLastDamagedTime() const { return _lastDamagedTime; }
|
||||
void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; }
|
||||
|
||||
protected:
|
||||
bool CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = NULL);
|
||||
bool InitEntry(uint32 entry, const CreatureData* data=NULL);
|
||||
|
||||
// vendor items
|
||||
VendorItemCounts m_vendorItemCounts;
|
||||
|
||||
static float _GetHealthMod(int32 Rank);
|
||||
|
||||
uint64 m_lootRecipient;
|
||||
uint32 m_lootRecipientGroup;
|
||||
|
||||
/// Timers
|
||||
time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance
|
||||
time_t m_respawnTime; // (secs) time of next respawn
|
||||
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
|
||||
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
|
||||
float m_respawnradius;
|
||||
uint16 m_transportCheckTimer;
|
||||
uint32 lootPickPocketRestoreTime;
|
||||
|
||||
ReactStates m_reactState; // for AI, not charmInfo
|
||||
void RegenerateHealth();
|
||||
void Regenerate(Powers power);
|
||||
MovementGeneratorType m_defaultMovementType;
|
||||
uint32 m_DBTableGuid; ///< For new or temporary creatures is 0 for saved it is lowguid
|
||||
uint8 m_equipmentId;
|
||||
int8 m_originalEquipmentId; // can be -1
|
||||
|
||||
bool m_AlreadyCallAssistance;
|
||||
bool m_AlreadySearchedAssistance;
|
||||
bool m_regenHealth;
|
||||
bool m_AI_locked;
|
||||
|
||||
SpellSchoolMask m_meleeDamageSchoolMask;
|
||||
uint32 m_originalEntry;
|
||||
|
||||
bool m_moveInLineOfSightDisabled;
|
||||
bool m_moveInLineOfSightStrictlyDisabled;
|
||||
|
||||
Position m_homePosition;
|
||||
Position m_transportHomePosition;
|
||||
|
||||
bool DisableReputationGain;
|
||||
|
||||
CreatureTemplate const* m_creatureInfo; // in difficulty mode > 0 can different from sObjectMgr->GetCreatureTemplate(GetEntry())
|
||||
CreatureData const* m_creatureData;
|
||||
|
||||
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
|
||||
|
||||
bool IsInvisibleDueToDespawn() const;
|
||||
bool CanAlwaysSee(WorldObject const* obj) const;
|
||||
|
||||
private:
|
||||
void ForcedDespawn(uint32 timeMSToDespawn = 0);
|
||||
|
||||
//WaypointMovementGenerator vars
|
||||
uint32 m_waypointID;
|
||||
uint32 m_path_id;
|
||||
|
||||
//Formation var
|
||||
CreatureGroup* m_formation;
|
||||
bool TriggerJustRespawned;
|
||||
|
||||
time_t _lastDamagedTime; // Part of Evade mechanics
|
||||
|
||||
Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
|
||||
};
|
||||
|
||||
class AssistDelayEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
AssistDelayEvent(uint64 victim, Unit& owner) : BasicEvent(), m_victim(victim), m_owner(owner) { }
|
||||
|
||||
bool Execute(uint64 e_time, uint32 p_time);
|
||||
void AddAssistant(uint64 guid) { m_assistants.push_back(guid); }
|
||||
private:
|
||||
AssistDelayEvent();
|
||||
|
||||
uint64 m_victim;
|
||||
std::list<uint64> m_assistants;
|
||||
Unit& m_owner;
|
||||
};
|
||||
|
||||
class ForcedDespawnDelayEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
ForcedDespawnDelayEvent(Creature& owner) : BasicEvent(), m_owner(owner) { }
|
||||
bool Execute(uint64 e_time, uint32 p_time);
|
||||
|
||||
private:
|
||||
Creature& m_owner;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,277 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Creature.h"
|
||||
#include "CreatureGroups.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "MoveSplineInit.h"
|
||||
|
||||
FormationMgr::~FormationMgr()
|
||||
{
|
||||
for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
void FormationMgr::AddCreatureToGroup(uint32 groupId, Creature* member)
|
||||
{
|
||||
Map* map = member->FindMap();
|
||||
if (!map)
|
||||
return;
|
||||
|
||||
CreatureGroupHolderType::iterator itr = map->CreatureGroupHolder.find(groupId);
|
||||
|
||||
//Add member to an existing group
|
||||
if (itr != map->CreatureGroupHolder.end())
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Group found: %u, inserting creature GUID: %u, Group InstanceID %u", groupId, member->GetGUIDLow(), member->GetInstanceId());
|
||||
itr->second->AddMember(member);
|
||||
}
|
||||
//Create new group
|
||||
else
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Group not found: %u. Creating new group.", groupId);
|
||||
CreatureGroup* group = new CreatureGroup(groupId);
|
||||
map->CreatureGroupHolder[groupId] = group;
|
||||
group->AddMember(member);
|
||||
}
|
||||
}
|
||||
|
||||
void FormationMgr::RemoveCreatureFromGroup(CreatureGroup* group, Creature* member)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Deleting member pointer to GUID: %u from group %u", group->GetId(), member->GetDBTableGUIDLow());
|
||||
group->RemoveMember(member);
|
||||
|
||||
if (group->isEmpty())
|
||||
{
|
||||
Map* map = member->FindMap();
|
||||
if (!map)
|
||||
return;
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Deleting group with InstanceID %u", member->GetInstanceId());
|
||||
map->CreatureGroupHolder.erase(group->GetId());
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
|
||||
void FormationMgr::LoadCreatureFormations()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr) // for reload case
|
||||
delete itr->second;
|
||||
CreatureGroupMap.clear();
|
||||
|
||||
//Get group data
|
||||
QueryResult result = WorldDatabase.Query("SELECT leaderGUID, memberGUID, dist, angle, groupAI, point_1, point_2 FROM creature_formations ORDER BY leaderGUID");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outErrorDb(">> Loaded 0 creatures in formations. DB table `creature_formations` is empty!");
|
||||
sLog->outString();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
Field* fields;
|
||||
FormationInfo* group_member;
|
||||
|
||||
do
|
||||
{
|
||||
fields = result->Fetch();
|
||||
|
||||
//Load group member data
|
||||
group_member = new FormationInfo();
|
||||
group_member->leaderGUID = fields[0].GetUInt32();
|
||||
uint32 memberGUID = fields[1].GetUInt32();
|
||||
group_member->groupAI = fields[4].GetUInt32();
|
||||
group_member->point_1 = fields[5].GetUInt16();
|
||||
group_member->point_2 = fields[6].GetUInt16();
|
||||
//If creature is group leader we may skip loading of dist/angle
|
||||
if (group_member->leaderGUID != memberGUID)
|
||||
{
|
||||
group_member->follow_dist = fields[2].GetFloat();
|
||||
group_member->follow_angle = fields[3].GetFloat() * M_PI / 180;
|
||||
}
|
||||
else
|
||||
{
|
||||
group_member->follow_dist = 0;
|
||||
group_member->follow_angle = 0;
|
||||
}
|
||||
|
||||
// check data correctness
|
||||
{
|
||||
if (!sObjectMgr->GetCreatureData(group_member->leaderGUID))
|
||||
{
|
||||
sLog->outErrorDb("creature_formations table leader guid %u incorrect (not exist)", group_member->leaderGUID);
|
||||
delete group_member;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sObjectMgr->GetCreatureData(memberGUID))
|
||||
{
|
||||
sLog->outErrorDb("creature_formations table member guid %u incorrect (not exist)", memberGUID);
|
||||
delete group_member;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
CreatureGroupMap[memberGUID] = group_member;
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u creatures in formations in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
void CreatureGroup::AddMember(Creature* member)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "CreatureGroup::AddMember: Adding unit GUID: %u.", member->GetGUIDLow());
|
||||
|
||||
//Check if it is a leader
|
||||
if (member->GetDBTableGUIDLow() == m_groupID)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Unit GUID: %u is formation leader. Adding group.", member->GetGUIDLow());
|
||||
m_leader = member;
|
||||
}
|
||||
|
||||
m_members[member] = sFormationMgr->CreatureGroupMap.find(member->GetDBTableGUIDLow())->second;
|
||||
member->SetFormation(this);
|
||||
}
|
||||
|
||||
void CreatureGroup::RemoveMember(Creature* member)
|
||||
{
|
||||
if (m_leader == member)
|
||||
m_leader = NULL;
|
||||
|
||||
m_members.erase(member);
|
||||
member->SetFormation(NULL);
|
||||
}
|
||||
|
||||
void CreatureGroup::MemberAttackStart(Creature* member, Unit* target)
|
||||
{
|
||||
uint8 groupAI = sFormationMgr->CreatureGroupMap[member->GetDBTableGUIDLow()]->groupAI;
|
||||
if (!groupAI)
|
||||
return;
|
||||
|
||||
if (groupAI == 1 && member != m_leader)
|
||||
return;
|
||||
|
||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
||||
{
|
||||
//if (m_leader) // avoid crash if leader was killed and reset.
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "GROUP ATTACK: group instance id %u calls member instid %u", m_leader->GetInstanceId(), member->GetInstanceId());
|
||||
|
||||
//Skip one check
|
||||
if (itr->first == member)
|
||||
continue;
|
||||
|
||||
if (!itr->first->IsAlive())
|
||||
continue;
|
||||
|
||||
if (itr->first->GetVictim())
|
||||
continue;
|
||||
|
||||
if (itr->first->IsValidAttackTarget(target) && itr->first->AI())
|
||||
itr->first->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureGroup::FormationReset(bool dismiss)
|
||||
{
|
||||
if (m_members.size() && m_members.begin()->second->groupAI == 5)
|
||||
return;
|
||||
|
||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
||||
{
|
||||
if (itr->first != m_leader && itr->first->IsAlive())
|
||||
{
|
||||
if (dismiss)
|
||||
itr->first->GetMotionMaster()->Initialize();
|
||||
else
|
||||
itr->first->GetMotionMaster()->MoveIdle();
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Set %s movement for member GUID: %u", dismiss ? "default" : "idle", itr->first->GetGUIDLow());
|
||||
}
|
||||
}
|
||||
m_Formed = !dismiss;
|
||||
}
|
||||
|
||||
void CreatureGroup::LeaderMoveTo(float x, float y, float z, bool run)
|
||||
{
|
||||
//! To do: This should probably get its own movement generator or use WaypointMovementGenerator.
|
||||
//! If the leader's path is known, member's path can be plotted as well using formation offsets.
|
||||
if (!m_leader)
|
||||
return;
|
||||
|
||||
uint8 groupAI = sFormationMgr->CreatureGroupMap[m_leader->GetDBTableGUIDLow()]->groupAI;
|
||||
if (groupAI == 5)
|
||||
return;
|
||||
|
||||
float pathDist = m_leader->GetExactDist(x, y, z);
|
||||
float pathAngle = m_leader->GetAngle(x, y);
|
||||
|
||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
||||
{
|
||||
Creature* member = itr->first;
|
||||
if (member == m_leader || !member->IsAlive() || member->GetVictim())
|
||||
continue;
|
||||
|
||||
// Xinef: If member is stunned / rooted etc don't allow to move him
|
||||
if (member->HasUnitState(UNIT_STATE_NOT_MOVE))
|
||||
continue;
|
||||
|
||||
// Xinef: this should be automatized, if turn angle is greater than PI/2 (90°) we should swap formation angle
|
||||
if (M_PI - fabs(fabs(m_leader->GetOrientation() - pathAngle) - M_PI) > M_PI*0.50f)
|
||||
{
|
||||
// pussywizard: in both cases should be 2*M_PI - follow_angle
|
||||
// pussywizard: also, GetCurrentWaypointID() returns 0..n-1, while point_1 must be > 0, so +1
|
||||
// pussywizard: db table waypoint_data shouldn't have point id 0 and shouldn't have any gaps for this to work!
|
||||
// if (m_leader->GetCurrentWaypointID()+1 == itr->second->point_1 || m_leader->GetCurrentWaypointID()+1 == itr->second->point_2)
|
||||
itr->second->follow_angle = Position::NormalizeOrientation(itr->second->follow_angle + M_PI); //(2 * M_PI) - itr->second->follow_angle;
|
||||
}
|
||||
|
||||
float followAngle = itr->second->follow_angle;
|
||||
float followDist = itr->second->follow_dist;
|
||||
|
||||
float dx = x + cos(followAngle + pathAngle) * followDist;
|
||||
float dy = y + sin(followAngle + pathAngle) * followDist;
|
||||
float dz = z;
|
||||
|
||||
Trinity::NormalizeMapCoord(dx);
|
||||
Trinity::NormalizeMapCoord(dy);
|
||||
|
||||
member->UpdateGroundPositionZ(dx, dy, dz);
|
||||
|
||||
member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
|
||||
// pussywizard: setting the same movementflags is not enough, spline decides whether leader walks/runs, so spline param is now passed as "run" parameter to this function
|
||||
if (run && member->IsWalking())
|
||||
member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
else if (!run && !member->IsWalking())
|
||||
member->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
|
||||
// xinef: if we move members to position without taking care of sizes, we should compare distance without sizes
|
||||
// xinef: change members speed basing on distance - if too far speed up, if too close slow down
|
||||
UnitMoveType mtype = Movement::SelectSpeedType(member->GetUnitMovementFlags());
|
||||
member->SetSpeedRate(mtype, m_leader->GetSpeedRate(mtype) * member->GetExactDist(dx, dy, dz) / pathDist);
|
||||
|
||||
member->GetMotionMaster()->MovePoint(0, dx, dy, dz);
|
||||
member->SetHomePosition(dx, dy, dz, pathAngle);
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FORMATIONS_H
|
||||
#define _FORMATIONS_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "UnorderedMap.h"
|
||||
#include <map>
|
||||
|
||||
class Creature;
|
||||
class CreatureGroup;
|
||||
|
||||
struct FormationInfo
|
||||
{
|
||||
uint32 leaderGUID;
|
||||
float follow_dist;
|
||||
float follow_angle;
|
||||
uint8 groupAI;
|
||||
uint16 point_1;
|
||||
uint16 point_2;
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32/*memberDBGUID*/, FormationInfo*> CreatureGroupInfoType;
|
||||
|
||||
class FormationMgr
|
||||
{
|
||||
friend class ACE_Singleton<FormationMgr, ACE_Null_Mutex>;
|
||||
public:
|
||||
FormationMgr() { }
|
||||
~FormationMgr();
|
||||
void AddCreatureToGroup(uint32 group_id, Creature* creature);
|
||||
void RemoveCreatureFromGroup(CreatureGroup* group, Creature* creature);
|
||||
void LoadCreatureFormations();
|
||||
CreatureGroupInfoType CreatureGroupMap;
|
||||
};
|
||||
|
||||
class CreatureGroup
|
||||
{
|
||||
public:
|
||||
// pussywizard: moved public to the top so it compiles and typedef is public
|
||||
typedef std::map<Creature*, FormationInfo*> CreatureGroupMemberType;
|
||||
|
||||
//Group cannot be created empty
|
||||
explicit CreatureGroup(uint32 id) : m_leader(NULL), m_groupID(id), m_Formed(false) {}
|
||||
~CreatureGroup() {}
|
||||
|
||||
Creature* getLeader() const { return m_leader; }
|
||||
uint32 GetId() const { return m_groupID; }
|
||||
bool isEmpty() const { return m_members.empty(); }
|
||||
bool isFormed() const { return m_Formed; }
|
||||
const CreatureGroupMemberType& GetMembers() const { return m_members; }
|
||||
|
||||
void AddMember(Creature* member);
|
||||
void RemoveMember(Creature* member);
|
||||
void FormationReset(bool dismiss);
|
||||
|
||||
void LeaderMoveTo(float x, float y, float z, bool run);
|
||||
void MemberAttackStart(Creature* member, Unit* target);
|
||||
|
||||
private:
|
||||
Creature* m_leader; //Important do not forget sometimes to work with pointers instead synonims :D:D
|
||||
CreatureGroupMemberType m_members;
|
||||
|
||||
uint32 m_groupID;
|
||||
bool m_Formed;
|
||||
};
|
||||
|
||||
#define sFormationMgr ACE_Singleton<FormationMgr, ACE_Null_Mutex>::instance()
|
||||
|
||||
#endif
|
||||
@@ -1,538 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QuestDef.h"
|
||||
#include "GossipDef.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Formulas.h"
|
||||
|
||||
GossipMenu::GossipMenu()
|
||||
{
|
||||
_menuId = 0;
|
||||
}
|
||||
|
||||
GossipMenu::~GossipMenu()
|
||||
{
|
||||
ClearMenu();
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(int32 menuItemId, uint8 icon, std::string const& message, uint32 sender, uint32 action, std::string const& boxMessage, uint32 boxMoney, bool coded /*= false*/)
|
||||
{
|
||||
//TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
ASSERT(_menuItems.size() <= GOSSIP_MAX_MENU_ITEMS);
|
||||
|
||||
// Find a free new id - script case
|
||||
if (menuItemId == -1)
|
||||
{
|
||||
menuItemId = 0;
|
||||
if (!_menuItems.empty())
|
||||
{
|
||||
for (GossipMenuItemContainer::const_iterator itr = _menuItems.begin(); itr != _menuItems.end(); ++itr)
|
||||
{
|
||||
if (int32(itr->first) > menuItemId)
|
||||
break;
|
||||
|
||||
menuItemId = itr->first + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GossipMenuItem& menuItem = _menuItems[menuItemId];
|
||||
|
||||
menuItem.MenuItemIcon = icon;
|
||||
menuItem.Message = message;
|
||||
menuItem.IsCoded = coded;
|
||||
menuItem.Sender = sender;
|
||||
menuItem.OptionType = action;
|
||||
menuItem.BoxMessage = boxMessage;
|
||||
menuItem.BoxMoney = boxMoney;
|
||||
}
|
||||
|
||||
void GossipMenu::AddGossipMenuItemData(uint32 menuItemId, uint32 gossipActionMenuId, uint32 gossipActionPoi)
|
||||
{
|
||||
//TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
GossipMenuItemData& itemData = _menuItemData[menuItemId];
|
||||
|
||||
itemData.GossipActionMenuId = gossipActionMenuId;
|
||||
itemData.GossipActionPoi = gossipActionPoi;
|
||||
}
|
||||
|
||||
uint32 GossipMenu::GetMenuItemSender(uint32 menuItemId) const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
GossipMenuItemContainer::const_iterator itr = _menuItems.find(menuItemId);
|
||||
if (itr == _menuItems.end())
|
||||
return 0;
|
||||
|
||||
return itr->second.Sender;
|
||||
}
|
||||
|
||||
uint32 GossipMenu::GetMenuItemAction(uint32 menuItemId) const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
GossipMenuItemContainer::const_iterator itr = _menuItems.find(menuItemId);
|
||||
if (itr == _menuItems.end())
|
||||
return 0;
|
||||
|
||||
return itr->second.OptionType;
|
||||
}
|
||||
|
||||
bool GossipMenu::IsMenuItemCoded(uint32 menuItemId) const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
GossipMenuItemContainer::const_iterator itr = _menuItems.find(menuItemId);
|
||||
if (itr == _menuItems.end())
|
||||
return false;
|
||||
|
||||
return itr->second.IsCoded;
|
||||
}
|
||||
|
||||
void GossipMenu::ClearMenu()
|
||||
{
|
||||
//TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
_menuItems.clear();
|
||||
_menuItemData.clear();
|
||||
}
|
||||
|
||||
PlayerMenu::PlayerMenu(WorldSession* session) : _session(session)
|
||||
{
|
||||
}
|
||||
|
||||
PlayerMenu::~PlayerMenu()
|
||||
{
|
||||
ClearMenus();
|
||||
}
|
||||
|
||||
void PlayerMenu::ClearMenus()
|
||||
{
|
||||
_gossipMenu.ClearMenu();
|
||||
_questMenu.ClearMenu();
|
||||
}
|
||||
|
||||
void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const
|
||||
{
|
||||
//ACE_Read_Guard<ACE_RW_Thread_Mutex> lock1(_gossipMenu.GetLock());
|
||||
//ACE_Read_Guard<ACE_RW_Thread_Mutex> lock2(_questMenu.GetLock());
|
||||
|
||||
WorldPacket data(SMSG_GOSSIP_MESSAGE, 24 + _gossipMenu.GetMenuItemCount()*100 + _questMenu.GetMenuItemCount()*75); // guess size
|
||||
data << uint64(objectGUID);
|
||||
data << uint32(_gossipMenu.GetMenuId()); // new 2.4.0
|
||||
data << uint32(titleTextId);
|
||||
data << uint32(_gossipMenu.GetMenuItemCount()); // max count 0x10
|
||||
|
||||
for (GossipMenuItemContainer::const_iterator itr = _gossipMenu.GetMenuItems().begin(); itr != _gossipMenu.GetMenuItems().end(); ++itr)
|
||||
{
|
||||
GossipMenuItem const& item = itr->second;
|
||||
data << uint32(itr->first);
|
||||
data << uint8(item.MenuItemIcon);
|
||||
data << uint8(item.IsCoded); // makes pop up box password
|
||||
data << uint32(item.BoxMoney); // money required to open menu, 2.0.3
|
||||
data << item.Message; // text for gossip item
|
||||
data << item.BoxMessage; // accept text (related to money) pop up box, 2.0.3
|
||||
}
|
||||
|
||||
data << uint32(_questMenu.GetMenuItemCount()); // max count 0x20
|
||||
|
||||
for (uint32 iI = 0; iI < _questMenu.GetMenuItemCount(); ++iI)
|
||||
{
|
||||
QuestMenuItem const& item = _questMenu.GetItem(iI);
|
||||
uint32 questID = item.QuestId;
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questID);
|
||||
|
||||
data << uint32(questID);
|
||||
data << uint32(item.QuestIcon);
|
||||
data << int32(quest->GetQuestLevel());
|
||||
data << uint32(quest->GetFlags()); // 3.3.3 quest flags
|
||||
data << uint8(0); // 3.3.3 changes icon: blue question or yellow exclamation
|
||||
data << quest->GetTitle(); // max 0x200
|
||||
}
|
||||
|
||||
_session->SendPacket(&data);
|
||||
}
|
||||
|
||||
void PlayerMenu::SendCloseGossip() const
|
||||
{
|
||||
WorldPacket data(SMSG_GOSSIP_COMPLETE, 0);
|
||||
_session->SendPacket(&data);
|
||||
}
|
||||
|
||||
void PlayerMenu::SendPointOfInterest(uint32 poiId) const
|
||||
{
|
||||
PointOfInterest const* poi = sObjectMgr->GetPointOfInterest(poiId);
|
||||
if (!poi)
|
||||
{
|
||||
sLog->outErrorDb("Request to send non-existing POI (Id: %u), ignored.", poiId);
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_GOSSIP_POI, 4 + 4 + 4 + 4 + 4 + 20); // guess size
|
||||
data << uint32(poi->flags);
|
||||
data << float(poi->x);
|
||||
data << float(poi->y);
|
||||
data << uint32(poi->icon);
|
||||
data << uint32(poi->data);
|
||||
data << poi->icon_name;
|
||||
|
||||
_session->SendPacket(&data);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** QUEST SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
QuestMenu::QuestMenu()
|
||||
{
|
||||
_questMenuItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use
|
||||
}
|
||||
|
||||
QuestMenu::~QuestMenu()
|
||||
{
|
||||
ClearMenu();
|
||||
}
|
||||
|
||||
void QuestMenu::AddMenuItem(uint32 QuestId, uint8 Icon)
|
||||
{
|
||||
if (!sObjectMgr->GetQuestTemplate(QuestId))
|
||||
return;
|
||||
|
||||
//TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
|
||||
ASSERT(_questMenuItems.size() <= GOSSIP_MAX_MENU_ITEMS);
|
||||
|
||||
QuestMenuItem questMenuItem;
|
||||
|
||||
questMenuItem.QuestId = QuestId;
|
||||
questMenuItem.QuestIcon = Icon;
|
||||
|
||||
_questMenuItems.push_back(questMenuItem);
|
||||
}
|
||||
|
||||
bool QuestMenu::HasItem(uint32 questId) const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
for (QuestMenuItemList::const_iterator i = _questMenuItems.begin(); i != _questMenuItems.end(); ++i)
|
||||
if (i->QuestId == questId)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QuestMenu::ClearMenu()
|
||||
{
|
||||
//TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
_questMenuItems.clear();
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string& Title, uint64 npcGUID)
|
||||
{
|
||||
WorldPacket data(SMSG_QUESTGIVER_QUEST_LIST, 100 + _questMenu.GetMenuItemCount()*75); // guess size
|
||||
data << uint64(npcGUID);
|
||||
data << Title;
|
||||
data << uint32(eEmote._Delay); // player emote
|
||||
data << uint32(eEmote._Emote); // NPC emote
|
||||
|
||||
size_t count_pos = data.wpos();
|
||||
data << uint8 (_questMenu.GetMenuItemCount());
|
||||
uint32 count = 0;
|
||||
for (; count < _questMenu.GetMenuItemCount(); ++count)
|
||||
{
|
||||
QuestMenuItem const& qmi = _questMenu.GetItem(count);
|
||||
|
||||
uint32 questID = qmi.QuestId;
|
||||
|
||||
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questID))
|
||||
{
|
||||
data << uint32(questID);
|
||||
data << uint32(qmi.QuestIcon);
|
||||
data << int32(quest->GetQuestLevel());
|
||||
data << uint32(quest->GetFlags()); // 3.3.3 quest flags
|
||||
data << uint8(0); // 3.3.3 changes icon: blue question or yellow exclamation
|
||||
data << quest->GetTitle();
|
||||
}
|
||||
}
|
||||
|
||||
data.put<uint8>(count_pos, count);
|
||||
_session->SendPacket(&data);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST NPC Guid=%u", GUID_LOPART(npcGUID));
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID) const
|
||||
{
|
||||
WorldPacket data(SMSG_QUESTGIVER_STATUS, 9);
|
||||
data << uint64(npcGUID);
|
||||
data << uint8(questStatus);
|
||||
|
||||
_session->SendPacket(&data);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC Guid=%u, status=%u", GUID_LOPART(npcGUID), questStatus);
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, bool activateAccept) const
|
||||
{
|
||||
WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 500); // guess size
|
||||
data << uint64(npcGUID);
|
||||
data << uint64(_session->GetPlayer()->GetDivider());
|
||||
data << uint32(quest->GetQuestId());
|
||||
data << quest->GetTitle();
|
||||
data << quest->GetDetails();
|
||||
data << quest->GetObjectives();
|
||||
data << uint8(activateAccept ? 1 : 0); // auto finish
|
||||
data << uint32(quest->GetFlags()); // 3.3.3 questFlags
|
||||
data << uint32(quest->GetSuggestedPlayers());
|
||||
data << uint8(0); // IsFinished? value is sent back to server in quest accept packet
|
||||
|
||||
if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
{
|
||||
data << uint32(0); // Rewarded chosen items hidden
|
||||
data << uint32(0); // Rewarded items hidden
|
||||
data << uint32(0); // Rewarded money hidden
|
||||
data << uint32(0); // Rewarded XP hidden
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(quest->GetRewChoiceItemsCount());
|
||||
for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
|
||||
{
|
||||
if (!quest->RewardChoiceItemId[i])
|
||||
continue;
|
||||
|
||||
data << uint32(quest->RewardChoiceItemId[i]);
|
||||
data << uint32(quest->RewardChoiceItemCount[i]);
|
||||
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[i]))
|
||||
data << uint32(itemTemplate->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0x00);
|
||||
}
|
||||
|
||||
data << uint32(quest->GetRewItemsCount());
|
||||
|
||||
for (uint32 i=0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
{
|
||||
if (!quest->RewardItemId[i])
|
||||
continue;
|
||||
|
||||
data << uint32(quest->RewardItemId[i]);
|
||||
data << uint32(quest->RewardItemIdCount[i]);
|
||||
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardItemId[i]))
|
||||
data << uint32(itemTemplate->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(quest->GetRewOrReqMoney());
|
||||
data << uint32(quest->XPValue(_session->GetPlayer()) * sWorld->getRate(RATE_XP_QUEST));
|
||||
}
|
||||
|
||||
// rewarded honor points. Multiply with 10 to satisfy client
|
||||
data << uint32(10 * quest->CalculateHonorGain(_session->GetPlayer()->GetQuestLevel(quest)));
|
||||
data << float(0.0f); // unk, honor multiplier?
|
||||
data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0)
|
||||
data << int32(quest->GetRewSpellCast()); // casted spell
|
||||
data << uint32(quest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
|
||||
data << uint32(quest->GetBonusTalents()); // bonus talents
|
||||
data << uint32(quest->GetRewArenaPoints()); // reward arena points
|
||||
data << uint32(0); // unk
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
data << uint32(quest->RewardFactionId[i]);
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
data << int32(quest->RewardFactionValueId[i]);
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
data << int32(quest->RewardFactionValueIdOverride[i]);
|
||||
|
||||
data << uint32(QUEST_EMOTE_COUNT);
|
||||
for (uint32 i = 0; i < QUEST_EMOTE_COUNT; ++i)
|
||||
{
|
||||
data << uint32(quest->DetailsEmote[i]);
|
||||
data << uint32(quest->DetailsEmoteDelay[i]); // DetailsEmoteDelay (in ms)
|
||||
}
|
||||
_session->SendPacket(&data);
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_QUEST_DETAILS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const
|
||||
{
|
||||
_session->SendPacket(&quest->queryData);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", quest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, bool enableNext) const
|
||||
{
|
||||
WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 400); // guess size
|
||||
data << uint64(npcGUID);
|
||||
data << uint32(quest->GetQuestId());
|
||||
data << quest->GetTitle();
|
||||
data << quest->GetOfferRewardText();
|
||||
|
||||
data << uint8(enableNext ? 1 : 0); // Auto Finish
|
||||
data << uint32(quest->GetFlags()); // 3.3.3 questFlags
|
||||
data << uint32(quest->GetSuggestedPlayers()); // SuggestedGroupNum
|
||||
|
||||
uint32 emoteCount = 0;
|
||||
for (uint32 i = 0; i < QUEST_EMOTE_COUNT; ++i)
|
||||
{
|
||||
if (quest->OfferRewardEmote[i] <= 0)
|
||||
break;
|
||||
++emoteCount;
|
||||
}
|
||||
|
||||
data << emoteCount; // Emote Count
|
||||
for (uint32 i = 0; i < emoteCount; ++i)
|
||||
{
|
||||
data << uint32(quest->OfferRewardEmoteDelay[i]); // Delay Emote
|
||||
data << uint32(quest->OfferRewardEmote[i]);
|
||||
}
|
||||
|
||||
data << uint32(quest->GetRewChoiceItemsCount());
|
||||
for (uint32 i=0; i < quest->GetRewChoiceItemsCount(); ++i)
|
||||
{
|
||||
data << uint32(quest->RewardChoiceItemId[i]);
|
||||
data << uint32(quest->RewardChoiceItemCount[i]);
|
||||
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[i]))
|
||||
data << uint32(itemTemplate->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(quest->GetRewItemsCount());
|
||||
for (uint32 i = 0; i < quest->GetRewItemsCount(); ++i)
|
||||
{
|
||||
data << uint32(quest->RewardItemId[i]);
|
||||
data << uint32(quest->RewardItemIdCount[i]);
|
||||
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardItemId[i]))
|
||||
data << uint32(itemTemplate->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(quest->GetRewOrReqMoney());
|
||||
data << uint32(quest->XPValue(_session->GetPlayer()) * sWorld->getRate(RATE_XP_QUEST));
|
||||
|
||||
// rewarded honor points. Multiply with 10 to satisfy client
|
||||
data << uint32(10 * quest->CalculateHonorGain(_session->GetPlayer()->GetQuestLevel(quest)));
|
||||
data << float(0.0f); // unk, honor multiplier?
|
||||
data << uint32(0x08); // unused by client?
|
||||
data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0)
|
||||
data << int32(quest->GetRewSpellCast()); // casted spell
|
||||
data << uint32(0); // unknown
|
||||
data << uint32(quest->GetBonusTalents()); // bonus talents
|
||||
data << uint32(quest->GetRewArenaPoints()); // arena points
|
||||
data << uint32(0);
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
|
||||
data << uint32(quest->RewardFactionId[i]);
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid in QuestFactionReward.dbc (zero based)?
|
||||
data << int32(quest->RewardFactionValueId[i]);
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward reputation override?
|
||||
data << uint32(quest->RewardFactionValueIdOverride[i]);
|
||||
|
||||
_session->SendPacket(&data);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, bool canComplete, bool closeOnCancel) const
|
||||
{
|
||||
// We can always call to RequestItems, but this packet only goes out if there are actually
|
||||
// items. Otherwise, we'll skip straight to the OfferReward
|
||||
|
||||
if (!quest->GetReqItemsCount() && canComplete)
|
||||
{
|
||||
SendQuestGiverOfferReward(quest, npcGUID, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Xinef: recheck completion on reward display
|
||||
Player* _player = _session->GetPlayer();
|
||||
QuestStatusMap::iterator qsitr = _player->getQuestStatusMap().find(quest->GetQuestId());
|
||||
if (qsitr != _player->getQuestStatusMap().end() && qsitr->second.Status == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
for (uint8 i=0; i<6; ++i)
|
||||
if (quest->RequiredItemId[i] && qsitr->second.ItemCount[i] < quest->RequiredItemCount[i])
|
||||
if (_player->GetItemCount(quest->RequiredItemId[i], false) >= quest->RequiredItemCount[i])
|
||||
qsitr->second.ItemCount[i] = quest->RequiredItemCount[i];
|
||||
|
||||
if (_player->CanCompleteQuest(quest->GetQuestId()))
|
||||
{
|
||||
_player->CompleteQuest(quest->GetQuestId());
|
||||
canComplete = true;
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_QUESTGIVER_REQUEST_ITEMS, 300); // guess size
|
||||
data << uint64(npcGUID);
|
||||
data << uint32(quest->GetQuestId());
|
||||
data << quest->GetTitle();
|
||||
data << quest->GetRequestItemsText();
|
||||
|
||||
data << uint32(0x00); // unknown
|
||||
|
||||
if (canComplete)
|
||||
data << quest->GetCompleteEmote();
|
||||
else
|
||||
data << quest->GetIncompleteEmote();
|
||||
|
||||
// Close Window after cancel
|
||||
if (closeOnCancel)
|
||||
data << uint32(0x01);
|
||||
else
|
||||
data << uint32(0x00);
|
||||
|
||||
data << uint32(quest->GetFlags()); // 3.3.3 questFlags
|
||||
data << uint32(quest->GetSuggestedPlayers()); // SuggestedGroupNum
|
||||
|
||||
// Required Money
|
||||
data << uint32(quest->GetRewOrReqMoney() < 0 ? -quest->GetRewOrReqMoney() : 0);
|
||||
|
||||
data << uint32(quest->GetReqItemsCount());
|
||||
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
if (!quest->RequiredItemId[i])
|
||||
continue;
|
||||
|
||||
data << uint32(quest->RequiredItemId[i]);
|
||||
data << uint32(quest->RequiredItemCount[i]);
|
||||
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
|
||||
data << uint32(itemTemplate->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
if (!canComplete)
|
||||
data << uint32(0x00);
|
||||
else
|
||||
data << uint32(0x03);
|
||||
|
||||
data << uint32(0x04);
|
||||
data << uint32(0x08);
|
||||
data << uint32(0x10);
|
||||
|
||||
_session->SendPacket(&data);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId());
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_GOSSIP_H
|
||||
#define AZEROTHCORE_GOSSIP_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "QuestDef.h"
|
||||
#include "NPCHandler.h"
|
||||
|
||||
class WorldSession;
|
||||
|
||||
#define GOSSIP_MAX_MENU_ITEMS 32
|
||||
#define DEFAULT_GOSSIP_MESSAGE 0xffffff
|
||||
|
||||
enum Gossip_Option
|
||||
{
|
||||
GOSSIP_OPTION_NONE = 0, //UNIT_NPC_FLAG_NONE (0)
|
||||
GOSSIP_OPTION_GOSSIP = 1, //UNIT_NPC_FLAG_GOSSIP (1)
|
||||
GOSSIP_OPTION_QUESTGIVER = 2, //UNIT_NPC_FLAG_QUESTGIVER (2)
|
||||
GOSSIP_OPTION_VENDOR = 3, //UNIT_NPC_FLAG_VENDOR (128)
|
||||
GOSSIP_OPTION_TAXIVENDOR = 4, //UNIT_NPC_FLAG_TAXIVENDOR (8192)
|
||||
GOSSIP_OPTION_TRAINER = 5, //UNIT_NPC_FLAG_TRAINER (16)
|
||||
GOSSIP_OPTION_SPIRITHEALER = 6, //UNIT_NPC_FLAG_SPIRITHEALER (16384)
|
||||
GOSSIP_OPTION_SPIRITGUIDE = 7, //UNIT_NPC_FLAG_SPIRITGUIDE (32768)
|
||||
GOSSIP_OPTION_INNKEEPER = 8, //UNIT_NPC_FLAG_INNKEEPER (65536)
|
||||
GOSSIP_OPTION_BANKER = 9, //UNIT_NPC_FLAG_BANKER (131072)
|
||||
GOSSIP_OPTION_PETITIONER = 10, //UNIT_NPC_FLAG_PETITIONER (262144)
|
||||
GOSSIP_OPTION_TABARDDESIGNER = 11, //UNIT_NPC_FLAG_TABARDDESIGNER (524288)
|
||||
GOSSIP_OPTION_BATTLEFIELD = 12, //UNIT_NPC_FLAG_BATTLEFIELDPERSON (1048576)
|
||||
GOSSIP_OPTION_AUCTIONEER = 13, //UNIT_NPC_FLAG_AUCTIONEER (2097152)
|
||||
GOSSIP_OPTION_STABLEPET = 14, //UNIT_NPC_FLAG_STABLE (4194304)
|
||||
GOSSIP_OPTION_ARMORER = 15, //UNIT_NPC_FLAG_ARMORER (4096)
|
||||
GOSSIP_OPTION_UNLEARNTALENTS = 16, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
|
||||
GOSSIP_OPTION_UNLEARNPETTALENTS = 17, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
|
||||
GOSSIP_OPTION_LEARNDUALSPEC = 18, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
|
||||
GOSSIP_OPTION_OUTDOORPVP = 19, //added by code (option for outdoor pvp creatures)
|
||||
GOSSIP_OPTION_MAX
|
||||
};
|
||||
|
||||
enum GossipOptionIcon
|
||||
{
|
||||
GOSSIP_ICON_CHAT = 0, // white chat bubble
|
||||
GOSSIP_ICON_VENDOR = 1, // brown bag
|
||||
GOSSIP_ICON_TAXI = 2, // flightmarker (paperplane)
|
||||
GOSSIP_ICON_TRAINER = 3, // brown book (trainer)
|
||||
GOSSIP_ICON_INTERACT_1 = 4, // golden interaction wheel
|
||||
GOSSIP_ICON_INTERACT_2 = 5, // golden interaction wheel
|
||||
GOSSIP_ICON_MONEY_BAG = 6, // brown bag (with gold coin in lower corner)
|
||||
GOSSIP_ICON_TALK = 7, // white chat bubble (with "..." inside)
|
||||
GOSSIP_ICON_TABARD = 8, // white tabard
|
||||
GOSSIP_ICON_BATTLE = 9, // two crossed swords
|
||||
GOSSIP_ICON_DOT = 10, // yellow dot/point
|
||||
GOSSIP_ICON_CHAT_11 = 11, // white chat bubble
|
||||
GOSSIP_ICON_CHAT_12 = 12, // white chat bubble
|
||||
GOSSIP_ICON_CHAT_13 = 13, // white chat bubble
|
||||
GOSSIP_ICON_UNK_14 = 14, // INVALID - DO NOT USE
|
||||
GOSSIP_ICON_UNK_15 = 15, // INVALID - DO NOT USE
|
||||
GOSSIP_ICON_CHAT_16 = 16, // white chat bubble
|
||||
GOSSIP_ICON_CHAT_17 = 17, // white chat bubble
|
||||
GOSSIP_ICON_CHAT_18 = 18, // white chat bubble
|
||||
GOSSIP_ICON_CHAT_19 = 19, // white chat bubble
|
||||
GOSSIP_ICON_CHAT_20 = 20, // white chat bubble
|
||||
GOSSIP_ICON_MAX
|
||||
};
|
||||
|
||||
//POI icons. Many more exist, list not complete.
|
||||
enum Poi_Icon
|
||||
{
|
||||
ICON_POI_BLANK = 0, // Blank (not visible)
|
||||
ICON_POI_GREY_AV_MINE = 1, // Grey mine lorry
|
||||
ICON_POI_RED_AV_MINE = 2, // Red mine lorry
|
||||
ICON_POI_BLUE_AV_MINE = 3, // Blue mine lorry
|
||||
ICON_POI_BWTOMB = 4, // Blue and White Tomb Stone
|
||||
ICON_POI_SMALL_HOUSE = 5, // Small house
|
||||
ICON_POI_GREYTOWER = 6, // Grey Tower
|
||||
ICON_POI_REDFLAG = 7, // Red Flag w/Yellow !
|
||||
ICON_POI_TOMBSTONE = 8, // Normal tomb stone (brown)
|
||||
ICON_POI_BWTOWER = 9, // Blue and White Tower
|
||||
ICON_POI_REDTOWER = 10, // Red Tower
|
||||
ICON_POI_BLUETOWER = 11, // Blue Tower
|
||||
ICON_POI_RWTOWER = 12, // Red and White Tower
|
||||
ICON_POI_REDTOMB = 13, // Red Tomb Stone
|
||||
ICON_POI_RWTOMB = 14, // Red and White Tomb Stone
|
||||
ICON_POI_BLUETOMB = 15, // Blue Tomb Stone
|
||||
ICON_POI_16 = 16, // Grey ?
|
||||
ICON_POI_17 = 17, // Blue/White ?
|
||||
ICON_POI_18 = 18, // Blue ?
|
||||
ICON_POI_19 = 19, // Red and White ?
|
||||
ICON_POI_20 = 20, // Red ?
|
||||
ICON_POI_GREYLOGS = 21, // Grey Wood Logs
|
||||
ICON_POI_BWLOGS = 22, // Blue and White Wood Logs
|
||||
ICON_POI_BLUELOGS = 23, // Blue Wood Logs
|
||||
ICON_POI_RWLOGS = 24, // Red and White Wood Logs
|
||||
ICON_POI_REDLOGS = 25, // Red Wood Logs
|
||||
ICON_POI_26 = 26, // Grey ?
|
||||
ICON_POI_27 = 27, // Blue and White ?
|
||||
ICON_POI_28 = 28, // Blue ?
|
||||
ICON_POI_29 = 29, // Red and White ?
|
||||
ICON_POI_30 = 30, // Red ?
|
||||
ICON_POI_GREYHOUSE = 31, // Grey House
|
||||
ICON_POI_BWHOUSE = 32, // Blue and White House
|
||||
ICON_POI_BLUEHOUSE = 33, // Blue House
|
||||
ICON_POI_RWHOUSE = 34, // Red and White House
|
||||
ICON_POI_REDHOUSE = 35, // Red House
|
||||
ICON_POI_GREYHORSE = 36, // Grey Horse
|
||||
ICON_POI_BWHORSE = 37, // Blue and White Horse
|
||||
ICON_POI_BLUEHORSE = 38, // Blue Horse
|
||||
ICON_POI_RWHORSE = 39, // Red and White Horse
|
||||
ICON_POI_REDHORSE = 40 // Red Horse
|
||||
};
|
||||
|
||||
struct GossipMenuItem
|
||||
{
|
||||
uint8 MenuItemIcon;
|
||||
bool IsCoded;
|
||||
std::string Message;
|
||||
uint32 Sender;
|
||||
uint32 OptionType;
|
||||
std::string BoxMessage;
|
||||
uint32 BoxMoney;
|
||||
};
|
||||
|
||||
// need an ordered container
|
||||
typedef std::map<uint32, GossipMenuItem> GossipMenuItemContainer;
|
||||
|
||||
struct GossipMenuItemData
|
||||
{
|
||||
uint32 GossipActionMenuId; // MenuId of the gossip triggered by this action
|
||||
uint32 GossipActionPoi;
|
||||
};
|
||||
|
||||
// need an ordered container
|
||||
typedef std::map<uint32, GossipMenuItemData> GossipMenuItemDataContainer;
|
||||
|
||||
struct QuestMenuItem
|
||||
{
|
||||
uint32 QuestId;
|
||||
uint8 QuestIcon;
|
||||
};
|
||||
|
||||
typedef std::vector<QuestMenuItem> QuestMenuItemList;
|
||||
|
||||
class GossipMenu
|
||||
{
|
||||
public:
|
||||
GossipMenu();
|
||||
~GossipMenu();
|
||||
|
||||
void AddMenuItem(int32 menuItemId, uint8 icon, std::string const& message, uint32 sender, uint32 action, std::string const& boxMessage, uint32 boxMoney, bool coded = false);
|
||||
|
||||
void SetMenuId(uint32 menu_id) { _menuId = menu_id; }
|
||||
uint32 GetMenuId() const { return _menuId; }
|
||||
|
||||
void AddGossipMenuItemData(uint32 menuItemId, uint32 gossipActionMenuId, uint32 gossipActionPoi);
|
||||
|
||||
uint32 GetMenuItemCount() const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
return _menuItems.size();
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
return _menuItems.empty();
|
||||
}
|
||||
|
||||
GossipMenuItem const* GetItem(uint32 id) const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
GossipMenuItemContainer::const_iterator itr = _menuItems.find(id);
|
||||
if (itr != _menuItems.end())
|
||||
return &itr->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GossipMenuItemData const* GetItemData(uint32 indexId) const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
GossipMenuItemDataContainer::const_iterator itr = _menuItemData.find(indexId);
|
||||
if (itr != _menuItemData.end())
|
||||
return &itr->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32 GetMenuItemSender(uint32 menuItemId) const;
|
||||
uint32 GetMenuItemAction(uint32 menuItemId) const;
|
||||
bool IsMenuItemCoded(uint32 menuItemId) const;
|
||||
|
||||
void ClearMenu();
|
||||
|
||||
GossipMenuItemContainer const& GetMenuItems() const
|
||||
{
|
||||
return _menuItems;
|
||||
}
|
||||
|
||||
//ACE_RW_Thread_Mutex& GetLock() const { return *(const_cast<ACE_RW_Thread_Mutex*>(&_menuLock)); }
|
||||
//ACE_RW_Thread_Mutex _menuLock; // pussywizard
|
||||
|
||||
private:
|
||||
GossipMenuItemContainer _menuItems;
|
||||
GossipMenuItemDataContainer _menuItemData;
|
||||
uint32 _menuId;
|
||||
};
|
||||
|
||||
class QuestMenu
|
||||
{
|
||||
public:
|
||||
QuestMenu();
|
||||
~QuestMenu();
|
||||
|
||||
void AddMenuItem(uint32 QuestId, uint8 Icon);
|
||||
void ClearMenu();
|
||||
|
||||
uint8 GetMenuItemCount() const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
return _questMenuItems.size();
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
return _questMenuItems.empty();
|
||||
}
|
||||
|
||||
bool HasItem(uint32 questId) const;
|
||||
|
||||
QuestMenuItem const& GetItem(uint16 index) const
|
||||
{
|
||||
//TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetLock());
|
||||
return _questMenuItems[index];
|
||||
}
|
||||
|
||||
//ACE_RW_Thread_Mutex& GetLock() const { return *(const_cast<ACE_RW_Thread_Mutex*>(&_menuLock)); }
|
||||
//ACE_RW_Thread_Mutex _menuLock; // pussywizard
|
||||
|
||||
private:
|
||||
QuestMenuItemList _questMenuItems;
|
||||
};
|
||||
|
||||
class PlayerMenu
|
||||
{
|
||||
public:
|
||||
explicit PlayerMenu(WorldSession* session);
|
||||
~PlayerMenu();
|
||||
|
||||
GossipMenu& GetGossipMenu() { return _gossipMenu; }
|
||||
QuestMenu& GetQuestMenu() { return _questMenu; }
|
||||
|
||||
bool Empty() const { return _gossipMenu.Empty() && _questMenu.Empty(); }
|
||||
|
||||
void ClearMenus();
|
||||
uint32 GetGossipOptionSender(uint32 selection) const { return _gossipMenu.GetMenuItemSender(selection); }
|
||||
uint32 GetGossipOptionAction(uint32 selection) const { return _gossipMenu.GetMenuItemAction(selection); }
|
||||
bool IsGossipOptionCoded(uint32 selection) const { return _gossipMenu.IsMenuItemCoded(selection); }
|
||||
|
||||
void SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const;
|
||||
void SendCloseGossip() const;
|
||||
void SendPointOfInterest(uint32 poiId) const;
|
||||
|
||||
/*********************************************************/
|
||||
/*** QUEST SYSTEM ***/
|
||||
/*********************************************************/
|
||||
void SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID) const;
|
||||
|
||||
void SendQuestGiverQuestList(QEmote const& eEmote, const std::string& Title, uint64 npcGUID);
|
||||
|
||||
void SendQuestQueryResponse(Quest const* quest) const;
|
||||
void SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, bool activateAccept) const;
|
||||
|
||||
void SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, bool enableNext) const;
|
||||
void SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, bool canComplete, bool closeOnCancel) const;
|
||||
|
||||
private:
|
||||
GossipMenu _gossipMenu;
|
||||
QuestMenu _questMenu;
|
||||
WorldSession* _session;
|
||||
};
|
||||
#endif
|
||||
@@ -1,435 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
|
||||
TempSummon::TempSummon(SummonPropertiesEntry const* properties, uint64 owner, bool isWorldObject) :
|
||||
Creature(isWorldObject), m_Properties(properties), m_type(TEMPSUMMON_MANUAL_DESPAWN),
|
||||
m_timer(0), m_lifetime(0)
|
||||
{
|
||||
m_summonerGUID = owner;
|
||||
m_unitTypeMask |= UNIT_MASK_SUMMON;
|
||||
}
|
||||
|
||||
Unit* TempSummon::GetSummoner() const
|
||||
{
|
||||
return m_summonerGUID ? ObjectAccessor::GetUnit(*this, m_summonerGUID) : NULL;
|
||||
}
|
||||
|
||||
void TempSummon::Update(uint32 diff)
|
||||
{
|
||||
Creature::Update(diff);
|
||||
|
||||
if (m_deathState == DEAD)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
switch (m_type)
|
||||
{
|
||||
case TEMPSUMMON_MANUAL_DESPAWN:
|
||||
case TEMPSUMMON_DESPAWNED:
|
||||
break;
|
||||
case TEMPSUMMON_TIMED_DESPAWN:
|
||||
{
|
||||
if (m_timer <= diff)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
m_timer -= diff;
|
||||
break;
|
||||
}
|
||||
case TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT:
|
||||
{
|
||||
if (!IsInCombat())
|
||||
{
|
||||
if (m_timer <= diff)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
m_timer -= diff;
|
||||
}
|
||||
else if (m_timer != m_lifetime)
|
||||
m_timer = m_lifetime;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TEMPSUMMON_CORPSE_TIMED_DESPAWN:
|
||||
{
|
||||
if (m_deathState == CORPSE)
|
||||
{
|
||||
if (m_timer <= diff)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
m_timer -= diff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TEMPSUMMON_CORPSE_DESPAWN:
|
||||
{
|
||||
// if m_deathState is DEAD, CORPSE was skipped
|
||||
if (m_deathState == CORPSE || m_deathState == DEAD)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TEMPSUMMON_DEAD_DESPAWN:
|
||||
{
|
||||
if (m_deathState == DEAD)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN:
|
||||
{
|
||||
// if m_deathState is DEAD, CORPSE was skipped
|
||||
if (m_deathState == CORPSE || m_deathState == DEAD)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsInCombat())
|
||||
{
|
||||
if (m_timer <= diff)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_timer -= diff;
|
||||
}
|
||||
else if (m_timer != m_lifetime)
|
||||
m_timer = m_lifetime;
|
||||
break;
|
||||
}
|
||||
case TEMPSUMMON_TIMED_OR_DEAD_DESPAWN:
|
||||
{
|
||||
// if m_deathState is DEAD, CORPSE was skipped
|
||||
if (m_deathState == DEAD)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsInCombat() && IsAlive())
|
||||
{
|
||||
if (m_timer <= diff)
|
||||
{
|
||||
UnSummon();
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_timer -= diff;
|
||||
}
|
||||
else if (m_timer != m_lifetime)
|
||||
m_timer = m_lifetime;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UnSummon();
|
||||
sLog->outError("Temporary summoned creature (entry: %u) have unknown type %u of ", GetEntry(), m_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TempSummon::InitStats(uint32 duration)
|
||||
{
|
||||
ASSERT(!IsPet());
|
||||
|
||||
m_timer = duration;
|
||||
m_lifetime = duration;
|
||||
|
||||
if (m_type == TEMPSUMMON_MANUAL_DESPAWN)
|
||||
m_type = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
||||
|
||||
Unit* owner = GetSummoner();
|
||||
if (owner)
|
||||
{
|
||||
if (IsTrigger() && m_spells[0])
|
||||
{
|
||||
setFaction(owner->getFaction());
|
||||
SetLevel(owner->getLevel());
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER)
|
||||
m_ControlledByPlayer = true;
|
||||
}
|
||||
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER)
|
||||
m_CreatedByPlayer = true;
|
||||
}
|
||||
|
||||
if (!m_Properties)
|
||||
return;
|
||||
|
||||
if (owner)
|
||||
{
|
||||
if (uint32 slot = m_Properties->Slot)
|
||||
{
|
||||
if (owner->m_SummonSlot[slot] && owner->m_SummonSlot[slot] != GetGUID())
|
||||
{
|
||||
Creature* oldSummon = GetMap()->GetCreature(owner->m_SummonSlot[slot]);
|
||||
if (oldSummon && oldSummon->IsSummon())
|
||||
oldSummon->ToTempSummon()->UnSummon();
|
||||
}
|
||||
owner->m_SummonSlot[slot] = GetGUID();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Properties->Faction)
|
||||
setFaction(m_Properties->Faction);
|
||||
else if (IsVehicle() && owner) // properties should be vehicle
|
||||
setFaction(owner->getFaction());
|
||||
}
|
||||
|
||||
void TempSummon::InitSummon()
|
||||
{
|
||||
Unit* owner = GetSummoner();
|
||||
if (owner)
|
||||
{
|
||||
if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled)
|
||||
owner->ToCreature()->AI()->JustSummoned(this);
|
||||
}
|
||||
|
||||
// Xinef: Allow to call this hook when npc is summoned by gameobject, in this case pass this as summoner to avoid possible null checks
|
||||
if (IsAIEnabled)
|
||||
AI()->IsSummonedBy(owner);
|
||||
}
|
||||
|
||||
void TempSummon::SetTempSummonType(TempSummonType type)
|
||||
{
|
||||
m_type = type;
|
||||
}
|
||||
|
||||
void TempSummon::UnSummon(uint32 msTime)
|
||||
{
|
||||
if (msTime)
|
||||
{
|
||||
ForcedUnsummonDelayEvent* pEvent = new ForcedUnsummonDelayEvent(*this);
|
||||
|
||||
m_Events.AddEvent(pEvent, m_Events.CalculateTime(msTime));
|
||||
return;
|
||||
}
|
||||
|
||||
// Dont allow to call this function twice (possible)
|
||||
if (m_type == TEMPSUMMON_DESPAWNED)
|
||||
return;
|
||||
SetTempSummonType(TEMPSUMMON_DESPAWNED);
|
||||
|
||||
//ASSERT(!IsPet());
|
||||
if (IsPet())
|
||||
{
|
||||
((Pet*)this)->Remove(PET_SAVE_NOT_IN_SLOT);
|
||||
ASSERT(!IsInWorld());
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* owner = GetSummoner();
|
||||
if (owner && owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled)
|
||||
owner->ToCreature()->AI()->SummonedCreatureDespawn(this);
|
||||
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
bool ForcedUnsummonDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
{
|
||||
m_owner.UnSummon();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TempSummon::RemoveFromWorld()
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
if (m_Properties)
|
||||
if (uint32 slot = m_Properties->Slot)
|
||||
if (Unit* owner = GetSummoner())
|
||||
if (owner->m_SummonSlot[slot] == GetGUID())
|
||||
owner->m_SummonSlot[slot] = 0;
|
||||
|
||||
//if (GetOwnerGUID())
|
||||
// sLog->outError("Unit %u has owner guid when removed from world", GetEntry());
|
||||
|
||||
Creature::RemoveFromWorld();
|
||||
}
|
||||
|
||||
Minion::Minion(SummonPropertiesEntry const* properties, uint64 owner, bool isWorldObject) : TempSummon(properties, owner, isWorldObject)
|
||||
, m_owner(owner)
|
||||
{
|
||||
ASSERT(m_owner);
|
||||
m_unitTypeMask |= UNIT_MASK_MINION;
|
||||
m_followAngle = PET_FOLLOW_ANGLE;
|
||||
}
|
||||
|
||||
void Minion::InitStats(uint32 duration)
|
||||
{
|
||||
TempSummon::InitStats(duration);
|
||||
|
||||
SetReactState(REACT_PASSIVE);
|
||||
|
||||
Unit *m_owner = GetOwner();
|
||||
SetCreatorGUID(m_owner->GetGUID());
|
||||
setFaction(m_owner->getFaction());
|
||||
|
||||
m_owner->SetMinion(this, true);
|
||||
}
|
||||
|
||||
void Minion::RemoveFromWorld()
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
if (Unit *owner = GetOwner())
|
||||
owner->SetMinion(this, false);
|
||||
|
||||
TempSummon::RemoveFromWorld();
|
||||
}
|
||||
|
||||
Unit* Minion::GetOwner() const
|
||||
{
|
||||
return ObjectAccessor::GetUnit(*this, m_owner);
|
||||
}
|
||||
|
||||
bool Minion::IsGuardianPet() const
|
||||
{
|
||||
return IsPet() || (m_Properties && m_Properties->Category == SUMMON_CATEGORY_PET);
|
||||
}
|
||||
|
||||
void Minion::setDeathState(DeathState s, bool despawn)
|
||||
{
|
||||
Creature::setDeathState(s, despawn);
|
||||
if (s == JUST_DIED && IsGuardianPet())
|
||||
if (Unit* owner = GetOwner())
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER && owner->GetMinionGUID() == GetGUID())
|
||||
for (Unit::ControlSet::const_iterator itr = owner->m_Controlled.begin(); itr != owner->m_Controlled.end(); ++itr)
|
||||
if ((*itr)->IsAlive() && (*itr)->GetEntry() == GetEntry())
|
||||
{
|
||||
owner->SetMinionGUID((*itr)->GetGUID());
|
||||
owner->SetPetGUID((*itr)->GetGUID());
|
||||
owner->ToPlayer()->CharmSpellInitialize();
|
||||
}
|
||||
}
|
||||
|
||||
Guardian::Guardian(SummonPropertiesEntry const* properties, uint64 owner, bool isWorldObject) : Minion(properties, owner, isWorldObject)
|
||||
{
|
||||
m_unitTypeMask |= UNIT_MASK_GUARDIAN;
|
||||
if (properties && properties->Type == SUMMON_TYPE_PET)
|
||||
{
|
||||
m_unitTypeMask |= UNIT_MASK_CONTROLABLE_GUARDIAN;
|
||||
InitCharmInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void Guardian::InitStats(uint32 duration)
|
||||
{
|
||||
Minion::InitStats(duration);
|
||||
|
||||
Unit *m_owner = GetOwner();
|
||||
InitStatsForLevel(m_owner->getLevel());
|
||||
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER && HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
|
||||
m_charmInfo->InitCharmCreateSpells();
|
||||
|
||||
SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
void Guardian::InitSummon()
|
||||
{
|
||||
TempSummon::InitSummon();
|
||||
|
||||
Unit *m_owner = GetOwner();
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER
|
||||
&& m_owner->GetMinionGUID() == GetGUID()
|
||||
&& !m_owner->GetCharmGUID())
|
||||
m_owner->ToPlayer()->CharmSpellInitialize();
|
||||
}
|
||||
|
||||
Puppet::Puppet(SummonPropertiesEntry const* properties, uint64 owner) : Minion(properties, owner, false), m_owner(owner) //maybe true?
|
||||
{
|
||||
ASSERT(IS_PLAYER_GUID(owner));
|
||||
m_unitTypeMask |= UNIT_MASK_PUPPET;
|
||||
}
|
||||
|
||||
void Puppet::InitStats(uint32 duration)
|
||||
{
|
||||
Minion::InitStats(duration);
|
||||
SetLevel(GetOwner()->getLevel());
|
||||
SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
void Puppet::InitSummon()
|
||||
{
|
||||
Minion::InitSummon();
|
||||
if (!SetCharmedBy(GetOwner(), CHARM_TYPE_POSSESS))
|
||||
{
|
||||
if (Player* p = GetOwner())
|
||||
sLog->outMisc("Puppet::InitSummon (A1) - %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u", p->GetTypeId(), p->GetEntry(), p->GetUnitTypeMask(), p->GetGUIDLow(), p->GetMapId(), p->GetInstanceId(), p->FindMap(), p->IsInWorld() ? 1 : 0, p->IsDuringRemoveFromWorld() ? 1 : 0, p->IsBeingTeleported() ? 1 : 0, p->isBeingLoaded() ? 1 : 0);
|
||||
else
|
||||
{
|
||||
sLog->outMisc("Puppet::InitSummon (B1)");
|
||||
//ASSERT(false); // ZOMG!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Puppet::Update(uint32 time)
|
||||
{
|
||||
Minion::Update(time);
|
||||
//check if caster is channelling?
|
||||
if (IsInWorld())
|
||||
{
|
||||
if (!IsAlive())
|
||||
{
|
||||
UnSummon();
|
||||
// TODO: why long distance .die does not remove it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Puppet::RemoveFromWorld()
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
RemoveCharmedBy(NULL);
|
||||
Minion::RemoveFromWorld();
|
||||
}
|
||||
|
||||
Player* Puppet::GetOwner() const
|
||||
{
|
||||
return ObjectAccessor::GetPlayer(*this, m_owner);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_TEMPSUMMON_H
|
||||
#define AZEROTHCORE_TEMPSUMMON_H
|
||||
|
||||
#include "Creature.h"
|
||||
|
||||
enum SummonerType
|
||||
{
|
||||
SUMMONER_TYPE_CREATURE = 0,
|
||||
SUMMONER_TYPE_GAMEOBJECT = 1,
|
||||
SUMMONER_TYPE_MAP = 2
|
||||
};
|
||||
|
||||
/// Stores data for temp summons
|
||||
struct TempSummonData
|
||||
{
|
||||
uint32 entry; ///< Entry of summoned creature
|
||||
Position pos; ///< Position, where should be creature spawned
|
||||
TempSummonType type; ///< Summon type, see TempSummonType for available types
|
||||
uint32 time; ///< Despawn time, usable only with certain temp summon types
|
||||
};
|
||||
|
||||
class TempSummon : public Creature
|
||||
{
|
||||
public:
|
||||
explicit TempSummon(SummonPropertiesEntry const* properties, uint64 owner, bool isWorldObject);
|
||||
virtual ~TempSummon() {}
|
||||
void Update(uint32 time);
|
||||
virtual void InitStats(uint32 lifetime);
|
||||
virtual void InitSummon();
|
||||
virtual void UnSummon(uint32 msTime = 0);
|
||||
void RemoveFromWorld();
|
||||
void SetTempSummonType(TempSummonType type);
|
||||
void SaveToDB(uint32 /*mapid*/, uint8 /*spawnMask*/, uint32 /*phaseMask*/) {}
|
||||
Unit* GetSummoner() const;
|
||||
uint64 GetSummonerGUID() { return m_summonerGUID; }
|
||||
TempSummonType const& GetSummonType() { return m_type; }
|
||||
uint32 GetTimer() { return m_timer; }
|
||||
void SetTimer(uint32 t) { m_timer = t; }
|
||||
|
||||
const SummonPropertiesEntry* const m_Properties;
|
||||
private:
|
||||
TempSummonType m_type;
|
||||
uint32 m_timer;
|
||||
uint32 m_lifetime;
|
||||
uint64 m_summonerGUID;
|
||||
};
|
||||
|
||||
class Minion : public TempSummon
|
||||
{
|
||||
public:
|
||||
Minion(SummonPropertiesEntry const* properties, uint64 owner, bool isWorldObject);
|
||||
void InitStats(uint32 duration);
|
||||
void RemoveFromWorld();
|
||||
Unit* GetOwner() const;
|
||||
float GetFollowAngle() const { return m_followAngle; }
|
||||
void SetFollowAngle(float angle) { m_followAngle = angle; }
|
||||
bool IsPetGhoul() const {return GetEntry() == 26125 /*normal ghoul*/ || GetEntry() == 30230 /*Raise Ally ghoul*/;} // Ghoul may be guardian or pet
|
||||
bool IsGuardianPet() const;
|
||||
void setDeathState(DeathState s, bool despawn = false); // override virtual Unit::setDeathState
|
||||
protected:
|
||||
const uint64 m_owner;
|
||||
float m_followAngle;
|
||||
};
|
||||
|
||||
class Guardian : public Minion
|
||||
{
|
||||
public:
|
||||
Guardian(SummonPropertiesEntry const* properties, uint64 owner, bool isWorldObject);
|
||||
void InitStats(uint32 duration);
|
||||
bool InitStatsForLevel(uint8 level);
|
||||
void InitSummon();
|
||||
|
||||
bool UpdateStats(Stats stat);
|
||||
bool UpdateAllStats();
|
||||
void UpdateArmor();
|
||||
void UpdateMaxHealth();
|
||||
void UpdateMaxPower(Powers power);
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false);
|
||||
void UpdateDamagePhysical(WeaponAttackType attType);
|
||||
};
|
||||
|
||||
class Puppet : public Minion
|
||||
{
|
||||
public:
|
||||
Puppet(SummonPropertiesEntry const* properties, uint64 owner);
|
||||
void InitStats(uint32 duration);
|
||||
void InitSummon();
|
||||
void Update(uint32 time);
|
||||
void RemoveFromWorld();
|
||||
protected:
|
||||
Player* GetOwner() const;
|
||||
const uint64 m_owner;
|
||||
};
|
||||
|
||||
class ForcedUnsummonDelayEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
ForcedUnsummonDelayEvent(TempSummon& owner) : BasicEvent(), m_owner(owner) { }
|
||||
bool Execute(uint64 e_time, uint32 p_time);
|
||||
|
||||
private:
|
||||
TempSummon& m_owner;
|
||||
};
|
||||
#endif
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "Opcodes.h"
|
||||
#include "World.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "Transport.h"
|
||||
|
||||
DynamicObject::DynamicObject(bool isWorldObject) : WorldObject(isWorldObject), MovableMapObject(),
|
||||
_aura(NULL), _removedAura(NULL), _caster(NULL), _duration(0), _isViewpoint(false)
|
||||
{
|
||||
m_objectType |= TYPEMASK_DYNAMICOBJECT;
|
||||
m_objectTypeId = TYPEID_DYNAMICOBJECT;
|
||||
|
||||
m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_POSITION);
|
||||
|
||||
m_valuesCount = DYNAMICOBJECT_END;
|
||||
}
|
||||
|
||||
DynamicObject::~DynamicObject()
|
||||
{
|
||||
// make sure all references were properly removed
|
||||
ASSERT(!_aura);
|
||||
ASSERT(!_caster);
|
||||
ASSERT(!_isViewpoint);
|
||||
delete _removedAura;
|
||||
}
|
||||
|
||||
void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */)
|
||||
{
|
||||
if (Transport* transport = GetTransport())
|
||||
{
|
||||
transport->RemovePassenger(this);
|
||||
SetTransport(NULL);
|
||||
m_movementInfo.transport.Reset();
|
||||
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
}
|
||||
|
||||
WorldObject::CleanupsBeforeDelete(finalCleanup);
|
||||
}
|
||||
|
||||
void DynamicObject::AddToWorld()
|
||||
{
|
||||
///- Register the dynamicObject for guid lookup and for caster
|
||||
if (!IsInWorld())
|
||||
{
|
||||
sObjectAccessor->AddObject(this);
|
||||
WorldObject::AddToWorld();
|
||||
BindToCaster();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveFromWorld()
|
||||
{
|
||||
///- Remove the dynamicObject from the accessor and from all lists of objects in world
|
||||
if (IsInWorld())
|
||||
{
|
||||
if (_isViewpoint)
|
||||
RemoveCasterViewpoint();
|
||||
|
||||
if (_aura)
|
||||
RemoveAura();
|
||||
|
||||
// dynobj could get removed in Aura::RemoveAura
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
UnbindFromCaster();
|
||||
if (Transport* transport = GetTransport())
|
||||
transport->RemovePassenger(this, true);
|
||||
WorldObject::RemoveFromWorld();
|
||||
sObjectAccessor->RemoveObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type)
|
||||
{
|
||||
SetMap(caster->GetMap());
|
||||
Relocate(pos);
|
||||
if (!IsPositionValid())
|
||||
{
|
||||
sLog->outError("DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", spellId, GetPositionX(), GetPositionY());
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask());
|
||||
|
||||
SetEntry(spellId);
|
||||
SetObjectScale(1);
|
||||
SetUInt64Value(DYNAMICOBJECT_CASTER, caster->GetGUID());
|
||||
|
||||
// The lower word of DYNAMICOBJECT_BYTES must be 0x0001. This value means that the visual radius will be overriden
|
||||
// by client for most of the "ground patch" visual effect spells and a few "skyfall" ones like Hurricane.
|
||||
// If any other value is used, the client will _always_ use the radius provided in DYNAMICOBJECT_RADIUS, but
|
||||
// precompensation is necessary (eg radius *= 2) for many spells. Anyway, blizz sends 0x0001 for all the spells
|
||||
// I saw sniffed...
|
||||
SetByteValue(DYNAMICOBJECT_BYTES, 0, type);
|
||||
SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId);
|
||||
SetFloatValue(DYNAMICOBJECT_RADIUS, radius);
|
||||
SetUInt32Value(DYNAMICOBJECT_CASTTIME, World::GetGameTimeMS());
|
||||
|
||||
if (IsWorldObject())
|
||||
setActive(true); //must before add to map to be put in world container
|
||||
|
||||
if (!GetMap()->AddToMap(this, true))
|
||||
{
|
||||
// Returning false will cause the object to be deleted - remove from transport
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DynamicObject::Update(uint32 p_time)
|
||||
{
|
||||
// caster has to be always available and in the same map
|
||||
ASSERT(_caster);
|
||||
ASSERT(_caster->GetMap() == GetMap());
|
||||
|
||||
bool expired = false;
|
||||
|
||||
if (_aura)
|
||||
{
|
||||
if (!_aura->IsRemoved())
|
||||
_aura->UpdateOwner(p_time, this);
|
||||
|
||||
// _aura may be set to null in Aura::UpdateOwner call
|
||||
if (_aura && (_aura->IsRemoved() || _aura->IsExpired()))
|
||||
expired = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetDuration() > int32(p_time))
|
||||
_duration -= p_time;
|
||||
else
|
||||
expired = true;
|
||||
}
|
||||
|
||||
if (expired)
|
||||
Remove();
|
||||
else
|
||||
sScriptMgr->OnDynamicObjectUpdate(this, p_time);
|
||||
}
|
||||
|
||||
void DynamicObject::Remove()
|
||||
{
|
||||
if (IsInWorld())
|
||||
{
|
||||
SendObjectDeSpawnAnim(GetGUID());
|
||||
RemoveFromWorld();
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
}
|
||||
|
||||
int32 DynamicObject::GetDuration() const
|
||||
{
|
||||
if (!_aura)
|
||||
return _duration;
|
||||
else
|
||||
return _aura->GetDuration();
|
||||
}
|
||||
|
||||
void DynamicObject::SetDuration(int32 newDuration)
|
||||
{
|
||||
if (!_aura)
|
||||
_duration = newDuration;
|
||||
else
|
||||
_aura->SetDuration(newDuration);
|
||||
}
|
||||
|
||||
void DynamicObject::Delay(int32 delaytime)
|
||||
{
|
||||
SetDuration(GetDuration() - delaytime);
|
||||
}
|
||||
|
||||
void DynamicObject::SetAura(Aura* aura)
|
||||
{
|
||||
ASSERT(!_aura && aura);
|
||||
_aura = aura;
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveAura()
|
||||
{
|
||||
ASSERT(_aura && !_removedAura);
|
||||
_removedAura = _aura;
|
||||
_aura = NULL;
|
||||
if (!_removedAura->IsRemoved())
|
||||
_removedAura->_Remove(AURA_REMOVE_BY_DEFAULT);
|
||||
}
|
||||
|
||||
void DynamicObject::SetCasterViewpoint()
|
||||
{
|
||||
if (Player* caster = _caster->ToPlayer())
|
||||
{
|
||||
caster->SetViewpoint(this, true);
|
||||
_isViewpoint = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveCasterViewpoint()
|
||||
{
|
||||
if (Player* caster = _caster->ToPlayer())
|
||||
{
|
||||
caster->SetViewpoint(this, false);
|
||||
_isViewpoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::BindToCaster()
|
||||
{
|
||||
ASSERT(!_caster);
|
||||
_caster = ObjectAccessor::GetUnit(*this, GetCasterGUID());
|
||||
ASSERT(_caster);
|
||||
ASSERT(_caster->GetMap() == GetMap());
|
||||
_caster->_RegisterDynObject(this);
|
||||
}
|
||||
|
||||
void DynamicObject::UnbindFromCaster()
|
||||
{
|
||||
ASSERT(_caster);
|
||||
_caster->_UnregisterDynObject(this);
|
||||
_caster = NULL;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_DYNAMICOBJECT_H
|
||||
#define AZEROTHCORE_DYNAMICOBJECT_H
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Unit;
|
||||
class Aura;
|
||||
class SpellInfo;
|
||||
|
||||
enum DynamicObjectType
|
||||
{
|
||||
DYNAMIC_OBJECT_PORTAL = 0x0, // unused
|
||||
DYNAMIC_OBJECT_AREA_SPELL = 0x1,
|
||||
DYNAMIC_OBJECT_FARSIGHT_FOCUS = 0x2,
|
||||
};
|
||||
|
||||
class DynamicObject : public WorldObject, public GridObject<DynamicObject>, public MovableMapObject
|
||||
{
|
||||
public:
|
||||
DynamicObject(bool isWorldObject);
|
||||
~DynamicObject();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
void CleanupsBeforeDelete(bool finalCleanup = true);
|
||||
|
||||
bool CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type);
|
||||
void Update(uint32 p_time);
|
||||
void Remove();
|
||||
void SetDuration(int32 newDuration);
|
||||
int32 GetDuration() const;
|
||||
void Delay(int32 delaytime);
|
||||
void SetAura(Aura* aura);
|
||||
void RemoveAura();
|
||||
void SetCasterViewpoint();
|
||||
void RemoveCasterViewpoint();
|
||||
Unit* GetCaster() const { return _caster; }
|
||||
void BindToCaster();
|
||||
void UnbindFromCaster();
|
||||
uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); }
|
||||
uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); }
|
||||
float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); }
|
||||
bool IsViewpoint() const { return _isViewpoint; }
|
||||
|
||||
protected:
|
||||
Aura* _aura;
|
||||
Aura* _removedAura;
|
||||
Unit* _caster;
|
||||
int32 _duration; // for non-aura dynobjects
|
||||
bool _isViewpoint;
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,915 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
|
||||
#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;
|
||||
uint32 faction;
|
||||
uint32 flags;
|
||||
float size;
|
||||
uint32 questItems[MAX_GAMEOBJECT_QUEST_ITEMS];
|
||||
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
|
||||
bool IsDespawnAtAction() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GAMEOBJECT_TYPE_CHEST: return chest.consumable;
|
||||
case GAMEOBJECT_TYPE_GOOBER: return goober.consumable;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint32 GetLootId() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GAMEOBJECT_TYPE_CHEST: return chest.lootId;
|
||||
case GAMEOBJECT_TYPE_FISHINGHOLE: return fishinghole.lootId;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetGossipMenuId() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.gossipID;
|
||||
case GAMEOBJECT_TYPE_GOOBER: return goober.gossipID;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsGameObjectForQuests() const
|
||||
{
|
||||
return IsForQuests;
|
||||
}
|
||||
};
|
||||
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
typedef UNORDERED_MAP<uint32, GameObjectTemplate> GameObjectTemplateContainer;
|
||||
|
||||
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 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;
|
||||
};
|
||||
|
||||
// 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();
|
||||
|
||||
void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const;
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
void CleanupsBeforeDelete(bool finalCleanup = true);
|
||||
|
||||
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);
|
||||
GameObjectTemplate const* GetGOInfo() const { return m_goInfo; }
|
||||
GameObjectData const* GetGOData() const { return m_goData; }
|
||||
GameObjectValue const* GetGOValue() const { return &m_goValue; }
|
||||
|
||||
bool IsTransport() const;
|
||||
bool IsDestructibleBuilding() const;
|
||||
|
||||
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);
|
||||
int64 GetPackedWorldRotation() const { return m_packedRotation; }
|
||||
|
||||
// overwrite WorldObject function for proper name localization
|
||||
std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const;
|
||||
|
||||
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)
|
||||
{
|
||||
ASSERT(false);
|
||||
}
|
||||
m_spawnedByDefault = false; // all object with owner is despawned after delay
|
||||
SetUInt64Value(OBJECT_FIELD_CREATED_BY, owner);
|
||||
}
|
||||
uint64 GetOwnerGUID() const { return GetUInt64Value(OBJECT_FIELD_CREATED_BY); }
|
||||
Unit* GetOwner() const;
|
||||
|
||||
void SetSpellId(uint32 id)
|
||||
{
|
||||
m_spawnedByDefault = false; // all summoned object is despawned after delay
|
||||
m_spellId = id;
|
||||
}
|
||||
uint32 GetSpellId() const { return m_spellId;}
|
||||
|
||||
time_t GetRespawnTime() const { return m_respawnTime; }
|
||||
time_t GetRespawnTimeEx() const
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
if (m_respawnTime > now)
|
||||
return m_respawnTime;
|
||||
else
|
||||
return now;
|
||||
}
|
||||
|
||||
void SetRespawnTime(int32 respawn)
|
||||
{
|
||||
m_respawnTime = respawn > 0 ? time(NULL) + respawn : 0;
|
||||
m_respawnDelayTime = respawn > 0 ? respawn : 0;
|
||||
}
|
||||
void Respawn();
|
||||
bool isSpawned() const
|
||||
{
|
||||
return m_respawnDelayTime == 0 ||
|
||||
(m_respawnTime > 0 && !m_spawnedByDefault) ||
|
||||
(m_respawnTime == 0 && m_spawnedByDefault);
|
||||
}
|
||||
bool isSpawnedByDefault() const { return m_spawnedByDefault; }
|
||||
void SetSpawnedByDefault(bool b) { m_spawnedByDefault = b; }
|
||||
uint32 GetRespawnDelay() const { return m_respawnDelayTime; }
|
||||
void Refresh();
|
||||
void Delete();
|
||||
void getFishLoot(Loot* loot, Player* loot_owner);
|
||||
void getFishLootJunk(Loot* loot, Player* loot_owner);
|
||||
GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
|
||||
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
|
||||
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
|
||||
void SetGoState(GOState state);
|
||||
uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); }
|
||||
void SetGoArtKit(uint8 artkit);
|
||||
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);
|
||||
void EnableCollision(bool enable);
|
||||
|
||||
void Use(Unit* user);
|
||||
|
||||
LootState getLootState() const { return m_lootState; }
|
||||
// Note: unit is only used when s = GO_ACTIVATED
|
||||
void SetLootState(LootState s, Unit* unit = NULL);
|
||||
|
||||
uint16 GetLootMode() const { return m_LootMode; }
|
||||
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); }
|
||||
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; }
|
||||
|
||||
uint32 GetUseCount() const { return m_usetimes; }
|
||||
uint32 GetUniqueUseCount() const { return m_unique_users.size(); }
|
||||
|
||||
void SaveRespawnTime();
|
||||
|
||||
Loot loot;
|
||||
|
||||
Player* GetLootRecipient() const;
|
||||
Group* GetLootRecipientGroup() const;
|
||||
void SetLootRecipient(Unit* unit);
|
||||
bool IsLootAllowedFor(Player const* player) const;
|
||||
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(NULL); }
|
||||
uint32 GetLootGenerationTime() const { return m_lootGenerationTime; }
|
||||
|
||||
bool hasQuest(uint32 quest_id) const;
|
||||
bool hasInvolvedQuest(uint32 quest_id) const;
|
||||
bool ActivateToQuest(Player* target) const;
|
||||
void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false, Unit* user = NULL);
|
||||
// 0 = use `gameobject`.`spawntimesecs`
|
||||
void ResetDoorOrButton();
|
||||
|
||||
void TriggeringLinkedGameObject(uint32 trapEntry, Unit* target);
|
||||
|
||||
bool IsNeverVisible() const;
|
||||
bool IsAlwaysVisibleFor(WorldObject const* seer) const;
|
||||
bool IsInvisibleDueToDespawn() const;
|
||||
|
||||
uint8 getLevelForTarget(WorldObject const* target) const
|
||||
{
|
||||
if (Unit* owner = GetOwner())
|
||||
return owner->getLevelForTarget(target);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameObject* LookupFishingHoleAround(float range);
|
||||
|
||||
void CastSpell(Unit* target, uint32 spell);
|
||||
void SendCustomAnim(uint32 anim);
|
||||
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 = NULL); // pussywizard!
|
||||
|
||||
void ModifyHealth(int32 change, Unit* attackerOrHealer = NULL, 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 = NULL, bool setHealth = false);
|
||||
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);
|
||||
|
||||
virtual uint32 GetScriptId() const { return GetGOInfo()->ScriptId; }
|
||||
GameObjectAI* AI() const { return m_AI; }
|
||||
|
||||
std::string GetAIName() const;
|
||||
void SetDisplayId(uint32 displayid);
|
||||
uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
|
||||
|
||||
GameObjectModel* m_model;
|
||||
void GetRespawnPosition(float &x, float &y, float &z, float* ori = NULL) 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()); }
|
||||
|
||||
bool IsStaticTransport() const { return GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT; }
|
||||
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 NULL; }
|
||||
Transport const* ToTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT || GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT) return reinterpret_cast<Transport const*>(this); else return NULL; }
|
||||
|
||||
StaticTransport* ToStaticTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT) return reinterpret_cast<StaticTransport*>(this); else return NULL; }
|
||||
StaticTransport const* ToStaticTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT) return reinterpret_cast<StaticTransport const*>(this); else return NULL; }
|
||||
|
||||
MotionTransport* ToMotionTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<MotionTransport*>(this); else return NULL; }
|
||||
MotionTransport const* ToMotionTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<MotionTransport const*>(this); else return NULL; }
|
||||
|
||||
float GetStationaryX() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionX(); return GetPositionX(); }
|
||||
float GetStationaryY() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionY(); return GetPositionY(); }
|
||||
float GetStationaryZ() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
|
||||
float GetStationaryO() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); }
|
||||
|
||||
float GetInteractionDistance();
|
||||
|
||||
void UpdateModelPosition();
|
||||
|
||||
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
|
||||
{
|
||||
//! Following check does check 3d distance
|
||||
dist2compare += obj->GetObjectSize();
|
||||
return IsInRange(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), dist2compare);
|
||||
}
|
||||
GameObjectAI* m_AI;
|
||||
};
|
||||
#endif
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "DatabaseEnv.h"
|
||||
|
||||
#include "Bag.h"
|
||||
#include "Log.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Player.h"
|
||||
|
||||
Bag::Bag(): Item()
|
||||
{
|
||||
m_objectType |= TYPEMASK_CONTAINER;
|
||||
m_objectTypeId = TYPEID_CONTAINER;
|
||||
|
||||
m_valuesCount = CONTAINER_END;
|
||||
|
||||
memset(m_bagslot, 0, sizeof(Item*) * MAX_BAG_SIZE);
|
||||
}
|
||||
|
||||
Bag::~Bag()
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
|
||||
if (Item* item = m_bagslot[i])
|
||||
{
|
||||
if (item->IsInWorld())
|
||||
{
|
||||
sLog->outCrash("Item %u (slot %u, bag slot %u) in bag %u (slot %u, bag slot %u, m_bagslot %u) is to be deleted but is still in world.",
|
||||
item->GetEntry(), (uint32)item->GetSlot(), (uint32)item->GetBagSlot(),
|
||||
GetEntry(), (uint32)GetSlot(), (uint32)GetBagSlot(), (uint32)i);
|
||||
item->RemoveFromWorld();
|
||||
}
|
||||
delete m_bagslot[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Bag::AddToWorld()
|
||||
{
|
||||
Item::AddToWorld();
|
||||
|
||||
for (uint32 i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i])
|
||||
m_bagslot[i]->AddToWorld();
|
||||
}
|
||||
|
||||
void Bag::RemoveFromWorld()
|
||||
{
|
||||
for (uint32 i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i])
|
||||
m_bagslot[i]->RemoveFromWorld();
|
||||
|
||||
Item::RemoveFromWorld();
|
||||
}
|
||||
|
||||
bool Bag::Create(uint32 guidlow, uint32 itemid, Player const* owner)
|
||||
{
|
||||
ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemid);
|
||||
|
||||
if (!itemProto || itemProto->ContainerSlots > MAX_BAG_SIZE)
|
||||
return false;
|
||||
|
||||
Object::_Create(guidlow, 0, HIGHGUID_CONTAINER);
|
||||
|
||||
SetEntry(itemid);
|
||||
SetObjectScale(1.0f);
|
||||
|
||||
SetUInt64Value(ITEM_FIELD_OWNER, owner ? owner->GetGUID() : 0);
|
||||
SetUInt64Value(ITEM_FIELD_CONTAINED, owner ? owner->GetGUID() : 0);
|
||||
|
||||
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
|
||||
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
|
||||
SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1);
|
||||
|
||||
// Setting the number of Slots the Container has
|
||||
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots);
|
||||
|
||||
// Cleaning 20 slots
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
|
||||
{
|
||||
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0);
|
||||
m_bagslot[i] = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bag::SaveToDB(SQLTransaction& trans)
|
||||
{
|
||||
Item::SaveToDB(trans);
|
||||
}
|
||||
|
||||
bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry)
|
||||
{
|
||||
if (!Item::LoadFromDB(guid, owner_guid, fields, entry))
|
||||
return false;
|
||||
|
||||
ItemTemplate const* itemProto = GetTemplate(); // checked in Item::LoadFromDB
|
||||
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots);
|
||||
// cleanup bag content related item value fields (its will be filled correctly from `character_inventory`)
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
|
||||
{
|
||||
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0);
|
||||
delete m_bagslot[i];
|
||||
m_bagslot[i] = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bag::DeleteFromDB(SQLTransaction& trans)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
|
||||
if (m_bagslot[i])
|
||||
m_bagslot[i]->DeleteFromDB(trans);
|
||||
|
||||
Item::DeleteFromDB(trans);
|
||||
}
|
||||
|
||||
uint32 Bag::GetFreeSlots() const
|
||||
{
|
||||
uint32 slots = 0;
|
||||
for (uint32 i=0; i < GetBagSize(); ++i)
|
||||
if (!m_bagslot[i])
|
||||
++slots;
|
||||
|
||||
return slots;
|
||||
}
|
||||
|
||||
void Bag::RemoveItem(uint8 slot, bool /*update*/)
|
||||
{
|
||||
ASSERT(slot < MAX_BAG_SIZE);
|
||||
|
||||
if (m_bagslot[slot])
|
||||
m_bagslot[slot]->SetContainer(NULL);
|
||||
|
||||
m_bagslot[slot] = NULL;
|
||||
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (slot * 2), 0);
|
||||
}
|
||||
|
||||
void Bag::StoreItem(uint8 slot, Item* pItem, bool /*update*/)
|
||||
{
|
||||
ASSERT(slot < MAX_BAG_SIZE);
|
||||
|
||||
if (pItem && pItem->GetGUID() != this->GetGUID())
|
||||
{
|
||||
m_bagslot[slot] = pItem;
|
||||
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (slot * 2), pItem->GetGUID());
|
||||
pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, GetGUID());
|
||||
pItem->SetUInt64Value(ITEM_FIELD_OWNER, GetOwnerGUID());
|
||||
pItem->SetContainer(this);
|
||||
pItem->SetSlot(slot);
|
||||
}
|
||||
}
|
||||
|
||||
void Bag::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
|
||||
{
|
||||
Item::BuildCreateUpdateBlockForPlayer(data, target);
|
||||
|
||||
for (uint32 i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i])
|
||||
m_bagslot[i]->BuildCreateUpdateBlockForPlayer(data, target);
|
||||
}
|
||||
|
||||
// If the bag is empty returns true
|
||||
bool Bag::IsEmpty() const
|
||||
{
|
||||
for (uint32 i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Bag::GetItemCount(uint32 item, Item* eItem) const
|
||||
{
|
||||
Item* pItem;
|
||||
uint32 count = 0;
|
||||
for (uint32 i=0; i < GetBagSize(); ++i)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if (pItem && pItem != eItem && pItem->GetEntry() == item)
|
||||
count += pItem->GetCount();
|
||||
}
|
||||
|
||||
if (eItem && eItem->GetTemplate()->GemProperties)
|
||||
{
|
||||
for (uint32 i=0; i < GetBagSize(); ++i)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if (pItem && pItem != eItem && pItem->GetTemplate()->Socket[0].Color)
|
||||
count += pItem->GetGemCountWithID(item);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32 Bag::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem) const
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (uint32 i = 0; i < GetBagSize(); ++i)
|
||||
if (Item* pItem = m_bagslot[i])
|
||||
if (pItem != skipItem)
|
||||
if (ItemTemplate const* pProto = pItem->GetTemplate())
|
||||
if (pProto->ItemLimitCategory == limitCategory)
|
||||
count += m_bagslot[i]->GetCount();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8 Bag::GetSlotByItemGUID(uint64 guid) const
|
||||
{
|
||||
for (uint32 i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i] != 0)
|
||||
if (m_bagslot[i]->GetGUID() == guid)
|
||||
return i;
|
||||
|
||||
return NULL_SLOT;
|
||||
}
|
||||
|
||||
Item* Bag::GetItemByPos(uint8 slot) const
|
||||
{
|
||||
if (slot < GetBagSize())
|
||||
return m_bagslot[slot];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_BAG_H
|
||||
#define TRINITY_BAG_H
|
||||
|
||||
// Maximum 36 Slots ((CONTAINER_END - CONTAINER_FIELD_SLOT_1)/2
|
||||
#define MAX_BAG_SIZE 36 // 2.0.12
|
||||
|
||||
#include "Item.h"
|
||||
#include "ItemPrototype.h"
|
||||
|
||||
class Bag : public Item
|
||||
{
|
||||
public:
|
||||
|
||||
Bag();
|
||||
~Bag();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create(uint32 guidlow, uint32 itemid, Player const* owner);
|
||||
|
||||
void Clear();
|
||||
void StoreItem(uint8 slot, Item* pItem, bool update);
|
||||
void RemoveItem(uint8 slot, bool update);
|
||||
|
||||
Item* GetItemByPos(uint8 slot) const;
|
||||
uint32 GetItemCount(uint32 item, Item* eItem = NULL) const;
|
||||
uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = NULL) const;
|
||||
|
||||
uint8 GetSlotByItemGUID(uint64 guid) const;
|
||||
bool IsEmpty() const;
|
||||
uint32 GetFreeSlots() const;
|
||||
uint32 GetBagSize() const { return GetUInt32Value(CONTAINER_FIELD_NUM_SLOTS); }
|
||||
|
||||
// DB operations
|
||||
// overwrite virtual Item::SaveToDB
|
||||
void SaveToDB(SQLTransaction& trans);
|
||||
// overwrite virtual Item::LoadFromDB
|
||||
bool LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry);
|
||||
// overwrite virtual Item::DeleteFromDB
|
||||
void DeleteFromDB(SQLTransaction& trans);
|
||||
|
||||
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const;
|
||||
|
||||
protected:
|
||||
|
||||
// Bag Storage space
|
||||
Item* m_bagslot[MAX_BAG_SIZE];
|
||||
};
|
||||
|
||||
inline Item* NewItemOrBag(ItemTemplate const* proto)
|
||||
{
|
||||
return (proto->InventoryType == INVTYPE_BAG) ? new Bag : new Item;
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,360 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_ITEM_H
|
||||
#define AZEROTHCORE_ITEM_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "LootMgr.h"
|
||||
#include "ItemPrototype.h"
|
||||
#include "DatabaseEnv.h"
|
||||
|
||||
class SpellInfo;
|
||||
class Bag;
|
||||
class Unit;
|
||||
|
||||
struct ItemSetEffect
|
||||
{
|
||||
uint32 setid;
|
||||
uint32 item_count;
|
||||
SpellInfo const* spells[8];
|
||||
};
|
||||
|
||||
enum InventoryResult
|
||||
{
|
||||
EQUIP_ERR_OK = 0,
|
||||
EQUIP_ERR_CANT_EQUIP_LEVEL_I = 1,
|
||||
EQUIP_ERR_CANT_EQUIP_SKILL = 2,
|
||||
EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT = 3,
|
||||
EQUIP_ERR_BAG_FULL = 4,
|
||||
EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG = 5,
|
||||
EQUIP_ERR_CANT_TRADE_EQUIP_BAGS = 6,
|
||||
EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE = 7,
|
||||
EQUIP_ERR_NO_REQUIRED_PROFICIENCY = 8,
|
||||
EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE = 9,
|
||||
EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM = 10,
|
||||
EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM2 = 11,
|
||||
EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE2 = 12,
|
||||
EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED = 13,
|
||||
EQUIP_ERR_CANT_DUAL_WIELD = 14,
|
||||
EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG = 15,
|
||||
EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG2 = 16,
|
||||
EQUIP_ERR_CANT_CARRY_MORE_OF_THIS = 17,
|
||||
EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE3 = 18,
|
||||
EQUIP_ERR_ITEM_CANT_STACK = 19,
|
||||
EQUIP_ERR_ITEM_CANT_BE_EQUIPPED = 20,
|
||||
EQUIP_ERR_ITEMS_CANT_BE_SWAPPED = 21,
|
||||
EQUIP_ERR_SLOT_IS_EMPTY = 22,
|
||||
EQUIP_ERR_ITEM_NOT_FOUND = 23,
|
||||
EQUIP_ERR_CANT_DROP_SOULBOUND = 24,
|
||||
EQUIP_ERR_OUT_OF_RANGE = 25,
|
||||
EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT = 26,
|
||||
EQUIP_ERR_COULDNT_SPLIT_ITEMS = 27,
|
||||
EQUIP_ERR_MISSING_REAGENT = 28,
|
||||
EQUIP_ERR_NOT_ENOUGH_MONEY = 29,
|
||||
EQUIP_ERR_NOT_A_BAG = 30,
|
||||
EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS = 31,
|
||||
EQUIP_ERR_DONT_OWN_THAT_ITEM = 32,
|
||||
EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER = 33,
|
||||
EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT = 34,
|
||||
EQUIP_ERR_TOO_FAR_AWAY_FROM_BANK = 35,
|
||||
EQUIP_ERR_ITEM_LOCKED = 36,
|
||||
EQUIP_ERR_YOU_ARE_STUNNED = 37,
|
||||
EQUIP_ERR_YOU_ARE_DEAD = 38,
|
||||
EQUIP_ERR_CANT_DO_RIGHT_NOW = 39,
|
||||
EQUIP_ERR_INT_BAG_ERROR = 40,
|
||||
EQUIP_ERR_CAN_EQUIP_ONLY1_BOLT = 41,
|
||||
EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH = 42,
|
||||
EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED = 43,
|
||||
EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED = 44,
|
||||
EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED = 45,
|
||||
EQUIP_ERR_BOUND_CANT_BE_WRAPPED = 46,
|
||||
EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED = 47,
|
||||
EQUIP_ERR_BAGS_CANT_BE_WRAPPED = 48,
|
||||
EQUIP_ERR_ALREADY_LOOTED = 49,
|
||||
EQUIP_ERR_INVENTORY_FULL = 50,
|
||||
EQUIP_ERR_BANK_FULL = 51,
|
||||
EQUIP_ERR_ITEM_IS_CURRENTLY_SOLD_OUT = 52,
|
||||
EQUIP_ERR_BAG_FULL3 = 53,
|
||||
EQUIP_ERR_ITEM_NOT_FOUND2 = 54,
|
||||
EQUIP_ERR_ITEM_CANT_STACK2 = 55,
|
||||
EQUIP_ERR_BAG_FULL4 = 56,
|
||||
EQUIP_ERR_ITEM_SOLD_OUT = 57,
|
||||
EQUIP_ERR_OBJECT_IS_BUSY = 58,
|
||||
EQUIP_ERR_NONE = 59,
|
||||
EQUIP_ERR_NOT_IN_COMBAT = 60,
|
||||
EQUIP_ERR_NOT_WHILE_DISARMED = 61,
|
||||
EQUIP_ERR_BAG_FULL6 = 62,
|
||||
EQUIP_ERR_CANT_EQUIP_RANK = 63,
|
||||
EQUIP_ERR_CANT_EQUIP_REPUTATION = 64,
|
||||
EQUIP_ERR_TOO_MANY_SPECIAL_BAGS = 65,
|
||||
EQUIP_ERR_LOOT_CANT_LOOT_THAT_NOW = 66,
|
||||
EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE = 67,
|
||||
EQUIP_ERR_VENDOR_MISSING_TURNINS = 68,
|
||||
EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS = 69,
|
||||
EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS = 70,
|
||||
EQUIP_ERR_ITEM_MAX_COUNT_SOCKETED = 71,
|
||||
EQUIP_ERR_MAIL_BOUND_ITEM = 72,
|
||||
EQUIP_ERR_NO_SPLIT_WHILE_PROSPECTING = 73,
|
||||
EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED = 75,
|
||||
EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED = 76,
|
||||
EQUIP_ERR_TOO_MUCH_GOLD = 77,
|
||||
EQUIP_ERR_NOT_DURING_ARENA_MATCH = 78,
|
||||
EQUIP_ERR_CANNOT_TRADE_THAT = 79,
|
||||
EQUIP_ERR_PERSONAL_ARENA_RATING_TOO_LOW = 80,
|
||||
EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM = 81,
|
||||
EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS = 82,
|
||||
// no output = 83,
|
||||
EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED = 84,
|
||||
EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED = 85,
|
||||
EQUIP_ERR_SCALING_STAT_ITEM_LEVEL_EXCEEDED = 86,
|
||||
EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW = 87,
|
||||
EQUIP_ERR_CANT_EQUIP_NEED_TALENT = 88,
|
||||
EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED = 89
|
||||
};
|
||||
|
||||
enum BuyResult
|
||||
{
|
||||
BUY_ERR_CANT_FIND_ITEM = 0,
|
||||
BUY_ERR_ITEM_ALREADY_SOLD = 1,
|
||||
BUY_ERR_NOT_ENOUGHT_MONEY = 2,
|
||||
BUY_ERR_SELLER_DONT_LIKE_YOU = 4,
|
||||
BUY_ERR_DISTANCE_TOO_FAR = 5,
|
||||
BUY_ERR_ITEM_SOLD_OUT = 7,
|
||||
BUY_ERR_CANT_CARRY_MORE = 8,
|
||||
BUY_ERR_RANK_REQUIRE = 11,
|
||||
BUY_ERR_REPUTATION_REQUIRE = 12
|
||||
};
|
||||
|
||||
enum SellResult
|
||||
{
|
||||
SELL_ERR_CANT_FIND_ITEM = 1,
|
||||
SELL_ERR_CANT_SELL_ITEM = 2, // merchant doesn't like that item
|
||||
SELL_ERR_CANT_FIND_VENDOR = 3, // merchant doesn't like you
|
||||
SELL_ERR_YOU_DONT_OWN_THAT_ITEM = 4, // you don't own that item
|
||||
SELL_ERR_UNK = 5, // nothing appears...
|
||||
SELL_ERR_ONLY_EMPTY_BAG = 6 // can only do with empty bags
|
||||
};
|
||||
|
||||
// -1 from client enchantment slot number
|
||||
enum EnchantmentSlot
|
||||
{
|
||||
PERM_ENCHANTMENT_SLOT = 0,
|
||||
TEMP_ENCHANTMENT_SLOT = 1,
|
||||
SOCK_ENCHANTMENT_SLOT = 2,
|
||||
SOCK_ENCHANTMENT_SLOT_2 = 3,
|
||||
SOCK_ENCHANTMENT_SLOT_3 = 4,
|
||||
BONUS_ENCHANTMENT_SLOT = 5,
|
||||
PRISMATIC_ENCHANTMENT_SLOT = 6, // added at apply special permanent enchantment
|
||||
MAX_INSPECTED_ENCHANTMENT_SLOT = 7,
|
||||
|
||||
PROP_ENCHANTMENT_SLOT_0 = 7, // used with RandomSuffix
|
||||
PROP_ENCHANTMENT_SLOT_1 = 8, // used with RandomSuffix
|
||||
PROP_ENCHANTMENT_SLOT_2 = 9, // used with RandomSuffix and RandomProperty
|
||||
PROP_ENCHANTMENT_SLOT_3 = 10, // used with RandomProperty
|
||||
PROP_ENCHANTMENT_SLOT_4 = 11, // used with RandomProperty
|
||||
MAX_ENCHANTMENT_SLOT = 12
|
||||
};
|
||||
|
||||
#define MAX_VISIBLE_ITEM_OFFSET 2 // 2 fields per visible item (entry+enchantment)
|
||||
|
||||
#define MAX_GEM_SOCKETS MAX_ITEM_PROTO_SOCKETS// (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) and item proto size, equal value expected
|
||||
|
||||
enum EnchantmentOffset
|
||||
{
|
||||
ENCHANTMENT_ID_OFFSET = 0,
|
||||
ENCHANTMENT_DURATION_OFFSET = 1,
|
||||
ENCHANTMENT_CHARGES_OFFSET = 2 // now here not only charges, but something new in wotlk
|
||||
};
|
||||
|
||||
#define MAX_ENCHANTMENT_OFFSET 3
|
||||
|
||||
enum EnchantmentSlotMask
|
||||
{
|
||||
ENCHANTMENT_CAN_SOULBOUND = 0x01,
|
||||
ENCHANTMENT_UNK1 = 0x02,
|
||||
ENCHANTMENT_UNK2 = 0x04,
|
||||
ENCHANTMENT_UNK3 = 0x08
|
||||
};
|
||||
|
||||
enum ItemUpdateState
|
||||
{
|
||||
ITEM_UNCHANGED = 0,
|
||||
ITEM_CHANGED = 1,
|
||||
ITEM_NEW = 2,
|
||||
ITEM_REMOVED = 3
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SPELLS 5
|
||||
|
||||
bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto);
|
||||
|
||||
class Item : public Object
|
||||
{
|
||||
public:
|
||||
static Item* CreateItem(uint32 item, uint32 count, Player const* player = NULL);
|
||||
Item* CloneItem(uint32 count, Player const* player = NULL) const;
|
||||
|
||||
Item();
|
||||
|
||||
virtual bool Create(uint32 guidlow, uint32 itemid, Player const* owner);
|
||||
|
||||
ItemTemplate const* GetTemplate() const;
|
||||
|
||||
uint64 GetOwnerGUID() const { return GetUInt64Value(ITEM_FIELD_OWNER); }
|
||||
void SetOwnerGUID(uint64 guid) { SetUInt64Value(ITEM_FIELD_OWNER, guid); }
|
||||
Player* GetOwner() const;
|
||||
|
||||
void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, val); }
|
||||
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND); }
|
||||
bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT) != 0; }
|
||||
bool IsBindedNotWith(Player const* player) const;
|
||||
bool IsBoundByEnchant() const;
|
||||
bool IsBoundByTempEnchant() const;
|
||||
virtual void SaveToDB(SQLTransaction& trans);
|
||||
virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry);
|
||||
static void DeleteFromDB(SQLTransaction& trans, uint32 itemGuid);
|
||||
virtual void DeleteFromDB(SQLTransaction& trans);
|
||||
static void DeleteFromInventoryDB(SQLTransaction& trans, uint32 itemGuid);
|
||||
void DeleteFromInventoryDB(SQLTransaction& trans);
|
||||
void SaveRefundDataToDB();
|
||||
void DeleteRefundDataFromDB(SQLTransaction* trans);
|
||||
|
||||
Bag* ToBag() { if (IsBag()) return reinterpret_cast<Bag*>(this); else return NULL; }
|
||||
const Bag* ToBag() const { if (IsBag()) return reinterpret_cast<const Bag*>(this); else return NULL; }
|
||||
|
||||
bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED); }
|
||||
bool IsBag() const { return GetTemplate()->InventoryType == INVTYPE_BAG; }
|
||||
bool IsCurrencyToken() const { return GetTemplate()->IsCurrencyToken(); }
|
||||
bool IsNotEmptyBag() const;
|
||||
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
|
||||
bool CanBeTraded(bool mail = false, bool trade = false) const;
|
||||
void SetInTrade(bool b = true) { mb_in_trade = b; }
|
||||
bool IsInTrade() const { return mb_in_trade; }
|
||||
|
||||
bool HasEnchantRequiredSkill(const Player* player) const;
|
||||
uint32 GetEnchantRequiredLevel() const;
|
||||
|
||||
bool IsFitToSpellRequirements(SpellInfo const* spellInfo) const;
|
||||
bool IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const;
|
||||
bool GemsFitSockets() const;
|
||||
|
||||
uint32 GetCount() const { return GetUInt32Value(ITEM_FIELD_STACK_COUNT); }
|
||||
void SetCount(uint32 value) { SetUInt32Value(ITEM_FIELD_STACK_COUNT, value); }
|
||||
uint32 GetMaxStackCount() const { return GetTemplate()->GetMaxStackSize(); }
|
||||
uint8 GetGemCountWithID(uint32 GemID) const;
|
||||
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const;
|
||||
InventoryResult CanBeMergedPartlyWith(ItemTemplate const* proto) const;
|
||||
|
||||
uint8 GetSlot() const {return m_slot;}
|
||||
Bag* GetContainer() { return m_container; }
|
||||
uint8 GetBagSlot() const;
|
||||
void SetSlot(uint8 slot) { m_slot = slot; }
|
||||
uint16 GetPos() const { return uint16(GetBagSlot()) << 8 | GetSlot(); }
|
||||
void SetContainer(Bag* container) { m_container = container; }
|
||||
|
||||
bool IsInBag() const { return m_container != NULL; }
|
||||
bool IsEquipped() const;
|
||||
|
||||
uint32 GetSkill();
|
||||
uint32 GetSpell();
|
||||
|
||||
// RandomPropertyId (signed but stored as unsigned)
|
||||
int32 GetItemRandomPropertyId() const { return GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID); }
|
||||
uint32 GetItemSuffixFactor() const { return GetUInt32Value(ITEM_FIELD_PROPERTY_SEED); }
|
||||
void SetItemRandomProperties(int32 randomPropId);
|
||||
void UpdateItemSuffixFactor();
|
||||
static int32 GenerateItemRandomPropertyId(uint32 item_id);
|
||||
void SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges, uint64 caster = 0);
|
||||
void SetEnchantmentDuration(EnchantmentSlot slot, uint32 duration, Player* owner);
|
||||
void SetEnchantmentCharges(EnchantmentSlot slot, uint32 charges);
|
||||
void ClearEnchantment(EnchantmentSlot slot);
|
||||
uint32 GetEnchantmentId(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET);}
|
||||
uint32 GetEnchantmentDuration(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET);}
|
||||
uint32 GetEnchantmentCharges(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET);}
|
||||
|
||||
std::string const& GetText() const { return m_text; }
|
||||
void SetText(std::string const& text) { m_text = text; }
|
||||
|
||||
void SendUpdateSockets();
|
||||
|
||||
void SendTimeUpdate(Player* owner);
|
||||
void UpdateDuration(Player* owner, uint32 diff);
|
||||
|
||||
// spell charges (signed but stored as unsigned)
|
||||
int32 GetSpellCharges(uint8 index/*0..5*/ = 0) const { return GetInt32Value(ITEM_FIELD_SPELL_CHARGES + index); }
|
||||
void SetSpellCharges(uint8 index/*0..5*/, int32 value) { SetInt32Value(ITEM_FIELD_SPELL_CHARGES + index, value); }
|
||||
|
||||
Loot loot;
|
||||
bool m_lootGenerated;
|
||||
|
||||
// Update States
|
||||
ItemUpdateState GetState() const { return uState; }
|
||||
void SetState(ItemUpdateState state, Player* forplayer = NULL);
|
||||
void AddToUpdateQueueOf(Player* player);
|
||||
void RemoveFromUpdateQueueOf(Player* player);
|
||||
bool IsInUpdateQueue() const { return uQueuePos != -1; }
|
||||
uint32 GetQueuePos() const { return uQueuePos; }
|
||||
void FSetState(ItemUpdateState state) // forced
|
||||
{
|
||||
uState = state;
|
||||
}
|
||||
|
||||
bool hasQuest(uint32 quest_id) const { return GetTemplate()->StartQuest == quest_id; }
|
||||
bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; }
|
||||
bool IsPotion() const { return GetTemplate()->IsPotion(); }
|
||||
bool IsWeaponVellum() const { return GetTemplate()->IsWeaponVellum(); }
|
||||
bool IsArmorVellum() const { return GetTemplate()->IsArmorVellum(); }
|
||||
bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); }
|
||||
|
||||
// Item Refund system
|
||||
void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = NULL);
|
||||
void SetRefundRecipient(uint32 pGuidLow) { m_refundRecipient = pGuidLow; }
|
||||
void SetPaidMoney(uint32 money) { m_paidMoney = money; }
|
||||
void SetPaidExtendedCost(uint32 iece) { m_paidExtendedCost = iece; }
|
||||
uint32 GetRefundRecipient() { return m_refundRecipient; }
|
||||
uint32 GetPaidMoney() { return m_paidMoney; }
|
||||
uint32 GetPaidExtendedCost() { return m_paidExtendedCost; }
|
||||
|
||||
void UpdatePlayedTime(Player* owner);
|
||||
uint32 GetPlayedTime();
|
||||
bool IsRefundExpired();
|
||||
|
||||
// Soulbound trade system
|
||||
void SetSoulboundTradeable(AllowedLooterSet& allowedLooters);
|
||||
void ClearSoulboundTradeable(Player* currentOwner);
|
||||
bool CheckSoulboundTradeExpire();
|
||||
|
||||
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet&);
|
||||
|
||||
uint32 GetScriptId() const { return GetTemplate()->ScriptId; }
|
||||
private:
|
||||
std::string m_text;
|
||||
uint8 m_slot;
|
||||
Bag* m_container;
|
||||
ItemUpdateState uState;
|
||||
int32 uQueuePos;
|
||||
bool mb_in_trade; // true if item is currently in trade-window
|
||||
time_t m_lastPlayedTimeUpdate;
|
||||
uint32 m_refundRecipient;
|
||||
uint32 m_paidMoney;
|
||||
uint32 m_paidExtendedCost;
|
||||
AllowedLooterSet allowedGUIDs;
|
||||
};
|
||||
#endif
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
#include "ItemEnchantmentMgr.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "Util.h"
|
||||
#include "DBCStores.h"
|
||||
|
||||
struct EnchStoreItem
|
||||
{
|
||||
uint32 ench;
|
||||
float chance;
|
||||
|
||||
EnchStoreItem()
|
||||
: ench(0), chance(0) {}
|
||||
|
||||
EnchStoreItem(uint32 _ench, float _chance)
|
||||
: ench(_ench), chance(_chance) {}
|
||||
};
|
||||
|
||||
typedef std::vector<EnchStoreItem> EnchStoreList;
|
||||
typedef UNORDERED_MAP<uint32, EnchStoreList> EnchantmentStore;
|
||||
|
||||
static EnchantmentStore RandomItemEnch;
|
||||
|
||||
void LoadRandomEnchantmentsTable()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
RandomItemEnch.clear(); // for reload case
|
||||
|
||||
// 0 1 2
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, ench, chance FROM item_enchantment_template");
|
||||
|
||||
if (result)
|
||||
{
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 entry = fields[0].GetUInt32();
|
||||
uint32 ench = fields[1].GetUInt32();
|
||||
float chance = fields[2].GetFloat();
|
||||
|
||||
if (chance > 0.000001f && chance <= 100.0f)
|
||||
RandomItemEnch[entry].push_back(EnchStoreItem(ench, chance));
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u Item Enchantment definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog->outErrorDb(">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty.");
|
||||
sLog->outString();
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetItemEnchantMod(int32 entry)
|
||||
{
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
if (entry == -1)
|
||||
return 0;
|
||||
|
||||
EnchantmentStore::const_iterator tab = RandomItemEnch.find(entry);
|
||||
if (tab == RandomItemEnch.end())
|
||||
{
|
||||
sLog->outErrorDb("Item RandomProperty / RandomSuffix id #%u used in `item_template` but it does not have records in `item_enchantment_template` table.", entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
double dRoll = rand_chance();
|
||||
float fCount = 0;
|
||||
|
||||
for (EnchStoreList::const_iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter)
|
||||
{
|
||||
fCount += ench_iter->chance;
|
||||
|
||||
if (fCount > dRoll)
|
||||
return ench_iter->ench;
|
||||
}
|
||||
|
||||
//we could get here only if sum of all enchantment chances is lower than 100%
|
||||
dRoll = (irand(0, (int)floor(fCount * 100) + 1)) / 100;
|
||||
fCount = 0;
|
||||
|
||||
for (EnchStoreList::const_iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter)
|
||||
{
|
||||
fCount += ench_iter->chance;
|
||||
|
||||
if (fCount > dRoll)
|
||||
return ench_iter->ench;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 GenerateEnchSuffixFactor(uint32 item_id)
|
||||
{
|
||||
ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_id);
|
||||
|
||||
if (!itemProto)
|
||||
return 0;
|
||||
if (!itemProto->RandomSuffix)
|
||||
return 0;
|
||||
|
||||
RandomPropertiesPointsEntry const* randomProperty = sRandomPropertiesPointsStore.LookupEntry(itemProto->ItemLevel);
|
||||
if (!randomProperty)
|
||||
return 0;
|
||||
|
||||
uint32 suffixFactor;
|
||||
switch (itemProto->InventoryType)
|
||||
{
|
||||
// Items of that type don`t have points
|
||||
case INVTYPE_NON_EQUIP:
|
||||
case INVTYPE_BAG:
|
||||
case INVTYPE_TABARD:
|
||||
case INVTYPE_AMMO:
|
||||
case INVTYPE_QUIVER:
|
||||
case INVTYPE_RELIC:
|
||||
return 0;
|
||||
// Select point coefficient
|
||||
case INVTYPE_HEAD:
|
||||
case INVTYPE_BODY:
|
||||
case INVTYPE_CHEST:
|
||||
case INVTYPE_LEGS:
|
||||
case INVTYPE_2HWEAPON:
|
||||
case INVTYPE_ROBE:
|
||||
suffixFactor = 0;
|
||||
break;
|
||||
case INVTYPE_SHOULDERS:
|
||||
case INVTYPE_WAIST:
|
||||
case INVTYPE_FEET:
|
||||
case INVTYPE_HANDS:
|
||||
case INVTYPE_TRINKET:
|
||||
suffixFactor = 1;
|
||||
break;
|
||||
case INVTYPE_NECK:
|
||||
case INVTYPE_WRISTS:
|
||||
case INVTYPE_FINGER:
|
||||
case INVTYPE_SHIELD:
|
||||
case INVTYPE_CLOAK:
|
||||
case INVTYPE_HOLDABLE:
|
||||
suffixFactor = 2;
|
||||
break;
|
||||
case INVTYPE_WEAPON:
|
||||
case INVTYPE_WEAPONMAINHAND:
|
||||
case INVTYPE_WEAPONOFFHAND:
|
||||
suffixFactor = 3;
|
||||
break;
|
||||
case INVTYPE_RANGED:
|
||||
case INVTYPE_THROWN:
|
||||
case INVTYPE_RANGEDRIGHT:
|
||||
suffixFactor = 4;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
// Select rare/epic modifier
|
||||
switch (itemProto->Quality)
|
||||
{
|
||||
case ITEM_QUALITY_UNCOMMON:
|
||||
return randomProperty->UncommonPropertiesPoints[suffixFactor];
|
||||
case ITEM_QUALITY_RARE:
|
||||
return randomProperty->RarePropertiesPoints[suffixFactor];
|
||||
case ITEM_QUALITY_EPIC:
|
||||
return randomProperty->EpicPropertiesPoints[suffixFactor];
|
||||
case ITEM_QUALITY_LEGENDARY:
|
||||
case ITEM_QUALITY_ARTIFACT:
|
||||
return 0; // not have random properties
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ITEM_ENCHANTMENT_MGR_H
|
||||
#define _ITEM_ENCHANTMENT_MGR_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
void LoadRandomEnchantmentsTable();
|
||||
uint32 GetItemEnchantMod(int32 entry);
|
||||
uint32 GenerateEnchSuffixFactor(uint32 item_id);
|
||||
#endif
|
||||
|
||||
@@ -1,812 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ITEMPROTOTYPE_H
|
||||
#define _ITEMPROTOTYPE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
enum ItemModType
|
||||
{
|
||||
ITEM_MOD_MANA = 0,
|
||||
ITEM_MOD_HEALTH = 1,
|
||||
ITEM_MOD_AGILITY = 3,
|
||||
ITEM_MOD_STRENGTH = 4,
|
||||
ITEM_MOD_INTELLECT = 5,
|
||||
ITEM_MOD_SPIRIT = 6,
|
||||
ITEM_MOD_STAMINA = 7,
|
||||
ITEM_MOD_DEFENSE_SKILL_RATING = 12,
|
||||
ITEM_MOD_DODGE_RATING = 13,
|
||||
ITEM_MOD_PARRY_RATING = 14,
|
||||
ITEM_MOD_BLOCK_RATING = 15,
|
||||
ITEM_MOD_HIT_MELEE_RATING = 16,
|
||||
ITEM_MOD_HIT_RANGED_RATING = 17,
|
||||
ITEM_MOD_HIT_SPELL_RATING = 18,
|
||||
ITEM_MOD_CRIT_MELEE_RATING = 19,
|
||||
ITEM_MOD_CRIT_RANGED_RATING = 20,
|
||||
ITEM_MOD_CRIT_SPELL_RATING = 21,
|
||||
ITEM_MOD_HIT_TAKEN_MELEE_RATING = 22,
|
||||
ITEM_MOD_HIT_TAKEN_RANGED_RATING = 23,
|
||||
ITEM_MOD_HIT_TAKEN_SPELL_RATING = 24,
|
||||
ITEM_MOD_CRIT_TAKEN_MELEE_RATING = 25,
|
||||
ITEM_MOD_CRIT_TAKEN_RANGED_RATING = 26,
|
||||
ITEM_MOD_CRIT_TAKEN_SPELL_RATING = 27,
|
||||
ITEM_MOD_HASTE_MELEE_RATING = 28,
|
||||
ITEM_MOD_HASTE_RANGED_RATING = 29,
|
||||
ITEM_MOD_HASTE_SPELL_RATING = 30,
|
||||
ITEM_MOD_HIT_RATING = 31,
|
||||
ITEM_MOD_CRIT_RATING = 32,
|
||||
ITEM_MOD_HIT_TAKEN_RATING = 33,
|
||||
ITEM_MOD_CRIT_TAKEN_RATING = 34,
|
||||
ITEM_MOD_RESILIENCE_RATING = 35,
|
||||
ITEM_MOD_HASTE_RATING = 36,
|
||||
ITEM_MOD_EXPERTISE_RATING = 37,
|
||||
ITEM_MOD_ATTACK_POWER = 38,
|
||||
ITEM_MOD_RANGED_ATTACK_POWER = 39,
|
||||
//ITEM_MOD_FERAL_ATTACK_POWER = 40, not in 3.3
|
||||
ITEM_MOD_SPELL_HEALING_DONE = 41, // deprecated
|
||||
ITEM_MOD_SPELL_DAMAGE_DONE = 42, // deprecated
|
||||
ITEM_MOD_MANA_REGENERATION = 43,
|
||||
ITEM_MOD_ARMOR_PENETRATION_RATING = 44,
|
||||
ITEM_MOD_SPELL_POWER = 45,
|
||||
ITEM_MOD_HEALTH_REGEN = 46,
|
||||
ITEM_MOD_SPELL_PENETRATION = 47,
|
||||
ITEM_MOD_BLOCK_VALUE = 48
|
||||
};
|
||||
|
||||
#define MAX_ITEM_MOD 49
|
||||
|
||||
enum ItemSpelltriggerType
|
||||
{
|
||||
ITEM_SPELLTRIGGER_ON_USE = 0, // use after equip cooldown
|
||||
ITEM_SPELLTRIGGER_ON_EQUIP = 1,
|
||||
ITEM_SPELLTRIGGER_CHANCE_ON_HIT = 2,
|
||||
ITEM_SPELLTRIGGER_SOULSTONE = 4,
|
||||
/*
|
||||
* ItemSpelltriggerType 5 might have changed on 2.4.3/3.0.3: Such auras
|
||||
* will be applied on item pickup and removed on item loss - maybe on the
|
||||
* other hand the item is destroyed if the aura is removed ("removed on
|
||||
* death" of spell 57348 makes me think so)
|
||||
*/
|
||||
ITEM_SPELLTRIGGER_ON_NO_DELAY_USE = 5, // no equip cooldown
|
||||
ITEM_SPELLTRIGGER_LEARN_SPELL_ID = 6 // used in item_template.spell_2 with spell_id with SPELL_GENERIC_LEARN in spell_1
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SPELLTRIGGER 7
|
||||
|
||||
enum ItemBondingType
|
||||
{
|
||||
NO_BIND = 0,
|
||||
BIND_WHEN_PICKED_UP = 1,
|
||||
BIND_WHEN_EQUIPED = 2,
|
||||
BIND_WHEN_USE = 3,
|
||||
BIND_QUEST_ITEM = 4,
|
||||
BIND_QUEST_ITEM1 = 5 // not used in game
|
||||
};
|
||||
|
||||
#define MAX_BIND_TYPE 6
|
||||
|
||||
/* TODO
|
||||
// need to know cases when using item is not allowed in shapeshift
|
||||
ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms
|
||||
*/
|
||||
|
||||
enum ItemProtoFlags
|
||||
{
|
||||
ITEM_PROTO_FLAG_UNK1 = 0x00000001, // ?
|
||||
ITEM_PROTO_FLAG_CONJURED = 0x00000002, // Conjured item
|
||||
ITEM_PROTO_FLAG_OPENABLE = 0x00000004, // Item can be right clicked to open for loot
|
||||
ITEM_PROTO_FLAG_HEROIC = 0x00000008, // Makes green "Heroic" text appear on item
|
||||
ITEM_PROTO_FLAG_DEPRECATED = 0x00000010, // Cannot equip or use
|
||||
ITEM_PROTO_FLAG_INDESTRUCTIBLE = 0x00000020, // Item can not be destroyed, except by using spell (item can be reagent for spell)
|
||||
ITEM_PROTO_FLAG_UNK2 = 0x00000040, // ?
|
||||
ITEM_PROTO_FLAG_NO_EQUIP_COOLDOWN = 0x00000080, // No default 30 seconds cooldown when equipped
|
||||
ITEM_PROTO_FLAG_UNK3 = 0x00000100, // ?
|
||||
ITEM_PROTO_FLAG_WRAPPER = 0x00000200, // Item can wrap other items
|
||||
ITEM_PROTO_FLAG_UNK4 = 0x00000400, // ?
|
||||
ITEM_PROTO_FLAG_PARTY_LOOT = 0x00000800, // Looting this item does not remove it from available loot
|
||||
ITEM_PROTO_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost)
|
||||
ITEM_PROTO_FLAG_CHARTER = 0x00002000, // Item is guild or arena charter
|
||||
ITEM_PROTO_FLAG_UNK5 = 0x00004000, // Only readable items have this (but not all)
|
||||
ITEM_PROTO_FLAG_UNK6 = 0x00008000, // ?
|
||||
ITEM_PROTO_FLAG_UNK7 = 0x00010000, // ?
|
||||
ITEM_PROTO_FLAG_UNK8 = 0x00020000, // ?
|
||||
ITEM_PROTO_FLAG_PROSPECTABLE = 0x00040000, // Item can be prospected
|
||||
ITEM_PROTO_FLAG_UNIQUE_EQUIPPED = 0x00080000, // You can only equip one of these
|
||||
ITEM_PROTO_FLAG_UNK9 = 0x00100000, // ?
|
||||
ITEM_PROTO_FLAG_USEABLE_IN_ARENA = 0x00200000, // Item can be used during arena match
|
||||
ITEM_PROTO_FLAG_THROWABLE = 0x00400000, // Some Thrown weapons have it (and only Thrown) but not all
|
||||
ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms
|
||||
ITEM_PROTO_FLAG_UNK10 = 0x01000000, // ?
|
||||
ITEM_PROTO_FLAG_SMART_LOOT = 0x02000000, // Profession recipes: can only be looted if you meet requirements and don't already know it
|
||||
ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA = 0x04000000, // Item cannot be used in arena
|
||||
ITEM_PROTO_FLAG_BIND_TO_ACCOUNT = 0x08000000, // Item binds to account and can be sent only to your own characters
|
||||
ITEM_PROTO_FLAG_TRIGGERED_CAST = 0x10000000, // Spell is cast with triggered flag
|
||||
ITEM_PROTO_FLAG_MILLABLE = 0x20000000, // Item can be milled
|
||||
ITEM_PROTO_FLAG_UNK11 = 0x40000000, // ?
|
||||
ITEM_PROTO_FLAG_UNK12 = 0x80000000 // ?
|
||||
};
|
||||
|
||||
/* TODO
|
||||
*/
|
||||
|
||||
enum ItemFieldFlags
|
||||
{
|
||||
ITEM_FLAG_SOULBOUND = 0x00000001, // Item is soulbound and cannot be traded <<--
|
||||
ITEM_FLAG_UNK1 = 0x00000002, // ?
|
||||
ITEM_FLAG_UNLOCKED = 0x00000004, // Item had lock but can be opened now
|
||||
ITEM_FLAG_WRAPPED = 0x00000008, // Item is wrapped and contains another item
|
||||
ITEM_FLAG_UNK2 = 0x00000010, // ?
|
||||
ITEM_FLAG_UNK3 = 0x00000020, // ?
|
||||
ITEM_FLAG_UNK4 = 0x00000040, // ?
|
||||
ITEM_FLAG_UNK5 = 0x00000080, // ?
|
||||
ITEM_FLAG_BOP_TRADEABLE = 0x00000100, // Allows trading soulbound items
|
||||
ITEM_FLAG_READABLE = 0x00000200, // Opens text page when right clicked
|
||||
ITEM_FLAG_UNK6 = 0x00000400, // ?
|
||||
ITEM_FLAG_UNK7 = 0x00000800, // ?
|
||||
ITEM_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost)
|
||||
ITEM_FLAG_UNK8 = 0x00002000, // ?
|
||||
ITEM_FLAG_UNK9 = 0x00004000, // ?
|
||||
ITEM_FLAG_UNK10 = 0x00008000, // ?
|
||||
ITEM_FLAG_UNK11 = 0x00010000, // ?
|
||||
ITEM_FLAG_UNK12 = 0x00020000, // ?
|
||||
ITEM_FLAG_UNK13 = 0x00040000, // ?
|
||||
ITEM_FLAG_UNK14 = 0x00080000, // ?
|
||||
ITEM_FLAG_UNK15 = 0x00100000, // ?
|
||||
ITEM_FLAG_UNK16 = 0x00200000, // ?
|
||||
ITEM_FLAG_UNK17 = 0x00400000, // ?
|
||||
ITEM_FLAG_UNK18 = 0x00800000, // ?
|
||||
ITEM_FLAG_UNK19 = 0x01000000, // ?
|
||||
ITEM_FLAG_UNK20 = 0x02000000, // ?
|
||||
ITEM_FLAG_UNK21 = 0x04000000, // ?
|
||||
ITEM_FLAG_UNK22 = 0x08000000, // ?
|
||||
ITEM_FLAG_UNK23 = 0x10000000, // ?
|
||||
ITEM_FLAG_UNK24 = 0x20000000, // ?
|
||||
ITEM_FLAG_UNK25 = 0x40000000, // ?
|
||||
ITEM_FLAG_UNK26 = 0x80000000, // ?
|
||||
|
||||
ITEM_FLAG_MAIL_TEXT_MASK = ITEM_FLAG_READABLE | ITEM_FLAG_UNK13 | ITEM_FLAG_UNK14,
|
||||
};
|
||||
|
||||
enum ItemFlagsExtra
|
||||
{
|
||||
ITEM_FLAGS_EXTRA_HORDE_ONLY = 0x00000001,
|
||||
ITEM_FLAGS_EXTRA_ALLIANCE_ONLY = 0x00000002,
|
||||
ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD = 0x00000004, // when item uses extended cost, gold is also required
|
||||
ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100
|
||||
};
|
||||
|
||||
enum ItemFlagsCustom
|
||||
{
|
||||
ITEM_FLAGS_CU_DURATION_REAL_TIME = 0x0001, // Item duration will tick even if player is offline
|
||||
ITEM_FLAGS_CU_IGNORE_QUEST_STATUS = 0x0002, // No quest status will be checked when this item drops
|
||||
ITEM_FLAGS_CU_FOLLOW_LOOT_RULES = 0x0004, // Item will always follow group/master/need before greed looting rules
|
||||
};
|
||||
|
||||
enum BAG_FAMILY_MASK
|
||||
{
|
||||
BAG_FAMILY_MASK_NONE = 0x00000000,
|
||||
BAG_FAMILY_MASK_ARROWS = 0x00000001,
|
||||
BAG_FAMILY_MASK_BULLETS = 0x00000002,
|
||||
BAG_FAMILY_MASK_SOUL_SHARDS = 0x00000004,
|
||||
BAG_FAMILY_MASK_LEATHERWORKING_SUPP = 0x00000008,
|
||||
BAG_FAMILY_MASK_INSCRIPTION_SUPP = 0x00000010,
|
||||
BAG_FAMILY_MASK_HERBS = 0x00000020,
|
||||
BAG_FAMILY_MASK_ENCHANTING_SUPP = 0x00000040,
|
||||
BAG_FAMILY_MASK_ENGINEERING_SUPP = 0x00000080,
|
||||
BAG_FAMILY_MASK_KEYS = 0x00000100,
|
||||
BAG_FAMILY_MASK_GEMS = 0x00000200,
|
||||
BAG_FAMILY_MASK_MINING_SUPP = 0x00000400,
|
||||
BAG_FAMILY_MASK_SOULBOUND_EQUIPMENT = 0x00000800,
|
||||
BAG_FAMILY_MASK_VANITY_PETS = 0x00001000,
|
||||
BAG_FAMILY_MASK_CURRENCY_TOKENS = 0x00002000,
|
||||
BAG_FAMILY_MASK_QUEST_ITEMS = 0x00004000
|
||||
};
|
||||
|
||||
enum SocketColor
|
||||
{
|
||||
SOCKET_COLOR_META = 1,
|
||||
SOCKET_COLOR_RED = 2,
|
||||
SOCKET_COLOR_YELLOW = 4,
|
||||
SOCKET_COLOR_BLUE = 8
|
||||
};
|
||||
|
||||
#define SOCKET_COLOR_ALL (SOCKET_COLOR_META | SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE)
|
||||
|
||||
enum InventoryType
|
||||
{
|
||||
INVTYPE_NON_EQUIP = 0,
|
||||
INVTYPE_HEAD = 1,
|
||||
INVTYPE_NECK = 2,
|
||||
INVTYPE_SHOULDERS = 3,
|
||||
INVTYPE_BODY = 4,
|
||||
INVTYPE_CHEST = 5,
|
||||
INVTYPE_WAIST = 6,
|
||||
INVTYPE_LEGS = 7,
|
||||
INVTYPE_FEET = 8,
|
||||
INVTYPE_WRISTS = 9,
|
||||
INVTYPE_HANDS = 10,
|
||||
INVTYPE_FINGER = 11,
|
||||
INVTYPE_TRINKET = 12,
|
||||
INVTYPE_WEAPON = 13,
|
||||
INVTYPE_SHIELD = 14,
|
||||
INVTYPE_RANGED = 15,
|
||||
INVTYPE_CLOAK = 16,
|
||||
INVTYPE_2HWEAPON = 17,
|
||||
INVTYPE_BAG = 18,
|
||||
INVTYPE_TABARD = 19,
|
||||
INVTYPE_ROBE = 20,
|
||||
INVTYPE_WEAPONMAINHAND = 21,
|
||||
INVTYPE_WEAPONOFFHAND = 22,
|
||||
INVTYPE_HOLDABLE = 23,
|
||||
INVTYPE_AMMO = 24,
|
||||
INVTYPE_THROWN = 25,
|
||||
INVTYPE_RANGEDRIGHT = 26,
|
||||
INVTYPE_QUIVER = 27,
|
||||
INVTYPE_RELIC = 28
|
||||
};
|
||||
|
||||
#define MAX_INVTYPE 29
|
||||
|
||||
enum ItemClass
|
||||
{
|
||||
ITEM_CLASS_CONSUMABLE = 0,
|
||||
ITEM_CLASS_CONTAINER = 1,
|
||||
ITEM_CLASS_WEAPON = 2,
|
||||
ITEM_CLASS_GEM = 3,
|
||||
ITEM_CLASS_ARMOR = 4,
|
||||
ITEM_CLASS_REAGENT = 5,
|
||||
ITEM_CLASS_PROJECTILE = 6,
|
||||
ITEM_CLASS_TRADE_GOODS = 7,
|
||||
ITEM_CLASS_GENERIC = 8,
|
||||
ITEM_CLASS_RECIPE = 9,
|
||||
ITEM_CLASS_MONEY = 10,
|
||||
ITEM_CLASS_QUIVER = 11,
|
||||
ITEM_CLASS_QUEST = 12,
|
||||
ITEM_CLASS_KEY = 13,
|
||||
ITEM_CLASS_PERMANENT = 14,
|
||||
ITEM_CLASS_MISC = 15,
|
||||
ITEM_CLASS_GLYPH = 16
|
||||
};
|
||||
|
||||
#define MAX_ITEM_CLASS 17
|
||||
|
||||
enum ItemSubclassConsumable
|
||||
{
|
||||
ITEM_SUBCLASS_CONSUMABLE = 0,
|
||||
ITEM_SUBCLASS_POTION = 1,
|
||||
ITEM_SUBCLASS_ELIXIR = 2,
|
||||
ITEM_SUBCLASS_FLASK = 3,
|
||||
ITEM_SUBCLASS_SCROLL = 4,
|
||||
ITEM_SUBCLASS_FOOD = 5,
|
||||
ITEM_SUBCLASS_ITEM_ENHANCEMENT = 6,
|
||||
ITEM_SUBCLASS_BANDAGE = 7,
|
||||
ITEM_SUBCLASS_CONSUMABLE_OTHER = 8
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_CONSUMABLE 9
|
||||
|
||||
enum ItemSubclassContainer
|
||||
{
|
||||
ITEM_SUBCLASS_CONTAINER = 0,
|
||||
ITEM_SUBCLASS_SOUL_CONTAINER = 1,
|
||||
ITEM_SUBCLASS_HERB_CONTAINER = 2,
|
||||
ITEM_SUBCLASS_ENCHANTING_CONTAINER = 3,
|
||||
ITEM_SUBCLASS_ENGINEERING_CONTAINER = 4,
|
||||
ITEM_SUBCLASS_GEM_CONTAINER = 5,
|
||||
ITEM_SUBCLASS_MINING_CONTAINER = 6,
|
||||
ITEM_SUBCLASS_LEATHERWORKING_CONTAINER = 7,
|
||||
ITEM_SUBCLASS_INSCRIPTION_CONTAINER = 8
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_CONTAINER 9
|
||||
|
||||
enum ItemSubclassWeapon
|
||||
{
|
||||
ITEM_SUBCLASS_WEAPON_AXE = 0,
|
||||
ITEM_SUBCLASS_WEAPON_AXE2 = 1,
|
||||
ITEM_SUBCLASS_WEAPON_BOW = 2,
|
||||
ITEM_SUBCLASS_WEAPON_GUN = 3,
|
||||
ITEM_SUBCLASS_WEAPON_MACE = 4,
|
||||
ITEM_SUBCLASS_WEAPON_MACE2 = 5,
|
||||
ITEM_SUBCLASS_WEAPON_POLEARM = 6,
|
||||
ITEM_SUBCLASS_WEAPON_SWORD = 7,
|
||||
ITEM_SUBCLASS_WEAPON_SWORD2 = 8,
|
||||
ITEM_SUBCLASS_WEAPON_obsolete = 9,
|
||||
ITEM_SUBCLASS_WEAPON_STAFF = 10,
|
||||
ITEM_SUBCLASS_WEAPON_EXOTIC = 11,
|
||||
ITEM_SUBCLASS_WEAPON_EXOTIC2 = 12,
|
||||
ITEM_SUBCLASS_WEAPON_FIST = 13,
|
||||
ITEM_SUBCLASS_WEAPON_MISC = 14,
|
||||
ITEM_SUBCLASS_WEAPON_DAGGER = 15,
|
||||
ITEM_SUBCLASS_WEAPON_THROWN = 16,
|
||||
ITEM_SUBCLASS_WEAPON_SPEAR = 17,
|
||||
ITEM_SUBCLASS_WEAPON_CROSSBOW = 18,
|
||||
ITEM_SUBCLASS_WEAPON_WAND = 19,
|
||||
ITEM_SUBCLASS_WEAPON_FISHING_POLE = 20
|
||||
};
|
||||
|
||||
#define ITEM_SUBCLASS_MASK_WEAPON_RANGED (\
|
||||
(1 << ITEM_SUBCLASS_WEAPON_BOW) | (1 << ITEM_SUBCLASS_WEAPON_GUN) |\
|
||||
(1 << ITEM_SUBCLASS_WEAPON_CROSSBOW) | (1 << ITEM_SUBCLASS_WEAPON_THROWN))
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_WEAPON 21
|
||||
|
||||
enum ItemSubclassGem
|
||||
{
|
||||
ITEM_SUBCLASS_GEM_RED = 0,
|
||||
ITEM_SUBCLASS_GEM_BLUE = 1,
|
||||
ITEM_SUBCLASS_GEM_YELLOW = 2,
|
||||
ITEM_SUBCLASS_GEM_PURPLE = 3,
|
||||
ITEM_SUBCLASS_GEM_GREEN = 4,
|
||||
ITEM_SUBCLASS_GEM_ORANGE = 5,
|
||||
ITEM_SUBCLASS_GEM_META = 6,
|
||||
ITEM_SUBCLASS_GEM_SIMPLE = 7,
|
||||
ITEM_SUBCLASS_GEM_PRISMATIC = 8
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_GEM 9
|
||||
|
||||
enum ItemSubclassArmor
|
||||
{
|
||||
ITEM_SUBCLASS_ARMOR_MISC = 0,
|
||||
ITEM_SUBCLASS_ARMOR_CLOTH = 1,
|
||||
ITEM_SUBCLASS_ARMOR_LEATHER = 2,
|
||||
ITEM_SUBCLASS_ARMOR_MAIL = 3,
|
||||
ITEM_SUBCLASS_ARMOR_PLATE = 4,
|
||||
ITEM_SUBCLASS_ARMOR_BUCKLER = 5,
|
||||
ITEM_SUBCLASS_ARMOR_SHIELD = 6,
|
||||
ITEM_SUBCLASS_ARMOR_LIBRAM = 7,
|
||||
ITEM_SUBCLASS_ARMOR_IDOL = 8,
|
||||
ITEM_SUBCLASS_ARMOR_TOTEM = 9,
|
||||
ITEM_SUBCLASS_ARMOR_SIGIL = 10
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_ARMOR 11
|
||||
|
||||
enum ItemSubclassReagent
|
||||
{
|
||||
ITEM_SUBCLASS_REAGENT = 0
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_REAGENT 1
|
||||
|
||||
enum ItemSubclassProjectile
|
||||
{
|
||||
ITEM_SUBCLASS_WAND = 0, // ABS
|
||||
ITEM_SUBCLASS_BOLT = 1, // ABS
|
||||
ITEM_SUBCLASS_ARROW = 2,
|
||||
ITEM_SUBCLASS_BULLET = 3,
|
||||
ITEM_SUBCLASS_THROWN = 4 // ABS
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_PROJECTILE 5
|
||||
|
||||
enum ItemSubclassTradeGoods
|
||||
{
|
||||
ITEM_SUBCLASS_TRADE_GOODS = 0,
|
||||
ITEM_SUBCLASS_PARTS = 1,
|
||||
ITEM_SUBCLASS_EXPLOSIVES = 2,
|
||||
ITEM_SUBCLASS_DEVICES = 3,
|
||||
ITEM_SUBCLASS_JEWELCRAFTING = 4,
|
||||
ITEM_SUBCLASS_CLOTH = 5,
|
||||
ITEM_SUBCLASS_LEATHER = 6,
|
||||
ITEM_SUBCLASS_METAL_STONE = 7,
|
||||
ITEM_SUBCLASS_MEAT = 8,
|
||||
ITEM_SUBCLASS_HERB = 9,
|
||||
ITEM_SUBCLASS_ELEMENTAL = 10,
|
||||
ITEM_SUBCLASS_TRADE_GOODS_OTHER = 11,
|
||||
ITEM_SUBCLASS_ENCHANTING = 12,
|
||||
ITEM_SUBCLASS_MATERIAL = 13,
|
||||
ITEM_SUBCLASS_ARMOR_ENCHANTMENT = 14,
|
||||
ITEM_SUBCLASS_WEAPON_ENCHANTMENT = 15
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_TRADE_GOODS 16
|
||||
|
||||
enum ItemSubclassGeneric
|
||||
{
|
||||
ITEM_SUBCLASS_GENERIC = 0
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_GENERIC 1
|
||||
|
||||
enum ItemSubclassRecipe
|
||||
{
|
||||
ITEM_SUBCLASS_BOOK = 0,
|
||||
ITEM_SUBCLASS_LEATHERWORKING_PATTERN = 1,
|
||||
ITEM_SUBCLASS_TAILORING_PATTERN = 2,
|
||||
ITEM_SUBCLASS_ENGINEERING_SCHEMATIC = 3,
|
||||
ITEM_SUBCLASS_BLACKSMITHING = 4,
|
||||
ITEM_SUBCLASS_COOKING_RECIPE = 5,
|
||||
ITEM_SUBCLASS_ALCHEMY_RECIPE = 6,
|
||||
ITEM_SUBCLASS_FIRST_AID_MANUAL = 7,
|
||||
ITEM_SUBCLASS_ENCHANTING_FORMULA = 8,
|
||||
ITEM_SUBCLASS_FISHING_MANUAL = 9,
|
||||
ITEM_SUBCLASS_JEWELCRAFTING_RECIPE = 10
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_RECIPE 11
|
||||
|
||||
enum ItemSubclassMoney
|
||||
{
|
||||
ITEM_SUBCLASS_MONEY = 0
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_MONEY 1
|
||||
|
||||
enum ItemSubclassQuiver
|
||||
{
|
||||
ITEM_SUBCLASS_QUIVER0 = 0, // ABS
|
||||
ITEM_SUBCLASS_QUIVER1 = 1, // ABS
|
||||
ITEM_SUBCLASS_QUIVER = 2,
|
||||
ITEM_SUBCLASS_AMMO_POUCH = 3
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_QUIVER 4
|
||||
|
||||
enum ItemSubclassQuest
|
||||
{
|
||||
ITEM_SUBCLASS_QUEST = 0
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_QUEST 1
|
||||
|
||||
enum ItemSubclassKey
|
||||
{
|
||||
ITEM_SUBCLASS_KEY = 0,
|
||||
ITEM_SUBCLASS_LOCKPICK = 1
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_KEY 2
|
||||
|
||||
enum ItemSubclassPermanent
|
||||
{
|
||||
ITEM_SUBCLASS_PERMANENT = 0
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_PERMANENT 1
|
||||
|
||||
enum ItemSubclassJunk
|
||||
{
|
||||
ITEM_SUBCLASS_JUNK = 0,
|
||||
ITEM_SUBCLASS_JUNK_REAGENT = 1,
|
||||
ITEM_SUBCLASS_JUNK_PET = 2,
|
||||
ITEM_SUBCLASS_JUNK_HOLIDAY = 3,
|
||||
ITEM_SUBCLASS_JUNK_OTHER = 4,
|
||||
ITEM_SUBCLASS_JUNK_MOUNT = 5
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_JUNK 6
|
||||
|
||||
enum ItemSubclassGlyph
|
||||
{
|
||||
ITEM_SUBCLASS_GLYPH_WARRIOR = 1,
|
||||
ITEM_SUBCLASS_GLYPH_PALADIN = 2,
|
||||
ITEM_SUBCLASS_GLYPH_HUNTER = 3,
|
||||
ITEM_SUBCLASS_GLYPH_ROGUE = 4,
|
||||
ITEM_SUBCLASS_GLYPH_PRIEST = 5,
|
||||
ITEM_SUBCLASS_GLYPH_DEATH_KNIGHT = 6,
|
||||
ITEM_SUBCLASS_GLYPH_SHAMAN = 7,
|
||||
ITEM_SUBCLASS_GLYPH_MAGE = 8,
|
||||
ITEM_SUBCLASS_GLYPH_WARLOCK = 9,
|
||||
ITEM_SUBCLASS_GLYPH_DRUID = 11
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SUBCLASS_GLYPH 12
|
||||
|
||||
const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] =
|
||||
{
|
||||
MAX_ITEM_SUBCLASS_CONSUMABLE,
|
||||
MAX_ITEM_SUBCLASS_CONTAINER,
|
||||
MAX_ITEM_SUBCLASS_WEAPON,
|
||||
MAX_ITEM_SUBCLASS_GEM,
|
||||
MAX_ITEM_SUBCLASS_ARMOR,
|
||||
MAX_ITEM_SUBCLASS_REAGENT,
|
||||
MAX_ITEM_SUBCLASS_PROJECTILE,
|
||||
MAX_ITEM_SUBCLASS_TRADE_GOODS,
|
||||
MAX_ITEM_SUBCLASS_GENERIC,
|
||||
MAX_ITEM_SUBCLASS_RECIPE,
|
||||
MAX_ITEM_SUBCLASS_MONEY,
|
||||
MAX_ITEM_SUBCLASS_QUIVER,
|
||||
MAX_ITEM_SUBCLASS_QUEST,
|
||||
MAX_ITEM_SUBCLASS_KEY,
|
||||
MAX_ITEM_SUBCLASS_PERMANENT,
|
||||
MAX_ITEM_SUBCLASS_JUNK,
|
||||
MAX_ITEM_SUBCLASS_GLYPH
|
||||
};
|
||||
|
||||
inline uint8 ItemSubClassToDurabilityMultiplierId(uint32 ItemClass, uint32 ItemSubClass)
|
||||
{
|
||||
switch (ItemClass)
|
||||
{
|
||||
case ITEM_CLASS_WEAPON: return ItemSubClass;
|
||||
case ITEM_CLASS_ARMOR: return ItemSubClass + 21;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct _Damage
|
||||
{
|
||||
float DamageMin;
|
||||
float DamageMax;
|
||||
uint32 DamageType; // id from Resistances.dbc
|
||||
};
|
||||
|
||||
struct _ItemStat
|
||||
{
|
||||
uint32 ItemStatType;
|
||||
int32 ItemStatValue;
|
||||
};
|
||||
struct _Spell
|
||||
{
|
||||
int32 SpellId; // id from Spell.dbc
|
||||
uint32 SpellTrigger;
|
||||
int32 SpellCharges;
|
||||
float SpellPPMRate;
|
||||
int32 SpellCooldown;
|
||||
uint32 SpellCategory; // id from SpellCategory.dbc
|
||||
int32 SpellCategoryCooldown;
|
||||
};
|
||||
|
||||
struct _Socket
|
||||
{
|
||||
uint32 Color;
|
||||
uint32 Content;
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#define MAX_ITEM_PROTO_DAMAGES 2 // changed in 3.1.0
|
||||
#define MAX_ITEM_PROTO_SOCKETS 3
|
||||
#define MAX_ITEM_PROTO_SPELLS 5
|
||||
#define MAX_ITEM_PROTO_STATS 10
|
||||
|
||||
struct ItemTemplate
|
||||
{
|
||||
uint32 ItemId;
|
||||
uint32 Class; // id from ItemClass.dbc
|
||||
uint32 SubClass; // id from ItemSubClass.dbc
|
||||
int32 SoundOverrideSubclass; // < 0: id from ItemSubClass.dbc, used to override weapon sound from actual SubClass
|
||||
std::string Name1;
|
||||
uint32 DisplayInfoID; // id from ItemDisplayInfo.dbc
|
||||
uint32 Quality;
|
||||
uint32 Flags;
|
||||
uint32 Flags2;
|
||||
uint32 BuyCount;
|
||||
int32 BuyPrice;
|
||||
uint32 SellPrice;
|
||||
uint32 InventoryType;
|
||||
uint32 AllowableClass;
|
||||
uint32 AllowableRace;
|
||||
uint32 ItemLevel;
|
||||
uint32 RequiredLevel;
|
||||
uint32 RequiredSkill; // id from SkillLine.dbc
|
||||
uint32 RequiredSkillRank;
|
||||
uint32 RequiredSpell; // id from Spell.dbc
|
||||
uint32 RequiredHonorRank;
|
||||
uint32 RequiredCityRank;
|
||||
uint32 RequiredReputationFaction; // id from Faction.dbc
|
||||
uint32 RequiredReputationRank;
|
||||
int32 MaxCount; // <= 0: no limit
|
||||
int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot)
|
||||
uint32 ContainerSlots;
|
||||
uint32 StatsCount;
|
||||
_ItemStat ItemStat[MAX_ITEM_PROTO_STATS];
|
||||
uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc
|
||||
uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc
|
||||
_Damage Damage[MAX_ITEM_PROTO_DAMAGES];
|
||||
uint32 Armor;
|
||||
uint32 HolyRes;
|
||||
uint32 FireRes;
|
||||
uint32 NatureRes;
|
||||
uint32 FrostRes;
|
||||
uint32 ShadowRes;
|
||||
uint32 ArcaneRes;
|
||||
uint32 Delay;
|
||||
uint32 AmmoType;
|
||||
float RangedModRange;
|
||||
_Spell Spells[MAX_ITEM_PROTO_SPELLS];
|
||||
uint32 Bonding;
|
||||
std::string Description;
|
||||
uint32 PageText;
|
||||
uint32 LanguageID;
|
||||
uint32 PageMaterial;
|
||||
uint32 StartQuest; // id from QuestCache.wdb
|
||||
uint32 LockID;
|
||||
int32 Material; // id from Material.dbc
|
||||
uint32 Sheath;
|
||||
int32 RandomProperty; // id from ItemRandomProperties.dbc
|
||||
int32 RandomSuffix; // id from ItemRandomSuffix.dbc
|
||||
uint32 Block;
|
||||
uint32 ItemSet; // id from ItemSet.dbc
|
||||
uint32 MaxDurability;
|
||||
uint32 Area; // id from AreaTable.dbc
|
||||
uint32 Map; // id from Map.dbc
|
||||
uint32 BagFamily; // bit mask (1 << id from ItemBagFamily.dbc)
|
||||
uint32 TotemCategory; // id from TotemCategory.dbc
|
||||
_Socket Socket[MAX_ITEM_PROTO_SOCKETS];
|
||||
uint32 socketBonus; // id from SpellItemEnchantment.dbc
|
||||
uint32 GemProperties; // id from GemProperties.dbc
|
||||
uint32 RequiredDisenchantSkill;
|
||||
float ArmorDamageModifier;
|
||||
uint32 Duration;
|
||||
uint32 ItemLimitCategory; // id from ItemLimitCategory.dbc
|
||||
uint32 HolidayId; // id from Holidays.dbc
|
||||
uint32 ScriptId;
|
||||
uint32 DisenchantID;
|
||||
uint32 FoodType;
|
||||
uint32 MinMoneyLoot;
|
||||
uint32 MaxMoneyLoot;
|
||||
uint32 FlagsCu;
|
||||
WorldPacket queryData; // pussywizard
|
||||
|
||||
// helpers
|
||||
bool CanChangeEquipStateInCombat() const
|
||||
{
|
||||
switch (InventoryType)
|
||||
{
|
||||
case INVTYPE_RELIC:
|
||||
case INVTYPE_SHIELD:
|
||||
case INVTYPE_HOLDABLE:
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (Class)
|
||||
{
|
||||
case ITEM_CLASS_WEAPON:
|
||||
case ITEM_CLASS_PROJECTILE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsCurrencyToken() const { return BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS; }
|
||||
|
||||
uint32 GetMaxStackSize() const
|
||||
{
|
||||
return (Stackable == 2147483647 || Stackable <= 0) ? uint32(0x7FFFFFFF-1) : uint32(Stackable);
|
||||
}
|
||||
|
||||
float getDPS() const
|
||||
{
|
||||
if (Delay == 0)
|
||||
return 0;
|
||||
float temp = 0;
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
temp+=Damage[i].DamageMin + Damage[i].DamageMax;
|
||||
return temp*500/Delay;
|
||||
}
|
||||
|
||||
int32 getFeralBonus(int32 extraDPS = 0) const
|
||||
{
|
||||
// 0x02A5F3 - is mask for Melee weapon from ItemSubClassMask.dbc
|
||||
if (Class == ITEM_CLASS_WEAPON && (1<<SubClass)&0x02A5F3)
|
||||
{
|
||||
int32 bonus = int32((extraDPS + getDPS())*14.0f) - 767;
|
||||
if (bonus < 0)
|
||||
return 0;
|
||||
return bonus;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float GetItemLevelIncludingQuality(uint8 pLevel) const
|
||||
{
|
||||
float itemLevel = (float)ItemLevel;
|
||||
switch (Quality)
|
||||
{
|
||||
case ITEM_QUALITY_POOR:
|
||||
case ITEM_QUALITY_NORMAL:
|
||||
case ITEM_QUALITY_UNCOMMON:
|
||||
itemLevel -= 26.0f;
|
||||
break;
|
||||
case ITEM_QUALITY_RARE:
|
||||
itemLevel -= 13.0f;
|
||||
break;
|
||||
case ITEM_QUALITY_HEIRLOOM:
|
||||
itemLevel = pLevel*2.33f;
|
||||
break;
|
||||
case ITEM_QUALITY_ARTIFACT:
|
||||
case ITEM_QUALITY_EPIC:
|
||||
case ITEM_QUALITY_LEGENDARY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return std::max<float>(0.f, itemLevel);
|
||||
}
|
||||
|
||||
uint32 GetSkill() const
|
||||
{
|
||||
const static uint32 item_weapon_skills[MAX_ITEM_SUBCLASS_WEAPON] =
|
||||
{
|
||||
SKILL_AXES, SKILL_2H_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES,
|
||||
SKILL_2H_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_2H_SWORDS, 0,
|
||||
SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0,
|
||||
SKILL_DAGGERS, SKILL_THROWN, SKILL_ASSASSINATION, SKILL_CROSSBOWS, SKILL_WANDS,
|
||||
SKILL_FISHING
|
||||
};
|
||||
|
||||
const static uint32 item_armor_skills[MAX_ITEM_SUBCLASS_ARMOR] =
|
||||
{
|
||||
0, SKILL_CLOTH, SKILL_LEATHER, SKILL_MAIL, SKILL_PLATE_MAIL, 0, SKILL_SHIELD, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
switch (Class)
|
||||
{
|
||||
case ITEM_CLASS_WEAPON:
|
||||
if (SubClass >= MAX_ITEM_SUBCLASS_WEAPON)
|
||||
return 0;
|
||||
else
|
||||
return item_weapon_skills[SubClass];
|
||||
|
||||
case ITEM_CLASS_ARMOR:
|
||||
if (SubClass >= MAX_ITEM_SUBCLASS_ARMOR)
|
||||
return 0;
|
||||
else
|
||||
return item_armor_skills[SubClass];
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPotion() const { return Class == ITEM_CLASS_CONSUMABLE && SubClass == ITEM_SUBCLASS_POTION; }
|
||||
bool IsWeaponVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_WEAPON_ENCHANTMENT; }
|
||||
bool IsArmorVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ARMOR_ENCHANTMENT; }
|
||||
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_PROTO_FLAG_CONJURED); }
|
||||
|
||||
void InitializeQueryData();
|
||||
};
|
||||
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
typedef UNORDERED_MAP<uint32, ItemTemplate> ItemTemplateContainer;
|
||||
|
||||
struct ItemLocale
|
||||
{
|
||||
StringVector Name;
|
||||
StringVector Description;
|
||||
};
|
||||
|
||||
struct ItemSetNameEntry
|
||||
{
|
||||
std::string name;
|
||||
uint32 InventoryType;
|
||||
};
|
||||
|
||||
struct ItemSetNameLocale
|
||||
{
|
||||
StringVector Name;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,254 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_OBJECTDEFINES_H
|
||||
#define TRINITY_OBJECTDEFINES_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
enum HighGuid
|
||||
{
|
||||
HIGHGUID_ITEM = 0x4000, // blizz 4000
|
||||
HIGHGUID_CONTAINER = 0x4000, // blizz 4000
|
||||
HIGHGUID_PLAYER = 0x0000, // blizz 0000
|
||||
HIGHGUID_GAMEOBJECT = 0xF110, // blizz F110
|
||||
HIGHGUID_TRANSPORT = 0xF120, // blizz F120 (for GAMEOBJECT_TYPE_TRANSPORT)
|
||||
HIGHGUID_UNIT = 0xF130, // blizz F130
|
||||
HIGHGUID_PET = 0xF140, // blizz F140
|
||||
HIGHGUID_VEHICLE = 0xF150, // blizz F550
|
||||
HIGHGUID_DYNAMICOBJECT = 0xF100, // blizz F100
|
||||
HIGHGUID_CORPSE = 0xF101, // blizz F100
|
||||
HIGHGUID_MO_TRANSPORT = 0x1FC0, // blizz 1FC0 (for GAMEOBJECT_TYPE_MO_TRANSPORT)
|
||||
HIGHGUID_GROUP = 0x1F50,
|
||||
HIGHGUID_INSTANCE = 0x1F42, // blizz 1F42/1F44/1F44/1F47
|
||||
};
|
||||
|
||||
// used for creating values for respawn for example
|
||||
inline uint64 MAKE_PAIR64(uint32 l, uint32 h);
|
||||
inline uint32 PAIR64_HIPART(uint64 x);
|
||||
inline uint32 PAIR64_LOPART(uint64 x);
|
||||
inline uint16 MAKE_PAIR16(uint8 l, uint8 h);
|
||||
inline uint32 MAKE_PAIR32(uint16 l, uint16 h);
|
||||
inline uint16 PAIR32_HIPART(uint32 x);
|
||||
inline uint16 PAIR32_LOPART(uint32 x);
|
||||
|
||||
inline bool IS_EMPTY_GUID(uint64 guid);
|
||||
inline bool IS_CREATURE_GUID(uint64 guid);
|
||||
inline bool IS_PET_GUID(uint64 guid);
|
||||
inline bool IS_VEHICLE_GUID(uint64 guid);
|
||||
inline bool IS_CRE_OR_VEH_GUID(uint64 guid);
|
||||
inline bool IS_CRE_OR_VEH_OR_PET_GUID(uint64 guid);
|
||||
inline bool IS_PLAYER_GUID(uint64 guid);
|
||||
inline bool IS_UNIT_GUID(uint64 guid);
|
||||
inline bool IS_ITEM_GUID(uint64 guid);
|
||||
inline bool IS_GAMEOBJECT_GUID(uint64 guid);
|
||||
inline bool IS_DYNAMICOBJECT_GUID(uint64 guid);
|
||||
inline bool IS_CORPSE_GUID(uint64 guid);
|
||||
inline bool IS_TRANSPORT_GUID(uint64 guid);
|
||||
inline bool IS_MO_TRANSPORT_GUID(uint64 guid);
|
||||
inline bool IS_GROUP_GUID(uint64 guid);
|
||||
|
||||
// l - OBJECT_FIELD_GUID
|
||||
// e - OBJECT_FIELD_ENTRY for GO (except GAMEOBJECT_TYPE_MO_TRANSPORT) and creatures or UNIT_FIELD_PETNUMBER for pets
|
||||
// h - OBJECT_FIELD_GUID + 1
|
||||
inline uint64 MAKE_NEW_GUID(uint32 l, uint32 e, uint32 h);
|
||||
|
||||
//#define GUID_HIPART(x) (uint32)((uint64(x) >> 52)) & 0x0000FFFF)
|
||||
inline uint32 GUID_HIPART(uint64 guid);
|
||||
inline uint32 GUID_ENPART(uint64 x);
|
||||
inline uint32 GUID_LOPART(uint64 x);
|
||||
|
||||
inline bool IsGuidHaveEnPart(uint64 guid);
|
||||
inline char const* GetLogNameForGuid(uint64 guid);
|
||||
|
||||
uint64 MAKE_PAIR64(uint32 l, uint32 h)
|
||||
{
|
||||
return uint64(l | (uint64(h) << 32));
|
||||
}
|
||||
|
||||
uint32 PAIR64_HIPART(uint64 x)
|
||||
{
|
||||
return (uint32)((x >> 32) & UI64LIT(0x00000000FFFFFFFF));
|
||||
}
|
||||
|
||||
uint32 PAIR64_LOPART(uint64 x)
|
||||
{
|
||||
return (uint32)(x & UI64LIT(0x00000000FFFFFFFF));
|
||||
}
|
||||
|
||||
uint16 MAKE_PAIR16(uint8 l, uint8 h)
|
||||
{
|
||||
return uint16(l | (uint16(h) << 8));
|
||||
}
|
||||
|
||||
uint32 MAKE_PAIR32(uint16 l, uint16 h)
|
||||
{
|
||||
return uint32(l | (uint32(h) << 16));
|
||||
}
|
||||
|
||||
uint16 PAIR32_HIPART(uint32 x)
|
||||
{
|
||||
return (uint16)((x >> 16) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
uint16 PAIR32_LOPART(uint32 x)
|
||||
{
|
||||
return (uint16)(x & 0x0000FFFF);
|
||||
}
|
||||
|
||||
bool IS_EMPTY_GUID(uint64 guid)
|
||||
{
|
||||
return guid == 0;
|
||||
}
|
||||
|
||||
bool IS_CREATURE_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_UNIT;
|
||||
}
|
||||
|
||||
bool IS_PET_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_PET;
|
||||
}
|
||||
|
||||
bool IS_VEHICLE_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_VEHICLE;
|
||||
}
|
||||
|
||||
bool IS_CRE_OR_VEH_GUID(uint64 guid)
|
||||
{
|
||||
return IS_CREATURE_GUID(guid) || IS_VEHICLE_GUID(guid);
|
||||
}
|
||||
|
||||
bool IS_CRE_OR_VEH_OR_PET_GUID(uint64 guid)
|
||||
{
|
||||
return IS_CRE_OR_VEH_GUID(guid) || IS_PET_GUID(guid);
|
||||
}
|
||||
|
||||
bool IS_PLAYER_GUID(uint64 guid)
|
||||
{
|
||||
return guid != 0 && GUID_HIPART(guid) == HIGHGUID_PLAYER;
|
||||
}
|
||||
|
||||
bool IS_UNIT_GUID(uint64 guid)
|
||||
{
|
||||
return IS_CRE_OR_VEH_OR_PET_GUID(guid) || IS_PLAYER_GUID(guid);
|
||||
}
|
||||
|
||||
bool IS_ITEM_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_ITEM;
|
||||
}
|
||||
|
||||
bool IS_GAMEOBJECT_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_GAMEOBJECT;
|
||||
}
|
||||
|
||||
bool IS_DYNAMICOBJECT_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_DYNAMICOBJECT;
|
||||
}
|
||||
|
||||
bool IS_CORPSE_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_CORPSE;
|
||||
}
|
||||
|
||||
bool IS_TRANSPORT_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_TRANSPORT;
|
||||
}
|
||||
|
||||
bool IS_MO_TRANSPORT_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_MO_TRANSPORT;
|
||||
}
|
||||
|
||||
bool IS_GROUP_GUID(uint64 guid)
|
||||
{
|
||||
return GUID_HIPART(guid) == HIGHGUID_GROUP;
|
||||
}
|
||||
|
||||
uint64 MAKE_NEW_GUID(uint32 l, uint32 e, uint32 h)
|
||||
{
|
||||
return uint64(uint64(l) | (uint64(e) << 24) | (uint64(h) << 48));
|
||||
}
|
||||
|
||||
uint32 GUID_HIPART(uint64 guid)
|
||||
{
|
||||
return (uint32)((uint64(guid) >> 48) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
uint32 GUID_ENPART(uint64 x)
|
||||
{
|
||||
return IsGuidHaveEnPart(x)
|
||||
? (uint32)((x >> 24) & UI64LIT(0x0000000000FFFFFF))
|
||||
: 0;
|
||||
}
|
||||
|
||||
uint32 GUID_LOPART(uint64 x)
|
||||
{
|
||||
return IsGuidHaveEnPart(x)
|
||||
? (uint32)(x & UI64LIT(0x0000000000FFFFFF))
|
||||
: (uint32)(x & UI64LIT(0x00000000FFFFFFFF));
|
||||
}
|
||||
|
||||
bool IsGuidHaveEnPart(uint64 guid)
|
||||
{
|
||||
switch (GUID_HIPART(guid))
|
||||
{
|
||||
case HIGHGUID_ITEM:
|
||||
case HIGHGUID_PLAYER:
|
||||
case HIGHGUID_DYNAMICOBJECT:
|
||||
case HIGHGUID_CORPSE:
|
||||
case HIGHGUID_GROUP:
|
||||
return false;
|
||||
case HIGHGUID_GAMEOBJECT:
|
||||
case HIGHGUID_TRANSPORT:
|
||||
case HIGHGUID_UNIT:
|
||||
case HIGHGUID_PET:
|
||||
case HIGHGUID_VEHICLE:
|
||||
case HIGHGUID_MO_TRANSPORT:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
char const* GetLogNameForGuid(uint64 guid)
|
||||
{
|
||||
switch (GUID_HIPART(guid))
|
||||
{
|
||||
case HIGHGUID_ITEM: return "item";
|
||||
case HIGHGUID_PLAYER: return guid ? "player" : "none";
|
||||
case HIGHGUID_GAMEOBJECT: return "gameobject";
|
||||
case HIGHGUID_TRANSPORT: return "transport";
|
||||
case HIGHGUID_UNIT: return "creature";
|
||||
case HIGHGUID_PET: return "pet";
|
||||
case HIGHGUID_VEHICLE: return "vehicle";
|
||||
case HIGHGUID_DYNAMICOBJECT:return "dynobject";
|
||||
case HIGHGUID_CORPSE: return "corpse";
|
||||
case HIGHGUID_MO_TRANSPORT: return "mo_transport";
|
||||
case HIGHGUID_GROUP: return "group";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ObjectPosSelector.h"
|
||||
|
||||
ObjectPosSelector::ObjectPosSelector(float x, float y, float size, float dist)
|
||||
: m_center_x(x), m_center_y(y), m_size(size), m_dist(dist)
|
||||
{
|
||||
m_anglestep = acos(m_dist/(m_dist+2*m_size));
|
||||
|
||||
m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].end();
|
||||
m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].end();
|
||||
|
||||
m_smallStepAngle[USED_POS_PLUS] = 0;
|
||||
m_smallStepAngle[USED_POS_MINUS] = 0;
|
||||
|
||||
m_smallStepOk[USED_POS_PLUS] = false;
|
||||
m_smallStepOk[USED_POS_MINUS] = false;
|
||||
|
||||
m_smallStepNextUsedPos[USED_POS_PLUS] = NULL;
|
||||
m_smallStepNextUsedPos[USED_POS_MINUS] = NULL;
|
||||
}
|
||||
|
||||
ObjectPosSelector::UsedPosList::value_type const* ObjectPosSelector::nextUsedPos(UsedPosType uptype)
|
||||
{
|
||||
UsedPosList::const_iterator itr = m_nextUsedPos[uptype];
|
||||
if (itr!=m_UsedPosLists[uptype].end())
|
||||
++itr;
|
||||
|
||||
if (itr==m_UsedPosLists[uptype].end())
|
||||
{
|
||||
if (!m_UsedPosLists[~uptype].empty())
|
||||
return &*m_UsedPosLists[~uptype].rbegin();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return &*itr;
|
||||
}
|
||||
|
||||
void ObjectPosSelector::AddUsedPos(float size, float angle, float dist)
|
||||
{
|
||||
if (angle >= 0)
|
||||
m_UsedPosLists[USED_POS_PLUS].insert(UsedPosList::value_type(angle, UsedPos(1.0f, size, dist)));
|
||||
else
|
||||
m_UsedPosLists[USED_POS_MINUS].insert(UsedPosList::value_type(-angle, UsedPos(-1.0f, size, dist)));
|
||||
}
|
||||
|
||||
void ObjectPosSelector::InitializeAngle()
|
||||
{
|
||||
m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].begin();
|
||||
m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].begin();
|
||||
|
||||
m_smallStepAngle[USED_POS_PLUS] = 0;
|
||||
m_smallStepAngle[USED_POS_MINUS] = 0;
|
||||
|
||||
m_smallStepOk[USED_POS_PLUS] = true;
|
||||
m_smallStepOk[USED_POS_MINUS] = true;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::FirstAngle(float& angle)
|
||||
{
|
||||
if (m_UsedPosLists[USED_POS_PLUS].empty() && !m_UsedPosLists[USED_POS_MINUS].empty())
|
||||
return NextAngleFor(*m_UsedPosLists[USED_POS_MINUS].begin(), 1.0f, USED_POS_PLUS, angle);
|
||||
else if (m_UsedPosLists[USED_POS_MINUS].empty() && !m_UsedPosLists[USED_POS_PLUS].empty())
|
||||
return NextAngleFor(*m_UsedPosLists[USED_POS_PLUS].begin(), -1.0f, USED_POS_MINUS, angle);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::NextAngle(float& angle)
|
||||
{
|
||||
while (m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
|
||||
m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() ||
|
||||
m_smallStepOk[USED_POS_PLUS] || m_smallStepOk[USED_POS_MINUS] )
|
||||
{
|
||||
// calculate next possible angle
|
||||
if (NextPosibleAngle(angle))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::NextUsedAngle(float& angle)
|
||||
{
|
||||
while (m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
|
||||
m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end())
|
||||
{
|
||||
// calculate next possible angle
|
||||
if (!NextPosibleAngle(angle))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::NextPosibleAngle(float& angle)
|
||||
{
|
||||
// ++ direction less updated
|
||||
if (m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() &&
|
||||
(m_nextUsedPos[USED_POS_MINUS]==m_UsedPosLists[USED_POS_MINUS].end() || m_nextUsedPos[USED_POS_PLUS]->first <= m_nextUsedPos[USED_POS_MINUS]->first))
|
||||
{
|
||||
bool ok;
|
||||
if (m_smallStepOk[USED_POS_PLUS])
|
||||
ok = NextSmallStepAngle(1.0f, USED_POS_PLUS, angle);
|
||||
else
|
||||
ok = NextAngleFor(*m_nextUsedPos[USED_POS_PLUS], 1.0f, USED_POS_PLUS, angle);
|
||||
|
||||
if (!ok)
|
||||
++m_nextUsedPos[USED_POS_PLUS]; // increase. only at fail (original or checked)
|
||||
return ok;
|
||||
}
|
||||
// -- direction less updated
|
||||
else if (m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end())
|
||||
{
|
||||
bool ok;
|
||||
if (m_smallStepOk[USED_POS_MINUS])
|
||||
ok = NextSmallStepAngle(-1.0f, USED_POS_MINUS, angle);
|
||||
else
|
||||
ok = NextAngleFor(*m_nextUsedPos[USED_POS_MINUS], -1.0f, USED_POS_MINUS, angle);
|
||||
|
||||
if (!ok)
|
||||
++m_nextUsedPos[USED_POS_MINUS];
|
||||
return ok;
|
||||
}
|
||||
else // both list empty
|
||||
{
|
||||
if (m_smallStepOk[USED_POS_PLUS] && (!m_smallStepOk[USED_POS_MINUS] || m_smallStepAngle[USED_POS_PLUS] <= m_smallStepAngle[USED_POS_MINUS]))
|
||||
return NextSmallStepAngle(1.0f, USED_POS_PLUS, angle);
|
||||
// -- direction less updated
|
||||
else if (m_smallStepOk[USED_POS_MINUS])
|
||||
return NextSmallStepAngle(-1.0f, USED_POS_MINUS, angle);
|
||||
}
|
||||
|
||||
// no angles
|
||||
return false;
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _OBJECT_POS_SELECTOR_H
|
||||
#define _OBJECT_POS_SELECTOR_H
|
||||
|
||||
#include<Common.h>
|
||||
|
||||
#include<map>
|
||||
|
||||
enum UsedPosType { USED_POS_PLUS, USED_POS_MINUS };
|
||||
|
||||
inline UsedPosType operator ~(UsedPosType uptype)
|
||||
{
|
||||
return uptype==USED_POS_PLUS ? USED_POS_MINUS : USED_POS_PLUS;
|
||||
}
|
||||
|
||||
struct ObjectPosSelector
|
||||
{
|
||||
struct UsedPos
|
||||
{
|
||||
UsedPos(float sign_, float size_, float dist_) : sign(sign_), size(size_), dist(dist_) {}
|
||||
|
||||
float sign;
|
||||
|
||||
float size; // size of point
|
||||
float dist; // dist to central point (including central point size)
|
||||
};
|
||||
|
||||
typedef std::multimap<float, UsedPos> UsedPosList; // abs(angle)->Node
|
||||
|
||||
ObjectPosSelector(float x, float y, float size, float dist);
|
||||
|
||||
void AddUsedPos(float size, float angle, float dist);
|
||||
void InitializeAngle();
|
||||
|
||||
bool FirstAngle(float& angle);
|
||||
bool NextAngle(float& angle);
|
||||
bool NextUsedAngle(float& angle);
|
||||
|
||||
bool NextPosibleAngle(float& angle);
|
||||
|
||||
bool CheckAngle(UsedPosList::value_type const& nextUsedPos, float sign, float angle ) const
|
||||
{
|
||||
float angle_step2 = GetAngle(nextUsedPos.second);
|
||||
|
||||
float next_angle = nextUsedPos.first;
|
||||
if (nextUsedPos.second.sign * sign < 0) // last node from diff. list (-pi+alpha)
|
||||
next_angle = 2*M_PI-next_angle; // move to positive
|
||||
|
||||
return fabs(angle)+angle_step2 <= next_angle;
|
||||
}
|
||||
|
||||
bool CheckOriginal() const
|
||||
{
|
||||
return (m_UsedPosLists[USED_POS_PLUS].empty() || CheckAngle(*m_UsedPosLists[USED_POS_PLUS].begin(), 1.0f, 0)) &&
|
||||
(m_UsedPosLists[USED_POS_MINUS].empty() || CheckAngle(*m_UsedPosLists[USED_POS_MINUS].begin(), -1.0f, 0));
|
||||
}
|
||||
|
||||
bool IsNonBalanced() const { return m_UsedPosLists[USED_POS_PLUS].empty() != m_UsedPosLists[USED_POS_MINUS].empty(); }
|
||||
|
||||
bool NextAngleFor(UsedPosList::value_type const& usedPos, float sign, UsedPosType uptype, float &angle)
|
||||
{
|
||||
float angle_step = GetAngle(usedPos.second);
|
||||
|
||||
// next possible angle
|
||||
angle = usedPos.first * usedPos.second.sign + angle_step * sign;
|
||||
|
||||
UsedPosList::value_type const* nextNode = nextUsedPos(uptype);
|
||||
if (nextNode)
|
||||
{
|
||||
// if next node permit use selected angle, then do it
|
||||
if (!CheckAngle(*nextNode, sign, angle))
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// possible more points
|
||||
m_smallStepOk[uptype] = true;
|
||||
m_smallStepAngle[uptype] = angle;
|
||||
m_smallStepNextUsedPos[uptype] = nextNode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NextSmallStepAngle(float sign, UsedPosType uptype, float &angle)
|
||||
{
|
||||
// next possible angle
|
||||
angle = m_smallStepAngle[uptype] + m_anglestep * sign;
|
||||
|
||||
if (fabs(angle) > M_PI)
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_smallStepNextUsedPos[uptype])
|
||||
{
|
||||
if (fabs(angle) >= m_smallStepNextUsedPos[uptype]->first)
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if next node permit use selected angle, then do it
|
||||
if (!CheckAngle(*m_smallStepNextUsedPos[uptype], sign, angle))
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// possible more points
|
||||
m_smallStepAngle[uptype] = angle;
|
||||
return true;
|
||||
}
|
||||
|
||||
// next used post for m_nextUsedPos[uptype]
|
||||
UsedPosList::value_type const* nextUsedPos(UsedPosType uptype);
|
||||
|
||||
// angle from used pos to next possible free pos
|
||||
float GetAngle(UsedPos const& usedPos) const { return acos(m_dist/(usedPos.dist+usedPos.size+m_size)); }
|
||||
|
||||
float m_center_x;
|
||||
float m_center_y;
|
||||
float m_size; // size of object in center
|
||||
float m_dist; // distance for searching pos (including central object size)
|
||||
float m_anglestep;
|
||||
|
||||
UsedPosList m_UsedPosLists[2];
|
||||
UsedPosList::const_iterator m_nextUsedPos[2];
|
||||
|
||||
// field for small step from first after next used pos until next pos
|
||||
float m_smallStepAngle[2];
|
||||
bool m_smallStepOk[2];
|
||||
UsedPosList::value_type const* m_smallStepNextUsedPos[2];
|
||||
};
|
||||
#endif
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "World.h"
|
||||
#include "zlib.h"
|
||||
|
||||
UpdateData::UpdateData() : m_blockCount(0)
|
||||
{
|
||||
m_outOfRangeGUIDs.reserve(15);
|
||||
}
|
||||
|
||||
void UpdateData::AddOutOfRangeGUID(uint64 guid)
|
||||
{
|
||||
m_outOfRangeGUIDs.push_back(guid);
|
||||
}
|
||||
|
||||
void UpdateData::AddUpdateBlock(const ByteBuffer &block)
|
||||
{
|
||||
m_data.append(block);
|
||||
++m_blockCount;
|
||||
}
|
||||
|
||||
void UpdateData::AddUpdateBlock(const UpdateData &block)
|
||||
{
|
||||
m_data.append(block.m_data);
|
||||
m_blockCount += block.m_blockCount;
|
||||
}
|
||||
|
||||
void UpdateData::Compress(void* dst, uint32 *dst_size, void* src, int src_size)
|
||||
{
|
||||
z_stream c_stream;
|
||||
|
||||
c_stream.zalloc = (alloc_func)0;
|
||||
c_stream.zfree = (free_func)0;
|
||||
c_stream.opaque = (voidpf)0;
|
||||
|
||||
// default Z_BEST_SPEED (1)
|
||||
int z_res = deflateInit(&c_stream, sWorld->getIntConfig(CONFIG_COMPRESSION));
|
||||
if (z_res != Z_OK)
|
||||
{
|
||||
sLog->outError("Can't compress update packet (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res));
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
c_stream.next_out = (Bytef*)dst;
|
||||
c_stream.avail_out = *dst_size;
|
||||
c_stream.next_in = (Bytef*)src;
|
||||
c_stream.avail_in = (uInt)src_size;
|
||||
|
||||
z_res = deflate(&c_stream, Z_NO_FLUSH);
|
||||
if (z_res != Z_OK)
|
||||
{
|
||||
sLog->outError("Can't compress update packet (zlib: deflate) Error code: %i (%s)", z_res, zError(z_res));
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (c_stream.avail_in != 0)
|
||||
{
|
||||
sLog->outError("Can't compress update packet (zlib: deflate not greedy)");
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
z_res = deflate(&c_stream, Z_FINISH);
|
||||
if (z_res != Z_STREAM_END)
|
||||
{
|
||||
sLog->outError("Can't compress update packet (zlib: deflate should report Z_STREAM_END instead %i (%s)", z_res, zError(z_res));
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
z_res = deflateEnd(&c_stream);
|
||||
if (z_res != Z_OK)
|
||||
{
|
||||
sLog->outError("Can't compress update packet (zlib: deflateEnd) Error code: %i (%s)", z_res, zError(z_res));
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*dst_size = c_stream.total_out;
|
||||
}
|
||||
|
||||
bool UpdateData::BuildPacket(WorldPacket* packet)
|
||||
{
|
||||
ASSERT(packet->empty()); // shouldn't happen
|
||||
|
||||
ByteBuffer buf(4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos());
|
||||
|
||||
buf << (uint32) (!m_outOfRangeGUIDs.empty() ? m_blockCount + 1 : m_blockCount);
|
||||
|
||||
if (!m_outOfRangeGUIDs.empty())
|
||||
{
|
||||
buf << (uint8) UPDATETYPE_OUT_OF_RANGE_OBJECTS;
|
||||
buf << (uint32) m_outOfRangeGUIDs.size();
|
||||
|
||||
for (std::vector<uint64>::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i)
|
||||
{
|
||||
buf.appendPackGUID(*i);
|
||||
}
|
||||
}
|
||||
|
||||
buf.append(m_data);
|
||||
|
||||
size_t pSize = buf.wpos(); // use real used data size
|
||||
|
||||
if (pSize > 100) // compress large packets
|
||||
{
|
||||
uint32 destsize = compressBound(pSize);
|
||||
packet->resize(destsize + sizeof(uint32));
|
||||
|
||||
packet->put<uint32>(0, pSize);
|
||||
Compress(const_cast<uint8*>(packet->contents()) + sizeof(uint32), &destsize, (void*)buf.contents(), pSize);
|
||||
if (destsize == 0)
|
||||
return false;
|
||||
|
||||
packet->resize(destsize + sizeof(uint32));
|
||||
packet->SetOpcode(SMSG_COMPRESSED_UPDATE_OBJECT);
|
||||
}
|
||||
else // send small packets without compression
|
||||
{
|
||||
packet->append(buf);
|
||||
packet->SetOpcode(SMSG_UPDATE_OBJECT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateData::Clear()
|
||||
{
|
||||
m_data.clear();
|
||||
m_outOfRangeGUIDs.clear();
|
||||
m_blockCount = 0;
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __UPDATEDATA_H
|
||||
#define __UPDATEDATA_H
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
class WorldPacket;
|
||||
|
||||
enum OBJECT_UPDATE_TYPE
|
||||
{
|
||||
UPDATETYPE_VALUES = 0,
|
||||
UPDATETYPE_MOVEMENT = 1,
|
||||
UPDATETYPE_CREATE_OBJECT = 2,
|
||||
UPDATETYPE_CREATE_OBJECT2 = 3,
|
||||
UPDATETYPE_OUT_OF_RANGE_OBJECTS = 4,
|
||||
UPDATETYPE_NEAR_OBJECTS = 5
|
||||
};
|
||||
|
||||
enum OBJECT_UPDATE_FLAGS
|
||||
{
|
||||
UPDATEFLAG_NONE = 0x0000,
|
||||
UPDATEFLAG_SELF = 0x0001,
|
||||
UPDATEFLAG_TRANSPORT = 0x0002,
|
||||
UPDATEFLAG_HAS_TARGET = 0x0004,
|
||||
UPDATEFLAG_UNKNOWN = 0x0008,
|
||||
UPDATEFLAG_LOWGUID = 0x0010,
|
||||
UPDATEFLAG_LIVING = 0x0020,
|
||||
UPDATEFLAG_STATIONARY_POSITION = 0x0040,
|
||||
UPDATEFLAG_VEHICLE = 0x0080,
|
||||
UPDATEFLAG_POSITION = 0x0100,
|
||||
UPDATEFLAG_ROTATION = 0x0200
|
||||
};
|
||||
|
||||
class UpdateData
|
||||
{
|
||||
public:
|
||||
UpdateData();
|
||||
|
||||
void AddOutOfRangeGUID(uint64 guid);
|
||||
void AddUpdateBlock(const ByteBuffer &block);
|
||||
void AddUpdateBlock(const UpdateData &block);
|
||||
bool BuildPacket(WorldPacket* packet);
|
||||
bool HasData() const { return m_blockCount > 0 || !m_outOfRangeGUIDs.empty(); }
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
uint32 m_blockCount;
|
||||
std::vector<uint64> m_outOfRangeGUIDs;
|
||||
ByteBuffer m_data;
|
||||
|
||||
void Compress(void* dst, uint32 *dst_size, void* src, int src_size);
|
||||
};
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _UPDATEFIELDFLAGS_H
|
||||
#define _UPDATEFIELDFLAGS_H
|
||||
|
||||
#include "UpdateFields.h"
|
||||
#include "Define.h"
|
||||
|
||||
enum UpdatefieldFlags
|
||||
{
|
||||
UF_FLAG_NONE = 0x000,
|
||||
UF_FLAG_PUBLIC = 0x001,
|
||||
UF_FLAG_PRIVATE = 0x002,
|
||||
UF_FLAG_OWNER = 0x004,
|
||||
UF_FLAG_UNUSED1 = 0x008,
|
||||
UF_FLAG_ITEM_OWNER = 0x010,
|
||||
UF_FLAG_SPECIAL_INFO = 0x020,
|
||||
UF_FLAG_PARTY_MEMBER = 0x040,
|
||||
UF_FLAG_UNUSED2 = 0x080,
|
||||
UF_FLAG_DYNAMIC = 0x100,
|
||||
};
|
||||
|
||||
extern uint32 ItemUpdateFieldFlags[CONTAINER_END];
|
||||
extern uint32 UnitUpdateFieldFlags[PLAYER_END];
|
||||
extern uint32 GameObjectUpdateFieldFlags[GAMEOBJECT_END];
|
||||
extern uint32 DynamicObjectUpdateFieldFlags[DYNAMICOBJECT_END];
|
||||
extern uint32 CorpseUpdateFieldFlags[CORPSE_END];
|
||||
|
||||
#endif // _UPDATEFIELDFLAGS_H
|
||||
@@ -1,433 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _UPDATEFIELDS_AUTO_H
|
||||
#define _UPDATEFIELDS_AUTO_H
|
||||
|
||||
// Auto generated for version 3, 3, 5, 12340
|
||||
|
||||
enum EObjectFields
|
||||
{
|
||||
OBJECT_FIELD_GUID = 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
OBJECT_FIELD_TYPE = 0x0002, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
OBJECT_FIELD_ENTRY = 0x0003, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
OBJECT_FIELD_SCALE_X = 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC
|
||||
OBJECT_FIELD_PADDING = 0x0005, // Size: 1, Type: INT, Flags: NONE
|
||||
OBJECT_END = 0x0006,
|
||||
};
|
||||
|
||||
enum EItemFields
|
||||
{
|
||||
ITEM_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
ITEM_FIELD_CONTAINED = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
ITEM_FIELD_CREATOR = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
ITEM_FIELD_GIFTCREATOR = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
ITEM_FIELD_STACK_COUNT = OBJECT_END + 0x0008, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER
|
||||
ITEM_FIELD_DURATION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER
|
||||
ITEM_FIELD_SPELL_CHARGES = OBJECT_END + 0x000A, // Size: 5, Type: INT, Flags: OWNER, ITEM_OWNER
|
||||
ITEM_FIELD_FLAGS = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_1_1 = OBJECT_END + 0x0010, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_1_3 = OBJECT_END + 0x0012, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_2_1 = OBJECT_END + 0x0013, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_2_3 = OBJECT_END + 0x0015, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_3_1 = OBJECT_END + 0x0016, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_3_3 = OBJECT_END + 0x0018, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_4_1 = OBJECT_END + 0x0019, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_4_3 = OBJECT_END + 0x001B, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_5_1 = OBJECT_END + 0x001C, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_5_3 = OBJECT_END + 0x001E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_6_1 = OBJECT_END + 0x001F, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_6_3 = OBJECT_END + 0x0021, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_7_1 = OBJECT_END + 0x0022, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_7_3 = OBJECT_END + 0x0024, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_8_1 = OBJECT_END + 0x0025, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_8_3 = OBJECT_END + 0x0027, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_9_1 = OBJECT_END + 0x0028, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_9_3 = OBJECT_END + 0x002A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_10_1 = OBJECT_END + 0x002B, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_10_3 = OBJECT_END + 0x002D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_11_1 = OBJECT_END + 0x002E, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_11_3 = OBJECT_END + 0x0030, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_12_1 = OBJECT_END + 0x0031, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_ENCHANTMENT_12_3 = OBJECT_END + 0x0033, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x0034, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_DURABILITY = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER
|
||||
ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER
|
||||
ITEM_FIELD_CREATE_PLAYED_TIME = OBJECT_END + 0x0038, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
ITEM_FIELD_PAD = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: NONE
|
||||
ITEM_END = OBJECT_END + 0x003A,
|
||||
};
|
||||
|
||||
enum EContainerFields
|
||||
{
|
||||
CONTAINER_FIELD_NUM_SLOTS = ITEM_END + 0x0000, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
CONTAINER_ALIGN_PAD = ITEM_END + 0x0001, // Size: 1, Type: BYTES, Flags: NONE
|
||||
CONTAINER_FIELD_SLOT_1 = ITEM_END + 0x0002, // Size: 72, Type: LONG, Flags: PUBLIC
|
||||
CONTAINER_END = ITEM_END + 0x004A,
|
||||
};
|
||||
|
||||
enum EUnitFields
|
||||
{
|
||||
UNIT_FIELD_CHARM = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
UNIT_FIELD_SUMMON = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
UNIT_FIELD_CRITTER = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PRIVATE
|
||||
UNIT_FIELD_CHARMEDBY = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
UNIT_FIELD_SUMMONEDBY = OBJECT_END + 0x0008, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
UNIT_FIELD_CREATEDBY = OBJECT_END + 0x000A, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
UNIT_FIELD_TARGET = OBJECT_END + 0x000C, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
UNIT_FIELD_CHANNEL_OBJECT = OBJECT_END + 0x000E, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
UNIT_CHANNEL_SPELL = OBJECT_END + 0x0010, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_BYTES_0 = OBJECT_END + 0x0011, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
UNIT_FIELD_HEALTH = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER1 = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER2 = OBJECT_END + 0x0014, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER3 = OBJECT_END + 0x0015, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER4 = OBJECT_END + 0x0016, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER5 = OBJECT_END + 0x0017, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER6 = OBJECT_END + 0x0018, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER7 = OBJECT_END + 0x0019, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXHEALTH = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXPOWER1 = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXPOWER2 = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXPOWER3 = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXPOWER4 = OBJECT_END + 0x001E, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXPOWER5 = OBJECT_END + 0x001F, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXPOWER6 = OBJECT_END + 0x0020, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MAXPOWER7 = OBJECT_END + 0x0021, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER = OBJECT_END + 0x0022, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER = OBJECT_END + 0x0029, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_LEVEL = OBJECT_END + 0x0030, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_FACTIONTEMPLATE = OBJECT_END + 0x0031, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_VIRTUAL_ITEM_SLOT_ID = OBJECT_END + 0x0032, // Size: 3, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_FLAGS = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_FLAGS_2 = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_AURASTATE = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_BASEATTACKTIME = OBJECT_END + 0x0038, // Size: 2, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_RANGEDATTACKTIME = OBJECT_END + 0x003A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
UNIT_FIELD_BOUNDINGRADIUS = OBJECT_END + 0x003B, // Size: 1, Type: FLOAT, Flags: PUBLIC
|
||||
UNIT_FIELD_COMBATREACH = OBJECT_END + 0x003C, // Size: 1, Type: FLOAT, Flags: PUBLIC
|
||||
UNIT_FIELD_DISPLAYID = OBJECT_END + 0x003D, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_NATIVEDISPLAYID = OBJECT_END + 0x003E, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MOUNTDISPLAYID = OBJECT_END + 0x003F, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_MINDAMAGE = OBJECT_END + 0x0040, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER
|
||||
UNIT_FIELD_MAXDAMAGE = OBJECT_END + 0x0041, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER
|
||||
UNIT_FIELD_MINOFFHANDDAMAGE = OBJECT_END + 0x0042, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER
|
||||
UNIT_FIELD_MAXOFFHANDDAMAGE = OBJECT_END + 0x0043, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER
|
||||
UNIT_FIELD_BYTES_1 = OBJECT_END + 0x0044, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
UNIT_FIELD_PETNUMBER = OBJECT_END + 0x0045, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_PET_NAME_TIMESTAMP = OBJECT_END + 0x0046, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_PETEXPERIENCE = OBJECT_END + 0x0047, // Size: 1, Type: INT, Flags: OWNER
|
||||
UNIT_FIELD_PETNEXTLEVELEXP = OBJECT_END + 0x0048, // Size: 1, Type: INT, Flags: OWNER
|
||||
UNIT_DYNAMIC_FLAGS = OBJECT_END + 0x0049, // Size: 1, Type: INT, Flags: DYNAMIC
|
||||
UNIT_MOD_CAST_SPEED = OBJECT_END + 0x004A, // Size: 1, Type: FLOAT, Flags: PUBLIC
|
||||
UNIT_CREATED_BY_SPELL = OBJECT_END + 0x004B, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_NPC_FLAGS = OBJECT_END + 0x004C, // Size: 1, Type: INT, Flags: DYNAMIC
|
||||
UNIT_NPC_EMOTESTATE = OBJECT_END + 0x004D, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_STAT0 = OBJECT_END + 0x004E, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_STAT1 = OBJECT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_STAT2 = OBJECT_END + 0x0050, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_STAT3 = OBJECT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_STAT4 = OBJECT_END + 0x0052, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POSSTAT0 = OBJECT_END + 0x0053, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POSSTAT1 = OBJECT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POSSTAT2 = OBJECT_END + 0x0055, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POSSTAT3 = OBJECT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POSSTAT4 = OBJECT_END + 0x0057, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_NEGSTAT0 = OBJECT_END + 0x0058, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_NEGSTAT1 = OBJECT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_NEGSTAT2 = OBJECT_END + 0x005A, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_NEGSTAT3 = OBJECT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_NEGSTAT4 = OBJECT_END + 0x005C, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_RESISTANCES = OBJECT_END + 0x005D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER, PARTY_LEADER
|
||||
UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE = OBJECT_END + 0x0064, // Size: 7, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE = OBJECT_END + 0x006B, // Size: 7, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_BASE_MANA = OBJECT_END + 0x0072, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
UNIT_FIELD_BASE_HEALTH = OBJECT_END + 0x0073, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_BYTES_2 = OBJECT_END + 0x0074, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
UNIT_FIELD_ATTACK_POWER = OBJECT_END + 0x0075, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_ATTACK_POWER_MODS = OBJECT_END + 0x0076, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x0077, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_RANGED_ATTACK_POWER = OBJECT_END + 0x0078, // Size: 1, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_RANGED_ATTACK_POWER_MODS = OBJECT_END + 0x0079, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x007A, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_MINRANGEDDAMAGE = OBJECT_END + 0x007B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_MAXRANGEDDAMAGE = OBJECT_END + 0x007C, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POWER_COST_MODIFIER = OBJECT_END + 0x007D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_POWER_COST_MULTIPLIER = OBJECT_END + 0x0084, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_MAXHEALTHMODIFIER = OBJECT_END + 0x008B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER
|
||||
UNIT_FIELD_HOVERHEIGHT = OBJECT_END + 0x008C, // Size: 1, Type: FLOAT, Flags: PUBLIC
|
||||
UNIT_FIELD_PADDING = OBJECT_END + 0x008D, // Size: 1, Type: INT, Flags: NONE
|
||||
UNIT_END = OBJECT_END + 0x008E,
|
||||
|
||||
PLAYER_DUEL_ARBITER = UNIT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
PLAYER_FLAGS = UNIT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_GUILDID = UNIT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_GUILDRANK = UNIT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_BYTES = UNIT_END + 0x0005, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
PLAYER_BYTES_2 = UNIT_END + 0x0006, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
PLAYER_BYTES_3 = UNIT_END + 0x0007, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
PLAYER_DUEL_TEAM = UNIT_END + 0x0008, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_GUILD_TIMESTAMP = UNIT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_QUEST_LOG_1_1 = UNIT_END + 0x000A, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_1_2 = UNIT_END + 0x000B, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_1_3 = UNIT_END + 0x000C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_1_4 = UNIT_END + 0x000E, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_2_1 = UNIT_END + 0x000F, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_2_2 = UNIT_END + 0x0010, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_2_3 = UNIT_END + 0x0011, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_2_5 = UNIT_END + 0x0013, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_3_1 = UNIT_END + 0x0014, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_3_2 = UNIT_END + 0x0015, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_3_3 = UNIT_END + 0x0016, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_3_5 = UNIT_END + 0x0018, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_4_1 = UNIT_END + 0x0019, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_4_2 = UNIT_END + 0x001A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_4_3 = UNIT_END + 0x001B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_4_5 = UNIT_END + 0x001D, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_5_1 = UNIT_END + 0x001E, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_5_2 = UNIT_END + 0x001F, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_5_3 = UNIT_END + 0x0020, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_5_5 = UNIT_END + 0x0022, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_6_1 = UNIT_END + 0x0023, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_6_2 = UNIT_END + 0x0024, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_6_3 = UNIT_END + 0x0025, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_6_5 = UNIT_END + 0x0027, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_7_1 = UNIT_END + 0x0028, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_7_2 = UNIT_END + 0x0029, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_7_3 = UNIT_END + 0x002A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_7_5 = UNIT_END + 0x002C, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_8_1 = UNIT_END + 0x002D, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_8_2 = UNIT_END + 0x002E, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_8_3 = UNIT_END + 0x002F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_8_5 = UNIT_END + 0x0031, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_9_1 = UNIT_END + 0x0032, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_9_2 = UNIT_END + 0x0033, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_9_3 = UNIT_END + 0x0034, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_9_5 = UNIT_END + 0x0036, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_10_1 = UNIT_END + 0x0037, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_10_2 = UNIT_END + 0x0038, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_10_3 = UNIT_END + 0x0039, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_10_5 = UNIT_END + 0x003B, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_11_1 = UNIT_END + 0x003C, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_11_2 = UNIT_END + 0x003D, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_11_3 = UNIT_END + 0x003E, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_11_5 = UNIT_END + 0x0040, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_12_1 = UNIT_END + 0x0041, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_12_2 = UNIT_END + 0x0042, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_12_3 = UNIT_END + 0x0043, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_12_5 = UNIT_END + 0x0045, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_13_1 = UNIT_END + 0x0046, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_13_2 = UNIT_END + 0x0047, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_13_3 = UNIT_END + 0x0048, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_13_5 = UNIT_END + 0x004A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_14_1 = UNIT_END + 0x004B, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_14_2 = UNIT_END + 0x004C, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_14_3 = UNIT_END + 0x004D, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_14_5 = UNIT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_15_1 = UNIT_END + 0x0050, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_15_2 = UNIT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_15_3 = UNIT_END + 0x0052, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_15_5 = UNIT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_16_1 = UNIT_END + 0x0055, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_16_2 = UNIT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_16_3 = UNIT_END + 0x0057, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_16_5 = UNIT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_17_1 = UNIT_END + 0x005A, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_17_2 = UNIT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_17_3 = UNIT_END + 0x005C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_17_5 = UNIT_END + 0x005E, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_18_1 = UNIT_END + 0x005F, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_18_2 = UNIT_END + 0x0060, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_18_3 = UNIT_END + 0x0061, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_18_5 = UNIT_END + 0x0063, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_19_1 = UNIT_END + 0x0064, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_19_2 = UNIT_END + 0x0065, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_19_3 = UNIT_END + 0x0066, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_19_5 = UNIT_END + 0x0068, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_20_1 = UNIT_END + 0x0069, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_20_2 = UNIT_END + 0x006A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_20_3 = UNIT_END + 0x006B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_20_5 = UNIT_END + 0x006D, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_21_1 = UNIT_END + 0x006E, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_21_2 = UNIT_END + 0x006F, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_21_3 = UNIT_END + 0x0070, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_21_5 = UNIT_END + 0x0072, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_22_1 = UNIT_END + 0x0073, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_22_2 = UNIT_END + 0x0074, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_22_3 = UNIT_END + 0x0075, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_22_5 = UNIT_END + 0x0077, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_23_1 = UNIT_END + 0x0078, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_23_2 = UNIT_END + 0x0079, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_23_3 = UNIT_END + 0x007A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_23_5 = UNIT_END + 0x007C, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_24_1 = UNIT_END + 0x007D, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_24_2 = UNIT_END + 0x007E, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_24_3 = UNIT_END + 0x007F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_24_5 = UNIT_END + 0x0081, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_25_1 = UNIT_END + 0x0082, // Size: 1, Type: INT, Flags: PARTY_MEMBER
|
||||
PLAYER_QUEST_LOG_25_2 = UNIT_END + 0x0083, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_25_3 = UNIT_END + 0x0084, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_QUEST_LOG_25_5 = UNIT_END + 0x0086, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_VISIBLE_ITEM_1_ENTRYID = UNIT_END + 0x0087, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_1_ENCHANTMENT = UNIT_END + 0x0088, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_2_ENTRYID = UNIT_END + 0x0089, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_2_ENCHANTMENT = UNIT_END + 0x008A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_3_ENTRYID = UNIT_END + 0x008B, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_3_ENCHANTMENT = UNIT_END + 0x008C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_4_ENTRYID = UNIT_END + 0x008D, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_4_ENCHANTMENT = UNIT_END + 0x008E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_5_ENTRYID = UNIT_END + 0x008F, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_5_ENCHANTMENT = UNIT_END + 0x0090, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_6_ENTRYID = UNIT_END + 0x0091, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_6_ENCHANTMENT = UNIT_END + 0x0092, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_7_ENTRYID = UNIT_END + 0x0093, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_7_ENCHANTMENT = UNIT_END + 0x0094, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_8_ENTRYID = UNIT_END + 0x0095, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_8_ENCHANTMENT = UNIT_END + 0x0096, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_9_ENTRYID = UNIT_END + 0x0097, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_9_ENCHANTMENT = UNIT_END + 0x0098, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_10_ENTRYID = UNIT_END + 0x0099, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_10_ENCHANTMENT = UNIT_END + 0x009A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_11_ENTRYID = UNIT_END + 0x009B, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_11_ENCHANTMENT = UNIT_END + 0x009C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_12_ENTRYID = UNIT_END + 0x009D, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_12_ENCHANTMENT = UNIT_END + 0x009E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_13_ENTRYID = UNIT_END + 0x009F, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_13_ENCHANTMENT = UNIT_END + 0x00A0, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_14_ENTRYID = UNIT_END + 0x00A1, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_14_ENCHANTMENT = UNIT_END + 0x00A2, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_15_ENTRYID = UNIT_END + 0x00A3, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_15_ENCHANTMENT = UNIT_END + 0x00A4, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_16_ENTRYID = UNIT_END + 0x00A5, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_16_ENCHANTMENT = UNIT_END + 0x00A6, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_17_ENTRYID = UNIT_END + 0x00A7, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_17_ENCHANTMENT = UNIT_END + 0x00A8, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_18_ENTRYID = UNIT_END + 0x00A9, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_18_ENCHANTMENT = UNIT_END + 0x00AA, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_19_ENTRYID = UNIT_END + 0x00AB, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_VISIBLE_ITEM_19_ENCHANTMENT = UNIT_END + 0x00AC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
|
||||
PLAYER_CHOSEN_TITLE = UNIT_END + 0x00AD, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_FAKE_INEBRIATION = UNIT_END + 0x00AE, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
PLAYER_FIELD_PAD_0 = UNIT_END + 0x00AF, // Size: 1, Type: INT, Flags: NONE
|
||||
PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x00B0, // Size: 46, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x00DE, // Size: 32, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x00FE, // Size: 56, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FIELD_BANKBAG_SLOT_1 = UNIT_END + 0x0136, // Size: 14, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FIELD_VENDORBUYBACK_SLOT_1 = UNIT_END + 0x0144, // Size: 24, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FIELD_KEYRING_SLOT_1 = UNIT_END + 0x015C, // Size: 64, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FIELD_CURRENCYTOKEN_SLOT_1 = UNIT_END + 0x019C, // Size: 64, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FARSIGHT = UNIT_END + 0x01DC, // Size: 2, Type: LONG, Flags: PRIVATE
|
||||
PLAYER__FIELD_KNOWN_TITLES = UNIT_END + 0x01DE, // Size: 2, Type: LONG, Flags: PRIVATE
|
||||
PLAYER__FIELD_KNOWN_TITLES1 = UNIT_END + 0x01E0, // Size: 2, Type: LONG, Flags: PRIVATE
|
||||
PLAYER__FIELD_KNOWN_TITLES2 = UNIT_END + 0x01E2, // Size: 2, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_FIELD_KNOWN_CURRENCIES = UNIT_END + 0x01E4, // Size: 2, Type: LONG, Flags: PRIVATE
|
||||
PLAYER_XP = UNIT_END + 0x01E6, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_NEXT_LEVEL_XP = UNIT_END + 0x01E7, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_SKILL_INFO_1_1 = UNIT_END + 0x01E8, // Size: 384, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_CHARACTER_POINTS1 = UNIT_END + 0x0368, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_CHARACTER_POINTS2 = UNIT_END + 0x0369, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_TRACK_CREATURES = UNIT_END + 0x036A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_TRACK_RESOURCES = UNIT_END + 0x036B, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_BLOCK_PERCENTAGE = UNIT_END + 0x036C, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_DODGE_PERCENTAGE = UNIT_END + 0x036D, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_PARRY_PERCENTAGE = UNIT_END + 0x036E, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_EXPERTISE = UNIT_END + 0x036F, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_OFFHAND_EXPERTISE = UNIT_END + 0x0370, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_CRIT_PERCENTAGE = UNIT_END + 0x0371, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_RANGED_CRIT_PERCENTAGE = UNIT_END + 0x0372, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_OFFHAND_CRIT_PERCENTAGE = UNIT_END + 0x0373, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_SPELL_CRIT_PERCENTAGE1 = UNIT_END + 0x0374, // Size: 7, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_SHIELD_BLOCK = UNIT_END + 0x037B, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE = UNIT_END + 0x037C, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_EXPLORED_ZONES_1 = UNIT_END + 0x037D, // Size: 128, Type: BYTES, Flags: PRIVATE
|
||||
PLAYER_REST_STATE_EXPERIENCE = UNIT_END + 0x03FD, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_COINAGE = UNIT_END + 0x03FE, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_DAMAGE_DONE_POS = UNIT_END + 0x03FF, // Size: 7, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x0406, // Size: 7, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x040D, // Size: 7, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x0414, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_HEALING_PCT = UNIT_END + 0x0415, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_HEALING_DONE_PCT = UNIT_END + 0x0416, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x0417, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x0418, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_BYTES = UNIT_END + 0x0419, // Size: 1, Type: BYTES, Flags: PRIVATE
|
||||
PLAYER_AMMO_ID = UNIT_END + 0x041A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_SELF_RES_SPELL = UNIT_END + 0x041B, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x041C, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x041D, // Size: 12, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x0429, // Size: 12, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_KILLS = UNIT_END + 0x0435, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x0436, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x0437, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_LIFETIME_HONORABLE_KILLS = UNIT_END + 0x0438, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_BYTES2 = UNIT_END + 0x0439, // Size: 1, Type: 6, Flags: PRIVATE
|
||||
PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x043A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x043B, // Size: 25, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x0454, // Size: 21, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x0469, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x046A, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x046B, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x046C, // Size: 25, Type: INT, Flags: PRIVATE
|
||||
PLAYER_RUNE_REGEN_1 = UNIT_END + 0x0485, // Size: 4, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x0489, // Size: 3, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x048C, // Size: 6, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0492, // Size: 6, Type: INT, Flags: PRIVATE
|
||||
PLAYER_GLYPHS_ENABLED = UNIT_END + 0x0498, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_PET_SPELL_POWER = UNIT_END + 0x0499, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_END = UNIT_END + 0x049A,
|
||||
};
|
||||
|
||||
enum EGameObjectFields
|
||||
{
|
||||
OBJECT_FIELD_CREATED_BY = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
GAMEOBJECT_DISPLAYID = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
GAMEOBJECT_FLAGS = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
GAMEOBJECT_PARENTROTATION = OBJECT_END + 0x0004, // Size: 4, Type: FLOAT, Flags: PUBLIC
|
||||
GAMEOBJECT_DYNAMIC = OBJECT_END + 0x0008, // Size: 1, Type: TWO_SHORT, Flags: DYNAMIC
|
||||
GAMEOBJECT_FACTION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
GAMEOBJECT_LEVEL = OBJECT_END + 0x000A, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
GAMEOBJECT_BYTES_1 = OBJECT_END + 0x000B, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
GAMEOBJECT_END = OBJECT_END + 0x000C,
|
||||
};
|
||||
|
||||
enum EDynamicObjectFields
|
||||
{
|
||||
DYNAMICOBJECT_CASTER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
DYNAMICOBJECT_BYTES = OBJECT_END + 0x0002, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
DYNAMICOBJECT_SPELLID = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
DYNAMICOBJECT_RADIUS = OBJECT_END + 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC
|
||||
DYNAMICOBJECT_CASTTIME = OBJECT_END + 0x0005, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
DYNAMICOBJECT_END = OBJECT_END + 0x0006,
|
||||
};
|
||||
|
||||
enum ECorpseFields
|
||||
{
|
||||
CORPSE_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
CORPSE_FIELD_PARTY = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC
|
||||
CORPSE_FIELD_DISPLAY_ID = OBJECT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
CORPSE_FIELD_ITEM = OBJECT_END + 0x0005, // Size: 19, Type: INT, Flags: PUBLIC
|
||||
CORPSE_FIELD_BYTES_1 = OBJECT_END + 0x0018, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
CORPSE_FIELD_BYTES_2 = OBJECT_END + 0x0019, // Size: 1, Type: BYTES, Flags: PUBLIC
|
||||
CORPSE_FIELD_GUILD = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
CORPSE_FIELD_FLAGS = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC
|
||||
CORPSE_FIELD_DYNAMIC_FLAGS = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: DYNAMIC
|
||||
CORPSE_FIELD_PAD = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: NONE
|
||||
CORPSE_END = OBJECT_END + 0x001E,
|
||||
};
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __UPDATEMASK_H
|
||||
#define __UPDATEMASK_H
|
||||
|
||||
#include "UpdateFields.h"
|
||||
#include "Errors.h"
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
class UpdateMask
|
||||
{
|
||||
public:
|
||||
/// Type representing how client reads update mask
|
||||
typedef uint32 ClientUpdateMaskType;
|
||||
|
||||
enum UpdateMaskCount
|
||||
{
|
||||
CLIENT_UPDATE_MASK_BITS = sizeof(ClientUpdateMaskType) * 8,
|
||||
};
|
||||
|
||||
UpdateMask() : _fieldCount(0), _blockCount(0), _bits(NULL) { }
|
||||
|
||||
UpdateMask(UpdateMask const& right) : _bits(NULL)
|
||||
{
|
||||
SetCount(right.GetCount());
|
||||
memcpy(_bits, right._bits, sizeof(uint8) * _blockCount * 32);
|
||||
}
|
||||
|
||||
~UpdateMask() { delete[] _bits; }
|
||||
|
||||
void SetBit(uint32 index) { _bits[index] = 1; }
|
||||
void UnsetBit(uint32 index) { _bits[index] = 0; }
|
||||
bool GetBit(uint32 index) const { return _bits[index] != 0; }
|
||||
|
||||
void AppendToPacket(ByteBuffer* data)
|
||||
{
|
||||
for (uint32 i = 0; i < GetBlockCount(); ++i)
|
||||
{
|
||||
ClientUpdateMaskType maskPart = 0;
|
||||
for (uint32 j = 0; j < CLIENT_UPDATE_MASK_BITS; ++j)
|
||||
if (_bits[CLIENT_UPDATE_MASK_BITS * i + j])
|
||||
maskPart |= 1 << j;
|
||||
|
||||
*data << maskPart;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetBlockCount() const { return _blockCount; }
|
||||
uint32 GetCount() const { return _fieldCount; }
|
||||
|
||||
void SetCount(uint32 valuesCount)
|
||||
{
|
||||
delete[] _bits;
|
||||
|
||||
_fieldCount = valuesCount;
|
||||
_blockCount = (valuesCount + CLIENT_UPDATE_MASK_BITS - 1) / CLIENT_UPDATE_MASK_BITS;
|
||||
|
||||
_bits = new uint8[_blockCount * CLIENT_UPDATE_MASK_BITS];
|
||||
memset(_bits, 0, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
if (_bits)
|
||||
memset(_bits, 0, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS);
|
||||
}
|
||||
|
||||
UpdateMask& operator=(UpdateMask const& right)
|
||||
{
|
||||
if (this == &right)
|
||||
return *this;
|
||||
|
||||
SetCount(right.GetCount());
|
||||
memcpy(_bits, right._bits, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
UpdateMask& operator&=(UpdateMask const& right)
|
||||
{
|
||||
ASSERT(right.GetCount() <= GetCount());
|
||||
for (uint32 i = 0; i < _fieldCount; ++i)
|
||||
_bits[i] &= right._bits[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
UpdateMask& operator|=(UpdateMask const& right)
|
||||
{
|
||||
ASSERT(right.GetCount() <= GetCount());
|
||||
for (uint32 i = 0; i < _fieldCount; ++i)
|
||||
_bits[i] |= right._bits[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
UpdateMask operator|(UpdateMask const& right)
|
||||
{
|
||||
UpdateMask ret(*this);
|
||||
ret |= right;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _fieldCount;
|
||||
uint32 _blockCount;
|
||||
uint8* _bits;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_PET_H
|
||||
#define AZEROTHCORE_PET_H
|
||||
|
||||
#include "PetDefines.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
#define PET_FOCUS_REGEN_INTERVAL 4 * IN_MILLISECONDS
|
||||
#define PET_LOSE_HAPPINES_INTERVAL 7500
|
||||
#define HAPPINESS_LEVEL_SIZE 333000
|
||||
|
||||
struct PetSpell
|
||||
{
|
||||
ActiveStates active;
|
||||
PetSpellState state;
|
||||
PetSpellType type;
|
||||
};
|
||||
|
||||
|
||||
class AsynchPetSummon
|
||||
{
|
||||
public:
|
||||
AsynchPetSummon(uint32 entry, Position position, PetType petType, uint32 duration, uint32 createdBySpell, uint64 casterGUID) :
|
||||
m_entry(entry), pos(position), m_petType(petType),
|
||||
m_duration(duration), m_createdBySpell(createdBySpell), m_casterGUID(casterGUID) { }
|
||||
|
||||
Position pos;
|
||||
uint32 m_entry, m_createdBySpell, m_duration;
|
||||
PetType m_petType;
|
||||
uint64 m_casterGUID;
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32, PetSpell> PetSpellMap;
|
||||
typedef std::vector<uint32> AutoSpellList;
|
||||
|
||||
class Player;
|
||||
|
||||
class Pet : public Guardian
|
||||
{
|
||||
public:
|
||||
explicit Pet(Player* owner, PetType type = MAX_PET_TYPE);
|
||||
virtual ~Pet();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
void SetDisplayId(uint32 modelId);
|
||||
|
||||
PetType getPetType() const { return m_petType; }
|
||||
void setPetType(PetType type) { m_petType = type; }
|
||||
bool isControlled() const { return getPetType() == SUMMON_PET || getPetType() == HUNTER_PET; }
|
||||
bool isTemporarySummoned() const { return m_duration > 0; }
|
||||
|
||||
bool IsPermanentPetFor(Player* owner) const; // pet have tab in character windows and set UNIT_FIELD_PETNUMBER
|
||||
|
||||
bool Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint32 pet_number);
|
||||
bool CreateBaseAtCreature(Creature* creature);
|
||||
bool CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner);
|
||||
bool CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phaseMask);
|
||||
static bool LoadPetFromDB(Player* owner, uint8 asynchLoadType, uint32 petentry = 0, uint32 petnumber = 0, bool current = false, AsynchPetSummon* info = NULL);
|
||||
bool isBeingLoaded() const { return m_loading;}
|
||||
void SavePetToDB(PetSaveMode mode, bool logout);
|
||||
void Remove(PetSaveMode mode, bool returnreagent = false);
|
||||
static void DeleteFromDB(uint32 guidlow);
|
||||
|
||||
void setDeathState(DeathState s, bool despawn = false); // overwrite virtual Creature::setDeathState and Unit::setDeathState
|
||||
void Update(uint32 diff); // overwrite virtual Creature::Update and Unit::Update
|
||||
|
||||
uint8 GetPetAutoSpellSize() const { return m_autospells.size(); }
|
||||
uint32 GetPetAutoSpellOnPos(uint8 pos) const
|
||||
{
|
||||
if (pos >= m_autospells.size())
|
||||
return 0;
|
||||
else
|
||||
return m_autospells[pos];
|
||||
}
|
||||
|
||||
void LoseHappiness();
|
||||
HappinessState GetHappinessState();
|
||||
void GivePetXP(uint32 xp);
|
||||
void GivePetLevel(uint8 level);
|
||||
void SynchronizeLevelWithOwner();
|
||||
bool HaveInDiet(ItemTemplate const* item) const;
|
||||
uint32 GetCurrentFoodBenefitLevel(uint32 itemlevel) const;
|
||||
void SetDuration(int32 dur) { m_duration = dur; }
|
||||
int32 GetDuration() const { return m_duration; }
|
||||
|
||||
/*
|
||||
bool UpdateStats(Stats stat);
|
||||
bool UpdateAllStats();
|
||||
void UpdateResistances(uint32 school);
|
||||
void UpdateArmor();
|
||||
void UpdateMaxHealth();
|
||||
void UpdateMaxPower(Powers power);
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false);
|
||||
void UpdateDamagePhysical(WeaponAttackType attType);
|
||||
*/
|
||||
|
||||
void ToggleAutocast(SpellInfo const* spellInfo, bool apply);
|
||||
|
||||
bool HasSpell(uint32 spell) const;
|
||||
|
||||
void LearnPetPassives();
|
||||
void CastPetAuras(bool current);
|
||||
|
||||
void CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, Unit* oldTarget, bool spellIsPositive = false);
|
||||
void ClearCastWhenWillAvailable();
|
||||
void RemoveSpellCooldown(uint32 spell_id, bool update /* = false */);
|
||||
|
||||
void _SaveSpellCooldowns(SQLTransaction& trans, bool logout);
|
||||
void _SaveAuras(SQLTransaction& trans, bool logout);
|
||||
void _SaveSpells(SQLTransaction& trans);
|
||||
|
||||
void _LoadSpellCooldowns(PreparedQueryResult result);
|
||||
void _LoadAuras(PreparedQueryResult result, uint32 timediff);
|
||||
void _LoadSpells(PreparedQueryResult result);
|
||||
|
||||
bool addSpell(uint32 spellId, ActiveStates active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL);
|
||||
bool learnSpell(uint32 spell_id);
|
||||
void learnSpellHighRank(uint32 spellid);
|
||||
void InitLevelupSpellsForLevel();
|
||||
bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
|
||||
bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
|
||||
void CleanupActionBar();
|
||||
|
||||
PetSpellMap m_spells;
|
||||
AutoSpellList m_autospells;
|
||||
|
||||
void InitPetCreateSpells();
|
||||
|
||||
bool resetTalents();
|
||||
static void resetTalentsForAllPetsOf(Player* owner, Pet* online_pet = NULL);
|
||||
void InitTalentForLevel();
|
||||
|
||||
uint8 GetMaxTalentPointsForLevel(uint8 level);
|
||||
uint8 GetFreeTalentPoints() { return GetByteValue(UNIT_FIELD_BYTES_1, 1); }
|
||||
void SetFreeTalentPoints(uint8 points) { SetByteValue(UNIT_FIELD_BYTES_1, 1, points); }
|
||||
|
||||
uint32 m_usedTalentCount;
|
||||
|
||||
uint64 GetAuraUpdateMaskForRaid() const { return m_auraRaidUpdateMask; }
|
||||
void SetAuraUpdateMaskForRaid(uint8 slot) { m_auraRaidUpdateMask |= (uint64(1) << slot); }
|
||||
void ResetAuraUpdateMaskForRaid() { m_auraRaidUpdateMask = 0; }
|
||||
|
||||
DeclinedName const* GetDeclinedNames() const { return m_declinedname; }
|
||||
|
||||
bool m_removed; // prevent overwrite pet state in DB at next Pet::Update if pet already removed(saved)
|
||||
|
||||
Player* GetOwner() const { return m_owner; }
|
||||
void SetLoading(bool load) { m_loading = load; }
|
||||
void HandleAsynchLoadSucceed();
|
||||
static void HandleAsynchLoadFailed(AsynchPetSummon* info, Player* player, uint8 asynchLoadType, uint8 loadResult);
|
||||
uint8 GetAsynchLoadType() const { return asynchLoadType; }
|
||||
void SetAsynchLoadType(uint8 type) { asynchLoadType = type; }
|
||||
protected:
|
||||
Player* m_owner;
|
||||
int32 m_happinessTimer;
|
||||
PetType m_petType;
|
||||
int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets)
|
||||
uint64 m_auraRaidUpdateMask;
|
||||
bool m_loading;
|
||||
int32 m_petRegenTimer; // xinef: used for focus regeneration
|
||||
|
||||
DeclinedName *m_declinedname;
|
||||
|
||||
Unit* m_tempspellTarget;
|
||||
Unit* m_tempoldTarget;
|
||||
bool m_tempspellIsPositive;
|
||||
uint32 m_tempspell;
|
||||
|
||||
uint8 asynchLoadType;
|
||||
|
||||
private:
|
||||
void SaveToDB(uint32, uint8, uint32) // override of Creature::SaveToDB - must not be called
|
||||
{
|
||||
ASSERT(false);
|
||||
}
|
||||
void DeleteFromDB() // override of Creature::DeleteFromDB - must not be called
|
||||
{
|
||||
ASSERT(false);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_PET_DEFINES_H
|
||||
#define AZEROTHCORE_PET_DEFINES_H
|
||||
|
||||
enum PetType
|
||||
{
|
||||
SUMMON_PET = 0,
|
||||
HUNTER_PET = 1,
|
||||
MAX_PET_TYPE = 4
|
||||
};
|
||||
|
||||
#define MAX_PET_STABLES 4
|
||||
|
||||
// stored in character_pet.slot
|
||||
enum PetSaveMode
|
||||
{
|
||||
PET_SAVE_AS_DELETED = -1, // not saved in fact
|
||||
PET_SAVE_AS_CURRENT = 0, // in current slot (with player)
|
||||
PET_SAVE_FIRST_STABLE_SLOT = 1,
|
||||
PET_SAVE_LAST_STABLE_SLOT = MAX_PET_STABLES, // last in DB stable slot index (including), all higher have same meaning as PET_SAVE_NOT_IN_SLOT
|
||||
PET_SAVE_NOT_IN_SLOT = 100 // for avoid conflict with stable size grow will use 100
|
||||
};
|
||||
|
||||
enum HappinessState
|
||||
{
|
||||
UNHAPPY = 1,
|
||||
CONTENT = 2,
|
||||
HAPPY = 3
|
||||
};
|
||||
|
||||
enum PetSpellState
|
||||
{
|
||||
PETSPELL_UNCHANGED = 0,
|
||||
PETSPELL_CHANGED = 1,
|
||||
PETSPELL_NEW = 2,
|
||||
PETSPELL_REMOVED = 3
|
||||
};
|
||||
|
||||
enum PetSpellType
|
||||
{
|
||||
PETSPELL_NORMAL = 0,
|
||||
PETSPELL_FAMILY = 1,
|
||||
PETSPELL_TALENT = 2
|
||||
};
|
||||
|
||||
enum ActionFeedback
|
||||
{
|
||||
FEEDBACK_NONE = 0,
|
||||
FEEDBACK_PET_DEAD = 1,
|
||||
FEEDBACK_NOTHING_TO_ATT = 2,
|
||||
FEEDBACK_CANT_ATT_TARGET = 3
|
||||
};
|
||||
|
||||
enum PetTalk
|
||||
{
|
||||
PET_TALK_SPECIAL_SPELL = 0,
|
||||
PET_TALK_ATTACK = 1
|
||||
};
|
||||
|
||||
// used at pet loading query list preparing, and later result selection
|
||||
enum PetLoadQueryIndex
|
||||
{
|
||||
PET_LOAD_QUERY_LOADAURAS = 0,
|
||||
PET_LOAD_QUERY_LOADSPELLS = 1,
|
||||
PET_LOAD_QUERY_LOADSPELLCOOLDOWN = 2,
|
||||
MAX_PET_LOAD_QUERY,
|
||||
};
|
||||
|
||||
enum PetLoadStage
|
||||
{
|
||||
PET_LOAD_DEFAULT = 0,
|
||||
PET_LOAD_HANDLE_UNSTABLE_CALLBACK = 1, // used also in HandleStableSwapPetCallback, uses same error / ok messages
|
||||
PET_LOAD_BG_RESURRECT = 2,
|
||||
PET_LOAD_SUMMON_PET = 3,
|
||||
PET_LOAD_SUMMON_DEAD_PET = 4
|
||||
};
|
||||
|
||||
enum PetLoadState
|
||||
{
|
||||
PET_LOAD_OK = 0,
|
||||
PET_LOAD_NO_RESULT = 1,
|
||||
PET_LOAD_ERROR = 2
|
||||
};
|
||||
|
||||
enum NPCEntries
|
||||
{
|
||||
// Warlock
|
||||
NPC_INFERNAL = 89,
|
||||
NPC_IMP = 416,
|
||||
NPC_FELHUNTER = 417,
|
||||
NPC_VOIDWALKER = 1860,
|
||||
NPC_SUCCUBUS = 1863,
|
||||
NPC_DOOMGUARD = 11859,
|
||||
NPC_FELGUARD = 17252,
|
||||
|
||||
// Mage
|
||||
NPC_WATER_ELEMENTAL_TEMP = 510,
|
||||
NPC_MIRROR_IMAGE = 31216,
|
||||
NPC_WATER_ELEMENTAL_PERM = 37994,
|
||||
|
||||
// Druid
|
||||
NPC_TREANT = 1964,
|
||||
|
||||
// Priest
|
||||
NPC_SHADOWFIEND = 19668,
|
||||
|
||||
// Shaman
|
||||
NPC_FIRE_ELEMENTAL = 15438,
|
||||
NPC_EARTH_ELEMENTAL = 15352,
|
||||
NPC_FERAL_SPIRIT = 29264,
|
||||
|
||||
// Death Knight
|
||||
NPC_RISEN_GHOUL = 26125,
|
||||
NPC_BLOODWORM = 28017,
|
||||
NPC_ARMY_OF_THE_DEAD = 24207,
|
||||
NPC_EBON_GARGOYLE = 27829,
|
||||
|
||||
// Generic
|
||||
NPC_GENERIC_IMP = 12922,
|
||||
NPC_GENERIC_VOIDWALKER = 8996
|
||||
};
|
||||
|
||||
enum PetScalingSpells
|
||||
{
|
||||
SPELL_PET_AVOIDANCE = 32233,
|
||||
|
||||
SPELL_HUNTER_PET_SCALING_01 = 34902,
|
||||
SPELL_HUNTER_PET_SCALING_02 = 34903,
|
||||
SPELL_HUNTER_PET_SCALING_03 = 34904,
|
||||
SPELL_HUNTER_PET_SCALING_04 = 61017, // Hit / Expertise
|
||||
|
||||
// Warlock
|
||||
SPELL_WARLOCK_PET_SCALING_01 = 34947,
|
||||
SPELL_WARLOCK_PET_SCALING_02 = 34956,
|
||||
SPELL_WARLOCK_PET_SCALING_03 = 34957,
|
||||
SPELL_WARLOCK_PET_SCALING_04 = 34958,
|
||||
SPELL_WARLOCK_PET_SCALING_05 = 61013, // Hit / Expertise
|
||||
SPELL_GLYPH_OF_FELGUARD = 56246,
|
||||
SPELL_INFERNAL_SCALING_01 = 36186,
|
||||
SPELL_INFERNAL_SCALING_02 = 36188,
|
||||
SPELL_INFERNAL_SCALING_03 = 36189,
|
||||
SPELL_INFERNAL_SCALING_04 = 36190,
|
||||
SPELL_RITUAL_ENSLAVEMENT = 22987,
|
||||
|
||||
// Shaman
|
||||
SPELL_FERAL_SPIRIT_SPIRIT_HUNT = 58877,
|
||||
SPELL_FERAL_SPIRIT_SCALING_01 = 35674,
|
||||
SPELL_FERAL_SPIRIT_SCALING_02 = 35675,
|
||||
SPELL_FERAL_SPIRIT_SCALING_03 = 35676,
|
||||
SPELL_FIRE_ELEMENTAL_SCALING_01 = 35665,
|
||||
SPELL_FIRE_ELEMENTAL_SCALING_02 = 35666,
|
||||
SPELL_FIRE_ELEMENTAL_SCALING_03 = 35667,
|
||||
SPELL_FIRE_ELEMENTAL_SCALING_04 = 35668,
|
||||
SPELL_EARTH_ELEMENTAL_SCALING_01 = 65225,
|
||||
SPELL_EARTH_ELEMENTAL_SCALING_02 = 65226,
|
||||
SPELL_EARTH_ELEMENTAL_SCALING_03 = 65227,
|
||||
SPELL_EARTH_ELEMENTAL_SCALING_04 = 65228,
|
||||
|
||||
// Priest
|
||||
SPELL_SHADOWFIEND_SCALING_01 = 35661,
|
||||
SPELL_SHADOWFIEND_SCALING_02 = 35662,
|
||||
SPELL_SHADOWFIEND_SCALING_03 = 35663,
|
||||
SPELL_SHADOWFIEND_SCALING_04 = 35664,
|
||||
|
||||
// Druid
|
||||
SPELL_TREANT_SCALING_01 = 35669,
|
||||
SPELL_TREANT_SCALING_02 = 35670,
|
||||
SPELL_TREANT_SCALING_03 = 35671,
|
||||
SPELL_TREANT_SCALING_04 = 35672,
|
||||
|
||||
// Mage
|
||||
SPELL_MAGE_PET_SCALING_01 = 35657,
|
||||
SPELL_MAGE_PET_SCALING_02 = 35658,
|
||||
SPELL_MAGE_PET_SCALING_03 = 35659,
|
||||
SPELL_MAGE_PET_SCALING_04 = 35660,
|
||||
|
||||
// Death Knight
|
||||
SPELL_ORC_RACIAL_COMMAND = 65221,
|
||||
SPELL_NIGHT_OF_THE_DEAD_AVOIDANCE = 62137,
|
||||
SPELL_DK_PET_SCALING_01 = 51996,
|
||||
SPELL_DK_PET_SCALING_02 = 54566,
|
||||
SPELL_DK_PET_SCALING_03 = 61697
|
||||
|
||||
};
|
||||
|
||||
#define PET_FOLLOW_DIST 1.0f
|
||||
#define PET_FOLLOW_ANGLE (M_PI/2)
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SocialMgr.h"
|
||||
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "Util.h"
|
||||
#include "AccountMgr.h"
|
||||
|
||||
PlayerSocial::PlayerSocial()
|
||||
{
|
||||
m_playerGUID = 0;
|
||||
}
|
||||
|
||||
PlayerSocial::~PlayerSocial()
|
||||
{
|
||||
m_playerSocialMap.clear();
|
||||
}
|
||||
|
||||
uint32 PlayerSocial::GetNumberOfSocialsWithFlag(SocialFlag flag) const
|
||||
{
|
||||
uint32 counter = 0;
|
||||
for (PlayerSocialMap::const_iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
|
||||
if (itr->second.Flags & flag)
|
||||
++counter;
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
bool PlayerSocial::AddToSocialList(uint32 friendGuid, bool ignore)
|
||||
{
|
||||
// check client limits
|
||||
if (ignore)
|
||||
{
|
||||
if (GetNumberOfSocialsWithFlag(SOCIAL_FLAG_IGNORED) >= SOCIALMGR_IGNORE_LIMIT)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetNumberOfSocialsWithFlag(SOCIAL_FLAG_FRIEND) >= SOCIALMGR_FRIEND_LIMIT)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 flag = SOCIAL_FLAG_FRIEND;
|
||||
if (ignore)
|
||||
flag = SOCIAL_FLAG_IGNORED;
|
||||
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friendGuid);
|
||||
if (itr != m_playerSocialMap.end())
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_CHARACTER_SOCIAL_FLAGS);
|
||||
|
||||
stmt->setUInt8(0, flag);
|
||||
stmt->setUInt32(1, GetPlayerGUID());
|
||||
stmt->setUInt32(2, friendGuid);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
m_playerSocialMap[friendGuid].Flags |= flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_SOCIAL);
|
||||
|
||||
stmt->setUInt32(0, GetPlayerGUID());
|
||||
stmt->setUInt32(1, friendGuid);
|
||||
stmt->setUInt8(2, flag);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
FriendInfo fi;
|
||||
fi.Flags |= flag;
|
||||
m_playerSocialMap[friendGuid] = fi;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlayerSocial::RemoveFromSocialList(uint32 friendGuid, bool ignore)
|
||||
{
|
||||
PlayerSocialMap::iterator itr = m_playerSocialMap.find(friendGuid);
|
||||
if (itr == m_playerSocialMap.end()) // not exist
|
||||
return;
|
||||
|
||||
uint8 flag = SOCIAL_FLAG_FRIEND;
|
||||
if (ignore)
|
||||
flag = SOCIAL_FLAG_IGNORED;
|
||||
|
||||
itr->second.Flags &= ~flag;
|
||||
if (itr->second.Flags == 0)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SOCIAL);
|
||||
|
||||
stmt->setUInt32(0, GetPlayerGUID());
|
||||
stmt->setUInt32(1, friendGuid);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
m_playerSocialMap.erase(itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_REM_CHARACTER_SOCIAL_FLAGS);
|
||||
|
||||
stmt->setUInt8(0, flag);
|
||||
stmt->setUInt32(1, GetPlayerGUID());
|
||||
stmt->setUInt32(2, friendGuid);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerSocial::SetFriendNote(uint32 friendGuid, std::string note)
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friendGuid);
|
||||
if (itr == m_playerSocialMap.end()) // not exist
|
||||
return;
|
||||
|
||||
utf8truncate(note, 48); // DB and client size limitation
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE);
|
||||
|
||||
stmt->setString(0, note);
|
||||
stmt->setUInt32(1, GetPlayerGUID());
|
||||
stmt->setUInt32(2, friendGuid);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
m_playerSocialMap[friendGuid].Note = note;
|
||||
}
|
||||
|
||||
void PlayerSocial::SendSocialList(Player* player)
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
uint32 size = m_playerSocialMap.size();
|
||||
|
||||
WorldPacket data(SMSG_CONTACT_LIST, (4+4+size*25)); // just can guess size
|
||||
data << uint32(7); // 0x1 = Friendlist update. 0x2 = Ignorelist update. 0x4 = Mutelist update.
|
||||
data << uint32(size); // friends count
|
||||
|
||||
for (PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
|
||||
{
|
||||
sSocialMgr->GetFriendInfo(player, itr->first, itr->second);
|
||||
|
||||
data << uint64(itr->first); // player guid
|
||||
data << uint32(itr->second.Flags); // player flag (0x1 = Friend, 0x2 = Ignored, 0x4 = Muted)
|
||||
data << itr->second.Note; // string note
|
||||
if (itr->second.Flags & SOCIAL_FLAG_FRIEND) // if IsFriend()
|
||||
{
|
||||
data << uint8(itr->second.Status); // online/offline/etc?
|
||||
if (itr->second.Status) // if online
|
||||
{
|
||||
data << uint32(itr->second.Area); // player area
|
||||
data << uint32(itr->second.Level); // player level
|
||||
data << uint32(itr->second.Class); // player class
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player->GetSession()->SendPacket(&data);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_CONTACT_LIST");
|
||||
}
|
||||
|
||||
bool PlayerSocial::HasFriend(uint32 friend_guid) const
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr != m_playerSocialMap.end())
|
||||
return itr->second.Flags & SOCIAL_FLAG_FRIEND;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerSocial::HasIgnore(uint32 ignore_guid) const
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(ignore_guid);
|
||||
if (itr != m_playerSocialMap.end())
|
||||
return itr->second.Flags & SOCIAL_FLAG_IGNORED;
|
||||
return false;
|
||||
}
|
||||
|
||||
SocialMgr::SocialMgr()
|
||||
{
|
||||
}
|
||||
|
||||
SocialMgr::~SocialMgr()
|
||||
{
|
||||
}
|
||||
|
||||
void SocialMgr::GetFriendInfo(Player* player, uint32 friendGUID, FriendInfo &friendInfo)
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
friendInfo.Status = FRIEND_STATUS_OFFLINE;
|
||||
friendInfo.Area = 0;
|
||||
friendInfo.Level = 0;
|
||||
friendInfo.Class = 0;
|
||||
|
||||
Player* pFriend = ObjectAccessor::FindPlayerInOrOutOfWorld(friendGUID);
|
||||
if (!pFriend || AccountMgr::IsGMAccount(pFriend->GetSession()->GetSecurity()))
|
||||
return;
|
||||
|
||||
TeamId teamId = player->GetTeamId();
|
||||
AccountTypes security = player->GetSession()->GetSecurity();
|
||||
bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
|
||||
AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
|
||||
|
||||
PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friendGUID);
|
||||
if (itr != player->GetSocial()->m_playerSocialMap.end())
|
||||
friendInfo.Note = itr->second.Note;
|
||||
|
||||
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
|
||||
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
|
||||
if (pFriend && (!AccountMgr::IsPlayerAccount(security) || ((pFriend->GetTeamId() == teamId || allowTwoSideWhoList) && pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList)) && pFriend->IsVisibleGloballyFor(player))
|
||||
{
|
||||
friendInfo.Status = FRIEND_STATUS_ONLINE;
|
||||
if (pFriend->isAFK())
|
||||
friendInfo.Status = FRIEND_STATUS_AFK;
|
||||
if (pFriend->isDND())
|
||||
friendInfo.Status = FRIEND_STATUS_DND;
|
||||
friendInfo.Area = pFriend->GetZoneId();
|
||||
friendInfo.Level = pFriend->getLevel();
|
||||
friendInfo.Class = pFriend->getClass();
|
||||
}
|
||||
}
|
||||
|
||||
void SocialMgr::MakeFriendStatusPacket(FriendsResult result, uint32 guid, WorldPacket* data)
|
||||
{
|
||||
data->Initialize(SMSG_FRIEND_STATUS, 9);
|
||||
*data << uint8(result);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
void SocialMgr::SendFriendStatus(Player* player, FriendsResult result, uint32 friendGuid, bool broadcast)
|
||||
{
|
||||
FriendInfo fi;
|
||||
|
||||
WorldPacket data;
|
||||
MakeFriendStatusPacket(result, friendGuid, &data);
|
||||
GetFriendInfo(player, friendGuid, fi);
|
||||
switch (result)
|
||||
{
|
||||
case FRIEND_ADDED_OFFLINE:
|
||||
case FRIEND_ADDED_ONLINE:
|
||||
data << fi.Note;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case FRIEND_ADDED_ONLINE:
|
||||
case FRIEND_ONLINE:
|
||||
data << uint8(fi.Status);
|
||||
data << uint32(fi.Area);
|
||||
data << uint32(fi.Level);
|
||||
data << uint32(fi.Class);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (broadcast)
|
||||
BroadcastToFriendListers(player, &data);
|
||||
else
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void SocialMgr::BroadcastToFriendListers(Player* player, WorldPacket* packet)
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
TeamId teamId = player->GetTeamId();
|
||||
AccountTypes security = player->GetSession()->GetSecurity();
|
||||
uint32 guid = player->GetGUIDLow();
|
||||
bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
|
||||
AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
|
||||
|
||||
for (SocialMap::const_iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr2 = itr->second.m_playerSocialMap.find(guid);
|
||||
if (itr2 != itr->second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND))
|
||||
{
|
||||
Player* pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
|
||||
|
||||
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
|
||||
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
|
||||
if (pFriend && (!AccountMgr::IsPlayerAccount(pFriend->GetSession()->GetSecurity()) || ((pFriend->GetTeamId() == teamId || allowTwoSideWhoList) && security <= gmLevelInWhoList)) && player->IsVisibleGloballyFor(pFriend))
|
||||
pFriend->GetSession()->SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayerSocial* SocialMgr::LoadFromDB(PreparedQueryResult result, uint32 guid)
|
||||
{
|
||||
PlayerSocial *social = &m_socialMap[guid];
|
||||
social->SetPlayerGUID(guid);
|
||||
|
||||
if (!result)
|
||||
return social;
|
||||
|
||||
uint32 friendGuid = 0;
|
||||
uint8 flags = 0;
|
||||
std::string note = "";
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
friendGuid = fields[0].GetUInt32();
|
||||
flags = fields[1].GetUInt8();
|
||||
note = fields[2].GetString();
|
||||
|
||||
social->m_playerSocialMap[friendGuid] = FriendInfo(flags, note);
|
||||
|
||||
// client's friends list and ignore list limit
|
||||
if (social->m_playerSocialMap.size() >= (SOCIALMGR_FRIEND_LIMIT + SOCIALMGR_IGNORE_LIMIT))
|
||||
break;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
return social;
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TRINITY_SOCIALMGR_H
|
||||
#define __TRINITY_SOCIALMGR_H
|
||||
|
||||
#include <ace/Singleton.h>
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Common.h"
|
||||
|
||||
class SocialMgr;
|
||||
class PlayerSocial;
|
||||
class Player;
|
||||
class WorldPacket;
|
||||
|
||||
enum FriendStatus
|
||||
{
|
||||
FRIEND_STATUS_OFFLINE = 0x00,
|
||||
FRIEND_STATUS_ONLINE = 0x01,
|
||||
FRIEND_STATUS_AFK = 0x02,
|
||||
FRIEND_STATUS_DND = 0x04,
|
||||
FRIEND_STATUS_RAF = 0x08
|
||||
};
|
||||
|
||||
enum SocialFlag
|
||||
{
|
||||
SOCIAL_FLAG_FRIEND = 0x01,
|
||||
SOCIAL_FLAG_IGNORED = 0x02,
|
||||
SOCIAL_FLAG_MUTED = 0x04, // guessed
|
||||
SOCIAL_FLAG_UNK = 0x08 // Unknown - does not appear to be RaF
|
||||
};
|
||||
|
||||
struct FriendInfo
|
||||
{
|
||||
FriendStatus Status;
|
||||
uint8 Flags;
|
||||
uint32 Area;
|
||||
uint8 Level;
|
||||
uint8 Class;
|
||||
std::string Note;
|
||||
|
||||
FriendInfo() : Status(FRIEND_STATUS_OFFLINE), Flags(0), Area(0), Level(0), Class(0), Note()
|
||||
{ }
|
||||
|
||||
FriendInfo(uint8 flags, std::string const& note) : Status(FRIEND_STATUS_OFFLINE), Flags(flags), Area(0), Level(0), Class(0), Note(note)
|
||||
{ }
|
||||
};
|
||||
|
||||
typedef std::map<uint32, FriendInfo> PlayerSocialMap;
|
||||
typedef std::map<uint32, PlayerSocial> SocialMap;
|
||||
|
||||
/// Results of friend related commands
|
||||
enum FriendsResult
|
||||
{
|
||||
FRIEND_DB_ERROR = 0x00,
|
||||
FRIEND_LIST_FULL = 0x01,
|
||||
FRIEND_ONLINE = 0x02,
|
||||
FRIEND_OFFLINE = 0x03,
|
||||
FRIEND_NOT_FOUND = 0x04,
|
||||
FRIEND_REMOVED = 0x05,
|
||||
FRIEND_ADDED_ONLINE = 0x06,
|
||||
FRIEND_ADDED_OFFLINE = 0x07,
|
||||
FRIEND_ALREADY = 0x08,
|
||||
FRIEND_SELF = 0x09,
|
||||
FRIEND_ENEMY = 0x0A,
|
||||
FRIEND_IGNORE_FULL = 0x0B,
|
||||
FRIEND_IGNORE_SELF = 0x0C,
|
||||
FRIEND_IGNORE_NOT_FOUND = 0x0D,
|
||||
FRIEND_IGNORE_ALREADY = 0x0E,
|
||||
FRIEND_IGNORE_ADDED = 0x0F,
|
||||
FRIEND_IGNORE_REMOVED = 0x10,
|
||||
FRIEND_IGNORE_AMBIGUOUS = 0x11, // That name is ambiguous, type more of the player's server name
|
||||
FRIEND_MUTE_FULL = 0x12,
|
||||
FRIEND_MUTE_SELF = 0x13,
|
||||
FRIEND_MUTE_NOT_FOUND = 0x14,
|
||||
FRIEND_MUTE_ALREADY = 0x15,
|
||||
FRIEND_MUTE_ADDED = 0x16,
|
||||
FRIEND_MUTE_REMOVED = 0x17,
|
||||
FRIEND_MUTE_AMBIGUOUS = 0x18, // That name is ambiguous, type more of the player's server name
|
||||
FRIEND_UNK7 = 0x19, // no message at client
|
||||
FRIEND_UNKNOWN = 0x1A // Unknown friend response from server
|
||||
};
|
||||
|
||||
#define SOCIALMGR_FRIEND_LIMIT 50
|
||||
#define SOCIALMGR_IGNORE_LIMIT 50
|
||||
|
||||
class PlayerSocial
|
||||
{
|
||||
friend class SocialMgr;
|
||||
public:
|
||||
PlayerSocial();
|
||||
~PlayerSocial();
|
||||
// adding/removing
|
||||
bool AddToSocialList(uint32 friend_guid, bool ignore);
|
||||
void RemoveFromSocialList(uint32 friend_guid, bool ignore);
|
||||
void SetFriendNote(uint32 friendGuid, std::string note);
|
||||
// Packet send's
|
||||
void SendSocialList(Player* player);
|
||||
// Misc
|
||||
bool HasFriend(uint32 friend_guid) const;
|
||||
bool HasIgnore(uint32 ignore_guid) const;
|
||||
uint32 GetPlayerGUID() const { return m_playerGUID; }
|
||||
void SetPlayerGUID(uint32 guid) { m_playerGUID = guid; }
|
||||
uint32 GetNumberOfSocialsWithFlag(SocialFlag flag) const;
|
||||
private:
|
||||
PlayerSocialMap m_playerSocialMap;
|
||||
uint32 m_playerGUID;
|
||||
};
|
||||
|
||||
class SocialMgr
|
||||
{
|
||||
friend class ACE_Singleton<SocialMgr, ACE_Null_Mutex>;
|
||||
|
||||
private:
|
||||
SocialMgr();
|
||||
~SocialMgr();
|
||||
|
||||
public:
|
||||
// Misc
|
||||
void RemovePlayerSocial(uint32 guid) { m_socialMap.erase(guid); }
|
||||
|
||||
void GetFriendInfo(Player* player, uint32 friendGUID, FriendInfo &friendInfo);
|
||||
// Packet management
|
||||
void MakeFriendStatusPacket(FriendsResult result, uint32 friend_guid, WorldPacket* data);
|
||||
void SendFriendStatus(Player* player, FriendsResult result, uint32 friend_guid, bool broadcast);
|
||||
void BroadcastToFriendListers(Player* player, WorldPacket* packet);
|
||||
// Loading
|
||||
PlayerSocial *LoadFromDB(PreparedQueryResult result, uint32 guid);
|
||||
private:
|
||||
SocialMap m_socialMap;
|
||||
};
|
||||
|
||||
#define sSocialMgr ACE_Singleton<SocialMgr, ACE_Null_Mutex>::instance()
|
||||
#endif
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Totem.h"
|
||||
#include "Log.h"
|
||||
#include "Group.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
Totem::Totem(SummonPropertiesEntry const* properties, uint64 owner) : Minion(properties, owner, false)
|
||||
{
|
||||
m_unitTypeMask |= UNIT_MASK_TOTEM;
|
||||
m_duration = 0;
|
||||
m_type = TOTEM_PASSIVE;
|
||||
}
|
||||
|
||||
void Totem::Update(uint32 time)
|
||||
{
|
||||
if (!GetOwner()->IsAlive() || !IsAlive())
|
||||
{
|
||||
UnSummon(); // remove self
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_duration <= time)
|
||||
{
|
||||
UnSummon(); // remove self
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_duration -= time;
|
||||
|
||||
Creature::Update(time);
|
||||
}
|
||||
|
||||
void Totem::InitStats(uint32 duration)
|
||||
{
|
||||
// client requires SMSG_TOTEM_CREATED to be sent before adding to world and before removing old totem
|
||||
// Xinef: Set level for Unit totems
|
||||
if (Unit* owner = ObjectAccessor::FindUnit(m_owner))
|
||||
{
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER && m_Properties->Slot >= SUMMON_SLOT_TOTEM && m_Properties->Slot < MAX_TOTEM_SLOT)
|
||||
{
|
||||
WorldPacket data(SMSG_TOTEM_CREATED, 1 + 8 + 4 + 4);
|
||||
data << uint8(m_Properties->Slot - 1);
|
||||
data << uint64(GetGUID());
|
||||
data << uint32(duration);
|
||||
data << uint32(GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
||||
owner->ToPlayer()->SendDirectMessage(&data);
|
||||
|
||||
// set display id depending on caster's race
|
||||
SetDisplayId(owner->GetModelForTotem(PlayerTotemType(m_Properties->Id)));
|
||||
}
|
||||
|
||||
SetLevel(owner->getLevel());
|
||||
}
|
||||
|
||||
Minion::InitStats(duration);
|
||||
|
||||
// Get spell cast by totem
|
||||
if (SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(GetSpell()))
|
||||
if (totemSpell->CalcCastTime()) // If spell has cast time -> its an active totem
|
||||
m_type = TOTEM_ACTIVE;
|
||||
|
||||
|
||||
m_duration = duration;
|
||||
}
|
||||
|
||||
void Totem::InitSummon()
|
||||
{
|
||||
if (m_type == TOTEM_PASSIVE && GetSpell())
|
||||
CastSpell(this, GetSpell(), true);
|
||||
|
||||
// Some totems can have both instant effect and passive spell
|
||||
if(GetSpell(1))
|
||||
CastSpell(this, GetSpell(1), true);
|
||||
|
||||
// xinef: this is better than the script, 100% sure to work
|
||||
if(GetEntry() == SENTRY_TOTEM_ENTRY)
|
||||
{
|
||||
SetReactState(REACT_AGGRESSIVE);
|
||||
GetOwner()->CastSpell(this, 6277, true);
|
||||
}
|
||||
|
||||
this->GetMotionMaster()->MoveFall();
|
||||
}
|
||||
|
||||
void Totem::UnSummon(uint32 msTime)
|
||||
{
|
||||
if (msTime)
|
||||
{
|
||||
m_Events.AddEvent(new ForcedUnsummonDelayEvent(*this), m_Events.CalculateTime(msTime));
|
||||
return;
|
||||
}
|
||||
|
||||
CombatStop();
|
||||
RemoveAurasDueToSpell(GetSpell(), GetGUID());
|
||||
|
||||
Unit *m_owner = GetOwner();
|
||||
// clear owner's totem slot
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
|
||||
{
|
||||
if (m_owner->m_SummonSlot[i] == GetGUID())
|
||||
{
|
||||
m_owner->m_SummonSlot[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_owner->RemoveAurasDueToSpell(GetSpell(), GetGUID());
|
||||
|
||||
// Remove Sentry Totem Aura
|
||||
if (GetEntry() == SENTRY_TOTEM_ENTRY)
|
||||
m_owner->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID);
|
||||
|
||||
//remove aura all party members too
|
||||
if (Player* owner = m_owner->ToPlayer())
|
||||
{
|
||||
owner->SendAutoRepeatCancel(this);
|
||||
|
||||
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
|
||||
owner->SendCooldownEvent(spell, 0, NULL, false);
|
||||
|
||||
if (Group* group = owner->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player* target = itr->GetSource();
|
||||
if (target && target->IsInMap(owner) && group->SameSubGroup(owner, target))
|
||||
target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
|
||||
{
|
||||
// xinef: immune to all positive spells, except of stoneclaw totem absorb and sentry totem bind sight
|
||||
// totems positive spells have unit_caster target
|
||||
if (spellInfo->Effects[index].Effect != SPELL_EFFECT_DUMMY &&
|
||||
spellInfo->Effects[index].Effect != SPELL_EFFECT_SCRIPT_EFFECT &&
|
||||
spellInfo->IsPositive() && spellInfo->Effects[index].TargetA.GetTarget() != TARGET_UNIT_CASTER &&
|
||||
spellInfo->Effects[index].TargetA.GetCheckType() != TARGET_CHECK_ENTRY && spellInfo->Id != 55277 && spellInfo->Id != 6277)
|
||||
return true;
|
||||
|
||||
switch (spellInfo->Effects[index].ApplyAuraName)
|
||||
{
|
||||
// i think its wrong (xinef)
|
||||
//case SPELL_AURA_PERIODIC_LEECH:
|
||||
case SPELL_AURA_PERIODIC_DAMAGE:
|
||||
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
|
||||
case SPELL_AURA_MOD_FEAR:
|
||||
case SPELL_AURA_TRANSFORM:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Creature::IsImmunedToSpellEffect(spellInfo, index);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_TOTEM_H
|
||||
#define AZEROTHCORE_TOTEM_H
|
||||
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum TotemType
|
||||
{
|
||||
TOTEM_PASSIVE = 0,
|
||||
TOTEM_ACTIVE = 1,
|
||||
TOTEM_STATUE = 2 // copied straight from moongose, may need more implementation to work
|
||||
};
|
||||
// Some Totems cast spells that are not in creature DB
|
||||
#define SENTRY_TOTEM_SPELLID 6495
|
||||
|
||||
#define SENTRY_TOTEM_ENTRY 3968
|
||||
#define EARTHBIND_TOTEM_ENTRY 2630
|
||||
|
||||
class Totem : public Minion
|
||||
{
|
||||
public:
|
||||
explicit Totem(SummonPropertiesEntry const *properties, uint64 owner);
|
||||
virtual ~Totem(){};
|
||||
void Update(uint32 time);
|
||||
void InitStats(uint32 duration);
|
||||
void InitSummon();
|
||||
void UnSummon(uint32 msTime = 0);
|
||||
uint32 GetSpell(uint8 slot = 0) const { return m_spells[slot]; }
|
||||
uint32 GetTotemDuration() const { return m_duration; }
|
||||
void SetTotemDuration(uint32 duration) { m_duration = duration; }
|
||||
TotemType GetTotemType() const { return m_type; }
|
||||
|
||||
bool UpdateStats(Stats /*stat*/) { return true; }
|
||||
bool UpdateAllStats() { return true; }
|
||||
void UpdateResistances(uint32 /*school*/) {}
|
||||
void UpdateArmor() {}
|
||||
void UpdateMaxHealth() {}
|
||||
void UpdateMaxPower(Powers /*power*/) {}
|
||||
void UpdateAttackPowerAndDamage(bool /*ranged*/) {}
|
||||
void UpdateDamagePhysical(WeaponAttackType /*attType*/) {}
|
||||
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const;
|
||||
|
||||
protected:
|
||||
TotemType m_type;
|
||||
uint32 m_duration;
|
||||
};
|
||||
#endif
|
||||
@@ -1,974 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Transport.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "DBCStores.h"
|
||||
#include "World.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "Vehicle.h"
|
||||
#include "MapReference.h"
|
||||
#include "Player.h"
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
#include "WorldModel.h"
|
||||
#include "Spell.h"
|
||||
|
||||
MotionTransport::MotionTransport() : Transport(), _transportInfo(NULL), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengersLoaded(false), _delayedTeleport(false)
|
||||
{
|
||||
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
|
||||
}
|
||||
|
||||
MotionTransport::~MotionTransport()
|
||||
{
|
||||
ASSERT(_passengers.empty());
|
||||
UnloadStaticPassengers();
|
||||
}
|
||||
|
||||
bool MotionTransport::CreateMoTrans(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress)
|
||||
{
|
||||
Relocate(x, y, z, ang);
|
||||
|
||||
if (!IsPositionValid())
|
||||
{
|
||||
sLog->outError("Transport (GUID: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
|
||||
guidlow, x, y);
|
||||
return false;
|
||||
}
|
||||
|
||||
Object::_Create(guidlow, 0, HIGHGUID_MO_TRANSPORT);
|
||||
|
||||
GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
|
||||
|
||||
if (!goinfo)
|
||||
{
|
||||
sLog->outError("Transport not created: entry in `gameobject_template` not found, guidlow: %u map: %u (X: %f Y: %f Z: %f) ang: %f", guidlow, mapid, x, y, z, ang);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_goInfo = goinfo;
|
||||
|
||||
TransportTemplate const* tInfo = sTransportMgr->GetTransportTemplate(entry);
|
||||
if (!tInfo)
|
||||
{
|
||||
sLog->outError("Transport %u (name: %s) will not be created, missing `transport_template` entry.", entry, goinfo->name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_transportInfo = tInfo;
|
||||
|
||||
// initialize waypoints
|
||||
_nextFrame = tInfo->keyFrames.begin();
|
||||
_currentFrame = _nextFrame++;
|
||||
_triggeredArrivalEvent = false;
|
||||
_triggeredDepartureEvent = false;
|
||||
|
||||
SetObjectScale(goinfo->size);
|
||||
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
|
||||
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
|
||||
SetPathProgress(0);
|
||||
SetPeriod(tInfo->pathTime);
|
||||
SetEntry(goinfo->entry);
|
||||
SetDisplayId(goinfo->displayId);
|
||||
SetGoState(!goinfo->moTransport.canBeStopped ? GO_STATE_READY : GO_STATE_ACTIVE);
|
||||
SetGoType(GAMEOBJECT_TYPE_MO_TRANSPORT);
|
||||
SetGoAnimProgress(animprogress);
|
||||
SetName(goinfo->name);
|
||||
|
||||
// pussywizard: no WorldRotation for MotionTransports
|
||||
SetWorldRotation(G3D::Quat());
|
||||
// pussywizard: no PathRotation for MotionTransports
|
||||
SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
m_model = GameObjectModel::Create(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MotionTransport::CleanupsBeforeDelete(bool finalCleanup /*= true*/)
|
||||
{
|
||||
UnloadStaticPassengers();
|
||||
while (!_passengers.empty())
|
||||
{
|
||||
WorldObject* obj = *_passengers.begin();
|
||||
RemovePassenger(obj);
|
||||
obj->SetTransport(NULL);
|
||||
obj->m_movementInfo.transport.Reset();
|
||||
obj->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
}
|
||||
|
||||
GameObject::CleanupsBeforeDelete(finalCleanup);
|
||||
}
|
||||
|
||||
void MotionTransport::BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet&)
|
||||
{
|
||||
Map::PlayerList const& players = GetMap()->GetPlayers();
|
||||
if (players.isEmpty())
|
||||
return;
|
||||
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
BuildFieldsUpdate(itr->GetSource(), data_map);
|
||||
|
||||
ClearUpdateMask(true);
|
||||
}
|
||||
|
||||
void MotionTransport::Update(uint32 diff)
|
||||
{
|
||||
uint32 const positionUpdateDelay = 1;
|
||||
|
||||
if (AI())
|
||||
AI()->UpdateAI(diff);
|
||||
else if (!AIM_Initialize())
|
||||
sLog->outError("Could not initialize GameObjectAI for Transport");
|
||||
|
||||
if (GetKeyFrames().size() <= 1)
|
||||
return;
|
||||
|
||||
if (IsMoving() || !_pendingStop)
|
||||
SetPathProgress(GetPathProgress() + diff);
|
||||
|
||||
uint32 timer = GetPathProgress() % GetPeriod();
|
||||
|
||||
// Set current waypoint
|
||||
// Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime
|
||||
// ... arrive | ... delay ... | departure
|
||||
// event / event /
|
||||
for (;;)
|
||||
{
|
||||
if (timer >= _currentFrame->ArriveTime)
|
||||
{
|
||||
if (!_triggeredArrivalEvent)
|
||||
{
|
||||
DoEventIfAny(*_currentFrame, false);
|
||||
_triggeredArrivalEvent = true;
|
||||
}
|
||||
|
||||
if (timer < _currentFrame->DepartureTime)
|
||||
{
|
||||
SetMoving(false);
|
||||
if (_pendingStop && GetGoState() != GO_STATE_READY)
|
||||
{
|
||||
SetGoState(GO_STATE_READY);
|
||||
SetPathProgress(GetPathProgress() / GetPeriod());
|
||||
SetPathProgress(GetPathProgress() * GetPeriod());
|
||||
SetPathProgress(GetPathProgress() + _currentFrame->ArriveTime);
|
||||
}
|
||||
break; // its a stop frame and we are waiting
|
||||
}
|
||||
}
|
||||
|
||||
if (timer >= _currentFrame->DepartureTime && !_triggeredDepartureEvent)
|
||||
{
|
||||
DoEventIfAny(*_currentFrame, true); // departure event
|
||||
_triggeredDepartureEvent = true;
|
||||
}
|
||||
|
||||
// not waiting anymore
|
||||
SetMoving(true);
|
||||
|
||||
// Enable movement
|
||||
if (GetGOInfo()->moTransport.canBeStopped)
|
||||
SetGoState(GO_STATE_ACTIVE);
|
||||
|
||||
if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime)
|
||||
break; // found current waypoint
|
||||
|
||||
MoveToNextWaypoint();
|
||||
|
||||
sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
|
||||
|
||||
//TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
|
||||
|
||||
// Departure event
|
||||
if (_currentFrame->IsTeleportFrame())
|
||||
if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z, _nextFrame->InitialOrientation))
|
||||
return; // Update more in new map thread
|
||||
}
|
||||
|
||||
// Set position
|
||||
_positionChangeTimer.Update(diff);
|
||||
if (_positionChangeTimer.Passed())
|
||||
{
|
||||
_positionChangeTimer.Reset(positionUpdateDelay);
|
||||
if (IsMoving())
|
||||
{
|
||||
float t = CalculateSegmentPos(float(timer) * 0.001f);
|
||||
G3D::Vector3 pos, dir;
|
||||
_currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos);
|
||||
_currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir);
|
||||
UpdatePosition(pos.x, pos.y, pos.z, NormalizeOrientation(atan2(dir.y, dir.x) + M_PI));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There are four possible scenarios that trigger loading/unloading passengers:
|
||||
1. transport moves from inactive to active grid
|
||||
2. the grid that transport is currently in becomes active
|
||||
3. transport moves from active to inactive grid
|
||||
4. the grid that transport is currently in unloads
|
||||
*/
|
||||
if (_staticPassengers.empty() && GetMap()->IsGridLoaded(GetPositionX(), GetPositionY())) // 2.
|
||||
LoadStaticPassengers();
|
||||
}
|
||||
}
|
||||
|
||||
sScriptMgr->OnTransportUpdate(this, diff);
|
||||
}
|
||||
|
||||
void MotionTransport::DelayedUpdate(uint32 diff)
|
||||
{
|
||||
if (GetKeyFrames().size() <= 1)
|
||||
return;
|
||||
|
||||
DelayedTeleportTransport();
|
||||
}
|
||||
|
||||
void MotionTransport::UpdatePosition(float x, float y, float z, float o)
|
||||
{
|
||||
if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case
|
||||
GetMap()->LoadGrid(x, y);
|
||||
|
||||
Relocate(x, y, z, o);
|
||||
UpdateModelPosition();
|
||||
|
||||
UpdatePassengerPositions(_passengers);
|
||||
|
||||
if (_staticPassengers.empty())
|
||||
LoadStaticPassengers();
|
||||
else
|
||||
UpdatePassengerPositions(_staticPassengers);
|
||||
}
|
||||
|
||||
void MotionTransport::AddPassenger(WorldObject* passenger, bool withAll)
|
||||
{
|
||||
TRINITY_GUARD(ACE_Thread_Mutex, Lock);
|
||||
if (_passengers.insert(passenger).second)
|
||||
{
|
||||
if (Player* plr = passenger->ToPlayer())
|
||||
sScriptMgr->OnAddPassenger(ToTransport(), plr);
|
||||
|
||||
if (withAll)
|
||||
{
|
||||
if (Transport* t = passenger->GetTransport()) // SHOULD NEVER HAPPEN
|
||||
t->RemovePassenger(passenger, false);
|
||||
|
||||
float x, y, z, o;
|
||||
passenger->GetPosition(x, y, z, o);
|
||||
CalculatePassengerOffset(x, y, z, &o);
|
||||
|
||||
passenger->SetTransport(this);
|
||||
passenger->m_movementInfo.flags |= MOVEMENTFLAG_ONTRANSPORT;
|
||||
passenger->m_movementInfo.transport.guid = GetGUID();
|
||||
passenger->m_movementInfo.transport.pos.Relocate(x, y, z, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MotionTransport::RemovePassenger(WorldObject* passenger, bool withAll)
|
||||
{
|
||||
TRINITY_GUARD(ACE_Thread_Mutex, Lock);
|
||||
if (_passengers.erase(passenger) || _staticPassengers.erase(passenger))
|
||||
{
|
||||
if (Player* plr = passenger->ToPlayer())
|
||||
{
|
||||
sScriptMgr->OnRemovePassenger(ToTransport(), plr);
|
||||
plr->SetFallInformation(time(NULL), plr->GetPositionZ());
|
||||
}
|
||||
|
||||
if (withAll)
|
||||
{
|
||||
passenger->SetTransport(NULL);
|
||||
passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
|
||||
passenger->m_movementInfo.transport.guid = 0;
|
||||
passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Creature* MotionTransport::CreateNPCPassenger(uint32 guid, CreatureData const* data)
|
||||
{
|
||||
Map* map = GetMap();
|
||||
Creature* creature = new Creature();
|
||||
|
||||
if (!creature->LoadCreatureFromDB(guid, map, false))
|
||||
{
|
||||
delete creature;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float x = data->posX;
|
||||
float y = data->posY;
|
||||
float z = data->posZ;
|
||||
float o = data->orientation;
|
||||
|
||||
creature->SetTransport(this);
|
||||
creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
creature->m_movementInfo.transport.guid = GetGUID();
|
||||
creature->m_movementInfo.transport.pos.Relocate(x, y, z, o);
|
||||
CalculatePassengerPosition(x, y, z, &o);
|
||||
creature->Relocate(x, y, z, o);
|
||||
creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
|
||||
creature->SetTransportHomePosition(creature->m_movementInfo.transport.pos);
|
||||
|
||||
/// @HACK - transport models are not added to map's dynamic LoS calculations
|
||||
/// because the current GameObjectModel cannot be moved without recreating
|
||||
creature->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING);
|
||||
|
||||
if (!creature->IsPositionValid())
|
||||
{
|
||||
sLog->outError("Creature (guidlow %d, entry %d) not created. Suggested coordinates aren't valid (X: %f Y: %f)",creature->GetGUIDLow(),creature->GetEntry(),creature->GetPositionX(),creature->GetPositionY());
|
||||
delete creature;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!map->AddToMap(creature))
|
||||
{
|
||||
delete creature;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_staticPassengers.insert(creature);
|
||||
sScriptMgr->OnAddCreaturePassenger(this, creature);
|
||||
return creature;
|
||||
}
|
||||
|
||||
GameObject* MotionTransport::CreateGOPassenger(uint32 guid, GameObjectData const* data)
|
||||
{
|
||||
Map* map = GetMap();
|
||||
GameObject* go = new GameObject();
|
||||
ASSERT(!sObjectMgr->IsGameObjectStaticTransport(data->id));
|
||||
|
||||
if (!go->LoadGameObjectFromDB(guid, map, false))
|
||||
{
|
||||
delete go;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float x = data->posX;
|
||||
float y = data->posY;
|
||||
float z = data->posZ;
|
||||
float o = data->orientation;
|
||||
|
||||
go->SetTransport(this);
|
||||
go->m_movementInfo.transport.guid = GetGUID();
|
||||
go->m_movementInfo.transport.pos.Relocate(x, y, z, o);
|
||||
CalculatePassengerPosition(x, y, z, &o);
|
||||
go->Relocate(x, y, z, o);
|
||||
|
||||
if (!go->IsPositionValid())
|
||||
{
|
||||
sLog->outError("GameObject (guidlow %d, entry %d) not created. Suggested coordinates aren't valid (X: %f Y: %f)", go->GetGUIDLow(), go->GetEntry(), go->GetPositionX(), go->GetPositionY());
|
||||
delete go;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!map->AddToMap(go))
|
||||
{
|
||||
delete go;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_staticPassengers.insert(go);
|
||||
return go;
|
||||
}
|
||||
|
||||
void MotionTransport::LoadStaticPassengers()
|
||||
{
|
||||
if (PassengersLoaded())
|
||||
return;
|
||||
SetPassengersLoaded(true);
|
||||
if (uint32 mapId = GetGOInfo()->moTransport.mapID)
|
||||
{
|
||||
CellObjectGuidsMap const& cells = sObjectMgr->GetMapObjectGuids(mapId, GetMap()->GetSpawnMode());
|
||||
CellGuidSet::const_iterator guidEnd;
|
||||
for (CellObjectGuidsMap::const_iterator cellItr = cells.begin(); cellItr != cells.end(); ++cellItr)
|
||||
{
|
||||
// Creatures on transport
|
||||
guidEnd = cellItr->second.creatures.end();
|
||||
for (CellGuidSet::const_iterator guidItr = cellItr->second.creatures.begin(); guidItr != guidEnd; ++guidItr)
|
||||
CreateNPCPassenger(*guidItr, sObjectMgr->GetCreatureData(*guidItr));
|
||||
|
||||
// GameObjects on transport
|
||||
guidEnd = cellItr->second.gameobjects.end();
|
||||
for (CellGuidSet::const_iterator guidItr = cellItr->second.gameobjects.begin(); guidItr != guidEnd; ++guidItr)
|
||||
CreateGOPassenger(*guidItr, sObjectMgr->GetGOData(*guidItr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MotionTransport::UnloadStaticPassengers()
|
||||
{
|
||||
SetPassengersLoaded(false);
|
||||
while (!_staticPassengers.empty())
|
||||
{
|
||||
WorldObject* obj = *_staticPassengers.begin();
|
||||
obj->AddObjectToRemoveList(); // also removes from _staticPassengers
|
||||
}
|
||||
}
|
||||
|
||||
void MotionTransport::UnloadNonStaticPassengers()
|
||||
{
|
||||
for (PassengerSet::iterator itr = _passengers.begin(); itr != _passengers.end(); )
|
||||
{
|
||||
if ((*itr)->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
PassengerSet::iterator itr2 = itr++;
|
||||
(*itr2)->AddObjectToRemoveList();
|
||||
}
|
||||
}
|
||||
|
||||
void MotionTransport::EnableMovement(bool enabled)
|
||||
{
|
||||
if (!GetGOInfo()->moTransport.canBeStopped)
|
||||
return;
|
||||
|
||||
_pendingStop = !enabled;
|
||||
}
|
||||
|
||||
void MotionTransport::MoveToNextWaypoint()
|
||||
{
|
||||
// Clear events flagging
|
||||
_triggeredArrivalEvent = false;
|
||||
_triggeredDepartureEvent = false;
|
||||
|
||||
// Set frames
|
||||
_currentFrame = _nextFrame++;
|
||||
if (_nextFrame == GetKeyFrames().end())
|
||||
_nextFrame = GetKeyFrames().begin();
|
||||
}
|
||||
|
||||
float MotionTransport::CalculateSegmentPos(float now)
|
||||
{
|
||||
KeyFrame const& frame = *_currentFrame;
|
||||
const float speed = float(m_goInfo->moTransport.moveSpeed);
|
||||
const float accel = float(m_goInfo->moTransport.accelRate);
|
||||
float timeSinceStop = frame.TimeFrom + (now - (1.0f/IN_MILLISECONDS) * frame.DepartureTime);
|
||||
float timeUntilStop = frame.TimeTo - (now - (1.0f/IN_MILLISECONDS) * frame.DepartureTime);
|
||||
float segmentPos, dist;
|
||||
float accelTime = _transportInfo->accelTime;
|
||||
float accelDist = _transportInfo->accelDist;
|
||||
// calculate from nearest stop, less confusing calculation...
|
||||
if (timeSinceStop < timeUntilStop)
|
||||
{
|
||||
if (timeSinceStop < accelTime)
|
||||
dist = 0.5f * accel * timeSinceStop * timeSinceStop;
|
||||
else
|
||||
dist = accelDist + (timeSinceStop - accelTime) * speed;
|
||||
segmentPos = dist - frame.DistSinceStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (timeUntilStop < _transportInfo->accelTime)
|
||||
dist = 0.5f * accel * timeUntilStop * timeUntilStop;
|
||||
else
|
||||
dist = accelDist + (timeUntilStop - accelTime) * speed;
|
||||
segmentPos = frame.DistUntilStop - dist;
|
||||
}
|
||||
|
||||
return segmentPos / frame.NextDistFromPrev;
|
||||
}
|
||||
|
||||
bool MotionTransport::TeleportTransport(uint32 newMapid, float x, float y, float z, float o)
|
||||
{
|
||||
Map const* oldMap = GetMap();
|
||||
|
||||
if (oldMap->GetId() != newMapid)
|
||||
{
|
||||
_delayedTeleport = true;
|
||||
UnloadStaticPassengers();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Teleport players, they need to know it
|
||||
for (PassengerSet::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
float destX, destY, destZ, destO;
|
||||
(*itr)->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
|
||||
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
|
||||
|
||||
(*itr)->ToUnit()->NearTeleportTo(destX, destY, destZ, destO);
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePosition(x, y, z, o);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void MotionTransport::DelayedTeleportTransport()
|
||||
{
|
||||
if (!_delayedTeleport)
|
||||
return;
|
||||
|
||||
_delayedTeleport = false;
|
||||
|
||||
uint32 newMapId = _nextFrame->Node->mapid;
|
||||
float x = _nextFrame->Node->x,
|
||||
y = _nextFrame->Node->y,
|
||||
z = _nextFrame->Node->z,
|
||||
o =_nextFrame->InitialOrientation;
|
||||
|
||||
PassengerSet _passengersCopy = _passengers;
|
||||
for (PassengerSet::iterator itr = _passengersCopy.begin(); itr != _passengersCopy.end(); )
|
||||
{
|
||||
WorldObject* obj = (*itr++);
|
||||
|
||||
if (_passengers.find(obj) == _passengers.end())
|
||||
continue;
|
||||
|
||||
switch (obj->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
_passengers.erase(obj);
|
||||
if (!obj->ToCreature()->IsPet())
|
||||
obj->ToCreature()->DespawnOrUnsummon();
|
||||
break;
|
||||
case TYPEID_GAMEOBJECT:
|
||||
_passengers.erase(obj);
|
||||
obj->ToGameObject()->Delete();
|
||||
break;
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
_passengers.erase(obj);
|
||||
if (Unit* caster = obj->ToDynObject()->GetCaster())
|
||||
if (Spell* s = caster->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
||||
if (obj->ToDynObject()->GetSpellId() == s->GetSpellInfo()->Id)
|
||||
{
|
||||
s->SendChannelUpdate(0);
|
||||
s->SendInterrupted(0);
|
||||
caster->RemoveOwnedAura(s->GetSpellInfo()->Id, caster->GetGUID());
|
||||
}
|
||||
obj->AddObjectToRemoveList();
|
||||
break;
|
||||
case TYPEID_PLAYER:
|
||||
{
|
||||
float destX, destY, destZ, destO;
|
||||
obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
|
||||
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
|
||||
if (!obj->ToPlayer()->TeleportTo(newMapId, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
|
||||
_passengers.erase(obj);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Map* newMap = sMapMgr->CreateBaseMap(newMapId);
|
||||
GetMap()->RemoveFromMap<MotionTransport>(this, false);
|
||||
newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map
|
||||
SetMap(newMap);
|
||||
|
||||
Relocate(x, y, z, o);
|
||||
GetMap()->AddToMap<MotionTransport>(this);
|
||||
|
||||
LoadStaticPassengers();
|
||||
}
|
||||
|
||||
void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers)
|
||||
{
|
||||
for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
|
||||
{
|
||||
WorldObject* passenger = *itr;
|
||||
// transport teleported but passenger not yet (can happen for players)
|
||||
if (passenger->GetMap() != GetMap())
|
||||
continue;
|
||||
|
||||
// if passenger is on vehicle we have to assume the vehicle is also on transport and its the vehicle that will be updating its passengers
|
||||
if (Unit* unit = passenger->ToUnit())
|
||||
if (unit->GetVehicle())
|
||||
continue;
|
||||
|
||||
// Do not use Unit::UpdatePosition here, we don't want to remove auras as if regular movement occurred
|
||||
float x, y, z, o;
|
||||
passenger->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
|
||||
CalculatePassengerPosition(x, y, z, &o);
|
||||
|
||||
// check if position is valid
|
||||
if (!Trinity::IsValidMapCoord(x, y, z))
|
||||
continue;
|
||||
|
||||
switch (passenger->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
{
|
||||
Creature* creature = passenger->ToCreature();
|
||||
GetMap()->CreatureRelocation(creature, x, y, z, o);
|
||||
|
||||
creature->GetTransportHomePosition(x, y, z, o);
|
||||
CalculatePassengerPosition(x, y, z, &o);
|
||||
creature->SetHomePosition(x, y, z, o);
|
||||
}
|
||||
break;
|
||||
case TYPEID_PLAYER:
|
||||
if (passenger->IsInWorld())
|
||||
GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o);
|
||||
break;
|
||||
case TYPEID_GAMEOBJECT:
|
||||
GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o);
|
||||
break;
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MotionTransport::DoEventIfAny(KeyFrame const& node, bool departure)
|
||||
{
|
||||
if (uint32 eventid = departure ? node.Node->departureEventID : node.Node->arrivalEventID)
|
||||
{
|
||||
//TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->index, GetName().c_str());
|
||||
GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
|
||||
EventInform(eventid);
|
||||
}
|
||||
}
|
||||
|
||||
// pussywizard: StaticTransport below
|
||||
|
||||
StaticTransport::StaticTransport() : Transport(), _needDoInitialRelocation(false)
|
||||
{
|
||||
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
|
||||
}
|
||||
|
||||
StaticTransport::~StaticTransport()
|
||||
{
|
||||
ASSERT(_passengers.empty());
|
||||
}
|
||||
|
||||
bool StaticTransport::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)
|
||||
{
|
||||
ASSERT(map);
|
||||
SetMap(map);
|
||||
|
||||
Relocate(x, y, z, ang);
|
||||
m_stationaryPosition.Relocate(x, y, z, ang);
|
||||
if (!IsPositionValid())
|
||||
{
|
||||
sLog->outError("Gameobject (GUID: %u Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, name_id, x, y);
|
||||
return false;
|
||||
}
|
||||
|
||||
SetPhaseMask(phaseMask, false);
|
||||
|
||||
SetZoneScript();
|
||||
if (m_zoneScript)
|
||||
{
|
||||
name_id = m_zoneScript->GetGameObjectEntry(guidlow, name_id);
|
||||
if (!name_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(name_id);
|
||||
if (!goinfo)
|
||||
{
|
||||
sLog->outErrorDb("Gameobject (GUID: %u Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", guidlow, name_id, map->GetId(), x, y, z);
|
||||
return false;
|
||||
}
|
||||
|
||||
Object::_Create(guidlow, 0, HIGHGUID_TRANSPORT);
|
||||
|
||||
m_goInfo = goinfo;
|
||||
|
||||
if (goinfo->type >= MAX_GAMEOBJECT_TYPE)
|
||||
{
|
||||
sLog->outErrorDb("Gameobject (GUID: %u Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guidlow, name_id, goinfo->type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct
|
||||
//SetWorldRotation( /*for StaticTransport we need 2 rotation Quats in db for World- and Path- Rotation*/ );
|
||||
SetWorldRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
|
||||
// pussywizard: PathRotation for StaticTransport (only StaticTransports have PathRotation)
|
||||
SetTransportPathRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
|
||||
SetObjectScale(goinfo->size);
|
||||
|
||||
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
|
||||
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
|
||||
|
||||
SetEntry(goinfo->entry);
|
||||
SetName(goinfo->name);
|
||||
|
||||
SetDisplayId(goinfo->displayId);
|
||||
|
||||
if (!m_model)
|
||||
m_model = GameObjectModel::Create(*this);
|
||||
|
||||
SetGoType(GameobjectTypes(goinfo->type));
|
||||
SetGoState(go_state);
|
||||
SetGoArtKit(artKit);
|
||||
|
||||
SetGoState(goinfo->transport.startOpen ? GO_STATE_ACTIVE : GO_STATE_READY);
|
||||
SetGoAnimProgress(animprogress);
|
||||
m_goValue.Transport.AnimationInfo = sTransportMgr->GetTransportAnimInfo(goinfo->entry);
|
||||
//ASSERT(m_goValue.Transport.AnimationInfo);
|
||||
//ASSERT(m_goValue.Transport.AnimationInfo->TotalTime > 0);
|
||||
SetPauseTime(goinfo->transport.pauseAtTime);
|
||||
if (goinfo->transport.startOpen && goinfo->transport.pauseAtTime)
|
||||
{
|
||||
SetPathProgress(goinfo->transport.pauseAtTime);
|
||||
_needDoInitialRelocation = true;
|
||||
}
|
||||
else
|
||||
SetPathProgress(0);
|
||||
|
||||
if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(guidlow))
|
||||
{
|
||||
if (addon->InvisibilityValue)
|
||||
{
|
||||
m_invisibility.AddFlag(addon->invisibilityType);
|
||||
m_invisibility.AddValue(addon->invisibilityType, addon->InvisibilityValue);
|
||||
}
|
||||
}
|
||||
|
||||
LastUsedScriptID = GetGOInfo()->ScriptId;
|
||||
AIM_Initialize();
|
||||
|
||||
this->setActive(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StaticTransport::CleanupsBeforeDelete(bool finalCleanup /*= true*/)
|
||||
{
|
||||
while (!_passengers.empty())
|
||||
{
|
||||
WorldObject* obj = *_passengers.begin();
|
||||
RemovePassenger(obj);
|
||||
obj->SetTransport(NULL);
|
||||
obj->m_movementInfo.transport.Reset();
|
||||
obj->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
}
|
||||
|
||||
GameObject::CleanupsBeforeDelete(finalCleanup);
|
||||
}
|
||||
|
||||
void StaticTransport::BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet&)
|
||||
{
|
||||
Map::PlayerList const& players = GetMap()->GetPlayers();
|
||||
if (players.isEmpty())
|
||||
return;
|
||||
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
BuildFieldsUpdate(itr->GetSource(), data_map);
|
||||
|
||||
ClearUpdateMask(true);
|
||||
}
|
||||
|
||||
void StaticTransport::Update(uint32 diff)
|
||||
{
|
||||
GameObject::Update(diff);
|
||||
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
if (!m_goValue.Transport.AnimationInfo)
|
||||
return;
|
||||
|
||||
if (_needDoInitialRelocation)
|
||||
{
|
||||
_needDoInitialRelocation = false;
|
||||
RelocateToProgress(GetPathProgress());
|
||||
}
|
||||
|
||||
if (GetPauseTime())
|
||||
{
|
||||
if (GetGoState() == GO_STATE_READY)
|
||||
{
|
||||
if (GetPathProgress() == 0) // waiting at it's destination for state change, do nothing
|
||||
return;
|
||||
|
||||
if (GetPathProgress() < GetPauseTime()) // GOState has changed before previous state was reached, move to new destination immediately
|
||||
SetPathProgress(0);
|
||||
else if (GetPathProgress() + diff < GetPeriod())
|
||||
SetPathProgress(GetPathProgress() + diff);
|
||||
else
|
||||
SetPathProgress(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetPathProgress() == GetPauseTime()) // waiting at it's destination for state change, do nothing
|
||||
return;
|
||||
|
||||
if (GetPathProgress() > GetPauseTime()) // GOState has changed before previous state was reached, move to new destination immediately
|
||||
SetPathProgress(GetPauseTime());
|
||||
else if (GetPathProgress() + diff < GetPauseTime())
|
||||
SetPathProgress(GetPathProgress() + diff);
|
||||
else
|
||||
SetPathProgress(GetPauseTime());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPathProgress(GetPathProgress() + diff);
|
||||
if (GetPathProgress() >= GetPeriod())
|
||||
SetPathProgress(GetPathProgress() % GetPeriod());
|
||||
}
|
||||
|
||||
RelocateToProgress(GetPathProgress());
|
||||
}
|
||||
|
||||
void StaticTransport::RelocateToProgress(uint32 progress)
|
||||
{
|
||||
TransportAnimationEntry const *curr = NULL, *next = NULL;
|
||||
float percPos;
|
||||
if (m_goValue.Transport.AnimationInfo->GetAnimNode(progress, curr, next, percPos))
|
||||
{
|
||||
// curr node offset
|
||||
G3D::Vector3 pos = G3D::Vector3(curr->X, curr->Y, curr->Z);
|
||||
|
||||
// move by percentage of segment already passed
|
||||
pos += G3D::Vector3(percPos * (next->X - curr->X), percPos * (next->Y - curr->Y), percPos * (next->Z - curr->Z));
|
||||
|
||||
// rotate path by PathRotation
|
||||
// pussywizard: PathRotation in db is only simple orientation rotation, so don't use sophisticated and not working code
|
||||
// reminder: WorldRotation only influences model rotation, not the path
|
||||
float sign = GetFloatValue(GAMEOBJECT_PARENTROTATION + 2) >= 0.0f ? 1.0f : -1.0f;
|
||||
float pathRotAngle = sign * 2.0f * acos(GetFloatValue(GAMEOBJECT_PARENTROTATION + 3));
|
||||
float cs = cos(pathRotAngle), sn = sin(pathRotAngle);
|
||||
float nx = pos.x * cs - pos.y * sn;
|
||||
float ny = pos.x * sn + pos.y * cs;
|
||||
pos.x = nx;
|
||||
pos.y = ny;
|
||||
|
||||
// add stationary position to the calculated offset
|
||||
pos += G3D::Vector3(GetStationaryX(), GetStationaryY(), GetStationaryZ());
|
||||
|
||||
// rotate by AnimRotation at current segment
|
||||
// pussywizard: AnimRotation in dbc is only simple orientation rotation, so don't use sophisticated and not working code
|
||||
G3D::Quat currRot, nextRot;
|
||||
float percRot;
|
||||
m_goValue.Transport.AnimationInfo->GetAnimRotation(progress, currRot, nextRot, percRot);
|
||||
float signCurr = currRot.z >= 0.0f ? 1.0f : -1.0f;
|
||||
float oriRotAngleCurr = signCurr * 2.0f * acos(currRot.w);
|
||||
float signNext = nextRot.z >= 0.0f ? 1.0f : -1.0f;
|
||||
float oriRotAngleNext = signNext * 2.0f * acos(nextRot.w);
|
||||
float oriRotAngle = oriRotAngleCurr + percRot * (oriRotAngleNext - oriRotAngleCurr);
|
||||
|
||||
// check if position is valid
|
||||
if (!Trinity::IsValidMapCoord(pos.x, pos.y, pos.z))
|
||||
return;
|
||||
|
||||
// update position to new one
|
||||
// also adding simplified orientation rotation here
|
||||
UpdatePosition(pos.x, pos.y, pos.z, NormalizeOrientation(GetStationaryO() + oriRotAngle));
|
||||
}
|
||||
}
|
||||
|
||||
void StaticTransport::UpdatePosition(float x, float y, float z, float o)
|
||||
{
|
||||
if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case
|
||||
GetMap()->LoadGrid(x, y);
|
||||
|
||||
GetMap()->GameObjectRelocation(this, x, y, z, o); // this also relocates the model
|
||||
UpdatePassengerPositions();
|
||||
}
|
||||
|
||||
void StaticTransport::UpdatePassengerPositions()
|
||||
{
|
||||
for (PassengerSet::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
|
||||
{
|
||||
WorldObject* passenger = *itr;
|
||||
|
||||
// if passenger is on vehicle we have to assume the vehicle is also on transport and its the vehicle that will be updating its passengers
|
||||
if (Unit* unit = passenger->ToUnit())
|
||||
if (unit->GetVehicle())
|
||||
continue;
|
||||
|
||||
// Do not use Unit::UpdatePosition here, we don't want to remove auras as if regular movement occurred
|
||||
float x, y, z, o;
|
||||
passenger->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
|
||||
CalculatePassengerPosition(x, y, z, &o);
|
||||
|
||||
// check if position is valid
|
||||
if (!Trinity::IsValidMapCoord(x, y, z))
|
||||
continue;
|
||||
|
||||
switch (passenger->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o);
|
||||
break;
|
||||
case TYPEID_PLAYER:
|
||||
if (passenger->IsInWorld())
|
||||
GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o);
|
||||
break;
|
||||
case TYPEID_GAMEOBJECT:
|
||||
GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o);
|
||||
break;
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StaticTransport::AddPassenger(WorldObject* passenger, bool withAll)
|
||||
{
|
||||
if (_passengers.insert(passenger).second)
|
||||
{
|
||||
if (Player* plr = passenger->ToPlayer())
|
||||
sScriptMgr->OnAddPassenger(ToTransport(), plr);
|
||||
|
||||
if (withAll)
|
||||
{
|
||||
if (Transport* t = passenger->GetTransport()) // SHOULD NEVER HAPPEN
|
||||
t->RemovePassenger(passenger, false);
|
||||
|
||||
float x, y, z, o;
|
||||
passenger->GetPosition(x, y, z, o);
|
||||
CalculatePassengerOffset(x, y, z, &o);
|
||||
|
||||
passenger->SetTransport(this);
|
||||
passenger->m_movementInfo.flags |= MOVEMENTFLAG_ONTRANSPORT;
|
||||
passenger->m_movementInfo.transport.guid = GetGUID();
|
||||
passenger->m_movementInfo.transport.pos.Relocate(x, y, z, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StaticTransport::RemovePassenger(WorldObject* passenger, bool withAll)
|
||||
{
|
||||
if (_passengers.erase(passenger))
|
||||
{
|
||||
if (Player* plr = passenger->ToPlayer())
|
||||
{
|
||||
sScriptMgr->OnRemovePassenger(ToTransport(), plr);
|
||||
plr->SetFallInformation(time(NULL), plr->GetPositionZ());
|
||||
}
|
||||
|
||||
if (withAll)
|
||||
{
|
||||
passenger->SetTransport(NULL);
|
||||
passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
|
||||
passenger->m_movementInfo.transport.guid = 0;
|
||||
passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRANSPORTS_H
|
||||
#define TRANSPORTS_H
|
||||
|
||||
#include "GameObject.h"
|
||||
#include "TransportMgr.h"
|
||||
#include "VehicleDefines.h"
|
||||
#include "ZoneScript.h"
|
||||
|
||||
struct CreatureData;
|
||||
|
||||
class Transport : public GameObject, public TransportBase
|
||||
{
|
||||
public:
|
||||
Transport() : GameObject() {}
|
||||
void CalculatePassengerPosition(float& x, float& y, float& z, float* o = NULL) const { TransportBase::CalculatePassengerPosition(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); }
|
||||
void CalculatePassengerOffset(float& x, float& y, float& z, float* o = NULL) const { TransportBase::CalculatePassengerOffset(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); }
|
||||
|
||||
typedef std::set<WorldObject*> PassengerSet;
|
||||
virtual void AddPassenger(WorldObject* passenger, bool withAll = false) = 0;
|
||||
virtual void RemovePassenger(WorldObject* passenger, bool withAll = false) = 0;
|
||||
PassengerSet const& GetPassengers() const { return _passengers; }
|
||||
|
||||
uint32 GetPathProgress() const { return GetGOValue()->Transport.PathProgress; }
|
||||
void SetPathProgress(uint32 val) { m_goValue.Transport.PathProgress = val; }
|
||||
|
||||
protected:
|
||||
PassengerSet _passengers;
|
||||
};
|
||||
|
||||
class MotionTransport : public Transport
|
||||
{
|
||||
friend MotionTransport* TransportMgr::CreateTransport(uint32, uint32, Map*);
|
||||
MotionTransport();
|
||||
public:
|
||||
~MotionTransport();
|
||||
|
||||
bool CreateMoTrans(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress);
|
||||
void CleanupsBeforeDelete(bool finalCleanup = true);
|
||||
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet&);
|
||||
|
||||
void Update(uint32 diff);
|
||||
void DelayedUpdate(uint32 diff);
|
||||
void UpdatePosition(float x, float y, float z, float o);
|
||||
|
||||
void AddPassenger(WorldObject* passenger, bool withAll = false);
|
||||
void RemovePassenger(WorldObject* passenger, bool withAll = false);
|
||||
Creature* CreateNPCPassenger(uint32 guid, CreatureData const* data);
|
||||
GameObject* CreateGOPassenger(uint32 guid, GameObjectData const* data);
|
||||
|
||||
void LoadStaticPassengers();
|
||||
PassengerSet const& GetStaticPassengers() const { return _staticPassengers; }
|
||||
void UnloadStaticPassengers();
|
||||
void UnloadNonStaticPassengers();
|
||||
void SetPassengersLoaded(bool loaded) { _passengersLoaded = loaded; }
|
||||
bool PassengersLoaded() const { return _passengersLoaded; }
|
||||
|
||||
KeyFrameVec const& GetKeyFrames() const { return _transportInfo->keyFrames; }
|
||||
void EnableMovement(bool enabled);
|
||||
TransportTemplate const* GetTransportTemplate() const { return _transportInfo; }
|
||||
|
||||
uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
|
||||
void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
|
||||
|
||||
private:
|
||||
void MoveToNextWaypoint();
|
||||
float CalculateSegmentPos(float perc);
|
||||
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
|
||||
void DelayedTeleportTransport();
|
||||
void UpdatePassengerPositions(PassengerSet& passengers);
|
||||
void DoEventIfAny(KeyFrame const& node, bool departure);
|
||||
|
||||
//! Helpers to know if stop frame was reached
|
||||
bool IsMoving() const { return _isMoving; }
|
||||
void SetMoving(bool val) { _isMoving = val; }
|
||||
|
||||
TransportTemplate const* _transportInfo;
|
||||
KeyFrameVec::const_iterator _currentFrame;
|
||||
KeyFrameVec::const_iterator _nextFrame;
|
||||
TimeTrackerSmall _positionChangeTimer;
|
||||
bool _isMoving;
|
||||
bool _pendingStop;
|
||||
|
||||
//! These are needed to properly control events triggering only once for each frame
|
||||
bool _triggeredArrivalEvent;
|
||||
bool _triggeredDepartureEvent;
|
||||
|
||||
PassengerSet _staticPassengers;
|
||||
mutable ACE_Thread_Mutex Lock;
|
||||
bool _passengersLoaded;
|
||||
bool _delayedTeleport;
|
||||
};
|
||||
|
||||
class StaticTransport : public Transport
|
||||
{
|
||||
public:
|
||||
StaticTransport();
|
||||
~StaticTransport();
|
||||
|
||||
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 CleanupsBeforeDelete(bool finalCleanup = true);
|
||||
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet&);
|
||||
|
||||
void Update(uint32 diff);
|
||||
void RelocateToProgress(uint32 progress);
|
||||
void UpdatePosition(float x, float y, float z, float o);
|
||||
void UpdatePassengerPositions();
|
||||
|
||||
void AddPassenger(WorldObject* passenger, bool withAll = false);
|
||||
void RemovePassenger(WorldObject* passenger, bool withAll = false);
|
||||
|
||||
uint32 GetPauseTime() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
|
||||
void SetPauseTime(uint32 val) { SetUInt32Value(GAMEOBJECT_LEVEL, val); }
|
||||
uint32 GetPeriod() const { return m_goValue.Transport.AnimationInfo ? m_goValue.Transport.AnimationInfo->TotalTime : GetPauseTime()+2; }
|
||||
private:
|
||||
bool _needDoInitialRelocation;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,603 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Unit.h"
|
||||
#include "Util.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "ZoneScript.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Player.h"
|
||||
#include "BattlefieldWG.h"
|
||||
|
||||
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
|
||||
_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i)
|
||||
{
|
||||
if (uint32 seatId = _vehicleInfo->m_seatID[i])
|
||||
if (VehicleSeatEntry const* veSeat = sVehicleSeatStore.LookupEntry(seatId))
|
||||
{
|
||||
Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
|
||||
if (veSeat->CanEnterOrExit())
|
||||
++_usableSeatNum;
|
||||
}
|
||||
}
|
||||
|
||||
// Ulduar demolisher
|
||||
if (vehInfo->m_ID == 338)
|
||||
++_usableSeatNum;
|
||||
|
||||
InitMovementInfoForBase();
|
||||
}
|
||||
|
||||
Vehicle::~Vehicle()
|
||||
{
|
||||
/// @Uninstall must be called before this.
|
||||
ASSERT(_status == STATUS_UNINSTALLING);
|
||||
|
||||
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
if (itr->second.Passenger.Guid)
|
||||
{
|
||||
if (Unit* unit = ObjectAccessor::FindUnit(itr->second.Passenger.Guid))
|
||||
{
|
||||
sLog->outString("ZOMG! ~Vehicle(), unit: %s, entry: %u, typeid: %u, this_entry: %u, this_typeid: %u!", unit->GetName().c_str(), unit->GetEntry(), unit->GetTypeId(), _me ? _me->GetEntry() : 0, _me ? _me->GetTypeId() : 0);
|
||||
unit->_ExitVehicle();
|
||||
}
|
||||
else
|
||||
sLog->outString("ZOMG! ~Vehicle(), unknown guid!");
|
||||
}
|
||||
//ASSERT(!itr->second.IsEmpty());
|
||||
}
|
||||
|
||||
void Vehicle::Install()
|
||||
{
|
||||
if (_me->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId))
|
||||
_me->setPowerType(Powers(powerDisplay->PowerType));
|
||||
else if (_me->getClass() == CLASS_ROGUE)
|
||||
_me->setPowerType(POWER_ENERGY);
|
||||
}
|
||||
|
||||
_status = STATUS_INSTALLED;
|
||||
if (GetBase()->GetTypeId() == TYPEID_UNIT)
|
||||
sScriptMgr->OnInstall(this);
|
||||
}
|
||||
|
||||
void Vehicle::InstallAllAccessories(bool evading)
|
||||
{
|
||||
if (GetBase()->GetTypeId() == TYPEID_PLAYER || !evading)
|
||||
RemoveAllPassengers(); // We might have aura's saved in the DB with now invalid casters - remove
|
||||
|
||||
VehicleAccessoryList const* accessories = sObjectMgr->GetVehicleAccessoryList(this);
|
||||
if (!accessories)
|
||||
return;
|
||||
|
||||
for (VehicleAccessoryList::const_iterator itr = accessories->begin(); itr != accessories->end(); ++itr)
|
||||
if (!evading || itr->IsMinion) // only install minions on evade mode
|
||||
InstallAccessory(itr->AccessoryEntry, itr->SeatId, itr->IsMinion, itr->SummonedType, itr->SummonTime);
|
||||
}
|
||||
|
||||
void Vehicle::Uninstall()
|
||||
{
|
||||
/// @Prevent recursive uninstall call. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
|
||||
if (_status == STATUS_UNINSTALLING)
|
||||
{
|
||||
sLog->outError("Vehicle GuidLow: %u, Entry: %u attempts to uninstall, but already has STATUS_UNINSTALLING! "
|
||||
"Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry());
|
||||
return;
|
||||
}
|
||||
_status = STATUS_UNINSTALLING;
|
||||
;//sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Uninstall Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
|
||||
RemoveAllPassengers();
|
||||
|
||||
if (GetBase()->GetTypeId() == TYPEID_UNIT)
|
||||
sScriptMgr->OnUninstall(this);
|
||||
}
|
||||
|
||||
void Vehicle::Reset(bool evading /*= false*/)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
|
||||
if (_me->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (_usableSeatNum)
|
||||
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyAllImmunities();
|
||||
InstallAllAccessories(evading);
|
||||
if (_usableSeatNum)
|
||||
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
|
||||
}
|
||||
|
||||
if (GetBase()->GetTypeId() == TYPEID_UNIT)
|
||||
sScriptMgr->OnReset(this);
|
||||
}
|
||||
|
||||
void Vehicle::ApplyAllImmunities()
|
||||
{
|
||||
// This couldn't be done in DB, because some spells have MECHANIC_NONE
|
||||
|
||||
// Vehicles should be immune on Knockback ...
|
||||
//_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
|
||||
//_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true);
|
||||
|
||||
// Mechanical units & vehicles ( which are not Bosses, they have own immunities in DB ) should be also immune on healing ( exceptions in switch below )
|
||||
if (_me->ToCreature() && _me->ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && !_me->ToCreature()->isWorldBoss())
|
||||
{
|
||||
// Heal & dispel ...
|
||||
_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_MAX_HEALTH, true); // Xinef
|
||||
_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true);
|
||||
|
||||
// ... Shield & Immunity grant spells ...
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_IMMUNITY, true);
|
||||
//_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_UNATTACKABLE, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_IMMUNE_SHIELD, true);
|
||||
if (_me->GetZoneId() == BATTLEFIELD_WG_ZONEID || _me->ToCreature()->GetDBTableGUIDLow() || (_me->FindMap() && _me->FindMap()->Instanceable()))
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, true);
|
||||
|
||||
// ... Resistance, Split damage, Change stats ...
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_DAMAGE_SHIELD, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SPLIT_DAMAGE_PCT, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_RESISTANCE, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true);
|
||||
|
||||
// Taunt
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
|
||||
}
|
||||
|
||||
// Different immunities for vehicles goes below
|
||||
switch (GetVehicleInfo()->m_ID)
|
||||
{
|
||||
case 160: //Isle of conquest turret
|
||||
case 244: //Wintergrasp turret
|
||||
case 510: // Isle of Conquest
|
||||
case 452: // Isle of Conquest
|
||||
case 543: // Isle of Conquest
|
||||
//_me->SetControlled(true, UNIT_STATE_ROOT);
|
||||
//me->AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
|
||||
//me->SetSpeed(MOVE_TURN_RATE, 0.7f);
|
||||
//me->SetSpeed(MOVE_PITCH_RATE, 0.7f);
|
||||
//me->m_movementInfo.flags2=59;
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true);
|
||||
break;
|
||||
// Ulduar vehicles, remove immunities used in flame leviathan spells
|
||||
case 335:
|
||||
case 336:
|
||||
case 338:
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, false);
|
||||
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::RemoveAllPassengers()
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::RemoveAllPassengers. Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
|
||||
|
||||
// Passengers always cast an aura with SPELL_AURA_CONTROL_VEHICLE on the vehicle
|
||||
// We just remove the aura and the unapply handler will make the target leave the vehicle.
|
||||
// We don't need to iterate over Seats
|
||||
_me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE);
|
||||
|
||||
// Following the above logic, this assertion should NEVER fail.
|
||||
// Even in 'hacky' cases, there should at least be VEHICLE_SPELL_RIDE_HARDCODED on us.
|
||||
// SeatMap::const_iterator itr;
|
||||
// for (itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
// ASSERT(!itr->second.passenger.Guid);
|
||||
}
|
||||
|
||||
bool Vehicle::HasEmptySeat(int8 seatId) const
|
||||
{
|
||||
SeatMap::const_iterator seat = Seats.find(seatId);
|
||||
if (seat == Seats.end())
|
||||
return false;
|
||||
return seat->second.IsEmpty();
|
||||
}
|
||||
|
||||
Unit* Vehicle::GetPassenger(int8 seatId) const
|
||||
{
|
||||
SeatMap::const_iterator seat = Seats.find(seatId);
|
||||
if (seat == Seats.end())
|
||||
return NULL;
|
||||
|
||||
return ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger.Guid);
|
||||
}
|
||||
|
||||
int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
|
||||
{
|
||||
SeatMap::const_iterator seat = Seats.find(seatId);
|
||||
if (seat == Seats.end())
|
||||
return -1;
|
||||
|
||||
while (!seat->second.IsEmpty() || (!seat->second.SeatInfo->CanEnterOrExit() && !seat->second.SeatInfo->IsUsableByOverride()))
|
||||
{
|
||||
if (next)
|
||||
{
|
||||
++seat;
|
||||
if (seat == Seats.end())
|
||||
seat = Seats.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (seat == Seats.begin())
|
||||
seat = Seats.end();
|
||||
--seat;
|
||||
}
|
||||
|
||||
if (seat->first == seatId)
|
||||
return -1; // no available seat
|
||||
}
|
||||
|
||||
return seat->first;
|
||||
}
|
||||
|
||||
void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime)
|
||||
{
|
||||
/// @Prevent adding accessories when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
|
||||
if (_status == STATUS_UNINSTALLING)
|
||||
{
|
||||
sLog->outError("Vehicle GuidLow: %u, Entry: %u attempts to install accessory Entry: %u on seat %d with STATUS_UNINSTALLING! "
|
||||
"Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry(), entry, (int32)seatId);
|
||||
return;
|
||||
}
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle: Installing accessory entry %u on vehicle entry %u (seat:%i)", entry, GetCreatureEntry(), seatId);
|
||||
if (Unit* passenger = GetPassenger(seatId))
|
||||
{
|
||||
// already installed
|
||||
if (passenger->GetEntry() == entry)
|
||||
{
|
||||
ASSERT(passenger->GetTypeId() == TYPEID_UNIT);
|
||||
if (_me->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (_me->ToCreature()->IsInEvadeMode() && passenger->ToCreature()->IsAIEnabled)
|
||||
passenger->ToCreature()->AI()->EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
passenger->ExitVehicle(); // this should not happen
|
||||
}
|
||||
|
||||
if (TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime))
|
||||
{
|
||||
if (minion)
|
||||
accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
|
||||
|
||||
if (!_me->HandleSpellClick(accessory, seatId))
|
||||
{
|
||||
accessory->UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetBase()->GetTypeId() == TYPEID_UNIT)
|
||||
sScriptMgr->OnInstallAccessory(this, accessory);
|
||||
}
|
||||
}
|
||||
|
||||
bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
|
||||
{
|
||||
/// @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
|
||||
if (_status == STATUS_UNINSTALLING)
|
||||
{
|
||||
;//sLog->outError(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, attempting to board vehicle GuidLow: %u, Entry: %u during uninstall! SeatId: %i",
|
||||
// unit->GetGUIDLow(), unit->GetEntry(), _me->GetGUIDLow(), _me->GetEntry(), (int32)seatId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unit->GetVehicle() != this)
|
||||
return false;
|
||||
|
||||
SeatMap::iterator seat;
|
||||
if (seatId < 0) // no specific seat requirement
|
||||
{
|
||||
for (seat = Seats.begin(); seat != Seats.end(); ++seat)
|
||||
if (seat->second.IsEmpty() && (seat->second.SeatInfo->CanEnterOrExit() || seat->second.SeatInfo->IsUsableByOverride()))
|
||||
break;
|
||||
|
||||
if (seat == Seats.end()) // no available seat
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
seat = Seats.find(seatId);
|
||||
if (seat == Seats.end())
|
||||
return false;
|
||||
|
||||
if (!seat->second.IsEmpty())
|
||||
{
|
||||
if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger.Guid))
|
||||
passenger->ExitVehicle();
|
||||
|
||||
seat->second.Passenger.Guid = 0;
|
||||
}
|
||||
|
||||
ASSERT(seat->second.IsEmpty());
|
||||
}
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
|
||||
|
||||
seat->second.Passenger.Guid = unit->GetGUID();
|
||||
seat->second.Passenger.IsUnselectable = unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
if (seat->second.SeatInfo->CanEnterOrExit())
|
||||
{
|
||||
ASSERT(_usableSeatNum);
|
||||
--_usableSeatNum;
|
||||
if (!_usableSeatNum)
|
||||
{
|
||||
if (_me->GetTypeId() == TYPEID_PLAYER)
|
||||
_me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
|
||||
else
|
||||
_me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_me->IsInWorld() || _me->IsDuringRemoveFromWorld())
|
||||
return false;
|
||||
|
||||
// Xinef: moved from unit.cpp, if aura passes seatId == -1 (choose automaticly) we wont get appropriate flags
|
||||
if (unit->GetTypeId() == TYPEID_PLAYER && !(seat->second.SeatInfo->m_flagsB & VEHICLE_SEAT_FLAG_B_KEEP_PET))
|
||||
unit->ToPlayer()->UnsummonPetTemporaryIfAny();
|
||||
|
||||
if (seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE)
|
||||
unit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
VehicleSeatEntry const* veSeat = seat->second.SeatInfo;
|
||||
unit->m_movementInfo.transport.pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
|
||||
unit->m_movementInfo.transport.time = 0;
|
||||
unit->m_movementInfo.transport.seat = seat->first;
|
||||
unit->m_movementInfo.transport.guid = _me->GetGUID();
|
||||
|
||||
// xinef: removed retarded seat->first == 0 check...
|
||||
if (_me->GetTypeId() == TYPEID_UNIT
|
||||
&& unit->GetTypeId() == TYPEID_PLAYER
|
||||
&& seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
|
||||
ASSERT(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
sLog->outString("ZOMG! CRASH! Try-catch in Unit::SetCharmedBy()!");
|
||||
sLog->outString("ZOMG! CRASH! Try-catch in Unit::SetCharmedBy(). not null: %u, this not null: %u", _me ? 1 : 0, this ? 1 : 0);
|
||||
if (!_me || !this)
|
||||
return false;
|
||||
sLog->outString("ZOMG! CRASH! Try-catch in Unit::SetCharmedBy(). Is: %u!", _me->IsInWorld());
|
||||
sLog->outString("ZOMG! CRASH! Try-catch in Unit::SetCharmedBy(). Is2: %u!", _me->IsDuringRemoveFromWorld());
|
||||
sLog->outString("ZOMG! CRASH! Try-catch in Unit::SetCharmedBy(). Unit %s!", _me->GetName().c_str());
|
||||
sLog->outString("ZOMG! CRASH! Try-catch in Unit::SetCharmedBy(). typeid: %u!", _me->GetTypeId());
|
||||
sLog->outString("ZOMG! CRASH! Try-catch in Unit::SetCharmedBy(). Unit %s, typeid: %u, in world: %u, duringremove: %u has wrong CharmType! Charmer %s, typeid: %u, in world: %u, duringremove: %u.", _me->GetName().c_str(), _me->GetTypeId(), _me->IsInWorld(), _me->IsDuringRemoveFromWorld(), unit->GetName().c_str(), unit->GetTypeId(), unit->IsInWorld(), unit->IsDuringRemoveFromWorld());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_me->IsInWorld())
|
||||
{
|
||||
unit->SendClearTarget(); // SMSG_BREAK_TARGET
|
||||
unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
|
||||
// also adds MOVEMENTFLAG_ROOT
|
||||
Movement::MoveSplineInit init(unit);
|
||||
init.DisableTransportPathTransformations();
|
||||
init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
|
||||
// Xinef: did not found anything unique in dbc, maybe missed something
|
||||
if (veSeat->m_ID == 3566 || veSeat->m_ID == 3567 || veSeat->m_ID == 3568 || veSeat->m_ID == 3570)
|
||||
{
|
||||
float x = veSeat->m_attachmentOffsetX, y = veSeat->m_attachmentOffsetY, z = veSeat->m_attachmentOffsetZ, o;
|
||||
CalculatePassengerPosition(x, y, z, &o);
|
||||
init.SetFacing(_me->GetAngle(x, y));
|
||||
}
|
||||
else
|
||||
init.SetFacing(0.0f);
|
||||
|
||||
init.SetTransportEnter();
|
||||
init.Launch();
|
||||
|
||||
if (_me->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (_me->ToCreature()->IsAIEnabled)
|
||||
_me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetBase()->GetTypeId() == TYPEID_UNIT)
|
||||
sScriptMgr->OnAddPassenger(this, unit, seatId);
|
||||
|
||||
// Remove parachute on vehicle switch
|
||||
unit->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Vehicle::RemovePassenger(Unit* unit)
|
||||
{
|
||||
if (unit->GetVehicle() != this)
|
||||
return;
|
||||
|
||||
SeatMap::iterator seat = GetSeatIteratorForPassenger(unit);
|
||||
// it can happen that unit enters vehicle and removes owner passenger
|
||||
// then vehicles is dissmised and removes all existing passengers, even the unit (vehicle has aura of unit)
|
||||
// but the unit is not on the vehicles seat yet, thus crashing at ASSERT(seat != Seats.end());
|
||||
// ASSERT(seat != Seats.end());
|
||||
if (seat == Seats.end())
|
||||
return;
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s exit vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
|
||||
|
||||
if (seat->second.SeatInfo->CanEnterOrExit() && ++_usableSeatNum)
|
||||
_me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
|
||||
|
||||
// Remove UNIT_FLAG_NOT_SELECTABLE if passenger did not have it before entering vehicle
|
||||
if (seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE && !seat->second.Passenger.IsUnselectable)
|
||||
unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
seat->second.Passenger.Reset();
|
||||
|
||||
if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER && seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
|
||||
_me->RemoveCharmedBy(unit);
|
||||
|
||||
if (_me->IsInWorld())
|
||||
{
|
||||
if (!_me->GetTransport())
|
||||
{
|
||||
unit->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
unit->m_movementInfo.transport.Reset();
|
||||
}
|
||||
else
|
||||
unit->m_movementInfo.transport = _me->m_movementInfo.transport;
|
||||
}
|
||||
|
||||
// only for flyable vehicles
|
||||
if (_me->IsFlying() && !_me->GetInstanceId() && unit->GetTypeId() == TYPEID_PLAYER && !(unit->ToPlayer()->GetDelayedOperations() & DELAYED_VEHICLE_TELEPORT) && _me->GetEntry() != 30275 /*NPC_WILD_WYRM*/)
|
||||
_me->CastSpell(unit, VEHICLE_SPELL_PARACHUTE, true);
|
||||
|
||||
if (_me->GetTypeId() == TYPEID_UNIT && _me->ToCreature()->IsAIEnabled)
|
||||
_me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, false);
|
||||
|
||||
if (GetBase()->GetTypeId() == TYPEID_UNIT)
|
||||
sScriptMgr->OnRemovePassenger(this, unit);
|
||||
}
|
||||
|
||||
void Vehicle::RelocatePassengers()
|
||||
{
|
||||
ASSERT(_me->GetMap());
|
||||
|
||||
// not sure that absolute position calculation is correct, it must depend on vehicle pitch angle
|
||||
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
{
|
||||
if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), itr->second.Passenger.Guid))
|
||||
{
|
||||
ASSERT(passenger->IsInWorld());
|
||||
|
||||
float px, py, pz, po;
|
||||
passenger->m_movementInfo.transport.pos.GetPosition(px, py, pz, po);
|
||||
CalculatePassengerPosition(px, py, pz, &po);
|
||||
passenger->UpdatePosition(px, py, pz, po);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::Dismiss()
|
||||
{
|
||||
if (GetBase()->GetTypeId() != TYPEID_UNIT)
|
||||
return;
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Dismiss Entry: %u, GuidLow %u", _creatureEntry, _me->GetGUIDLow());
|
||||
Uninstall();
|
||||
GetBase()->ToCreature()->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
bool Vehicle::IsVehicleInUse()
|
||||
{
|
||||
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), itr->second.Passenger.Guid))
|
||||
{
|
||||
if (passenger->GetTypeId() == TYPEID_PLAYER)
|
||||
return true;
|
||||
else if (passenger->GetTypeId() == TYPEID_UNIT && passenger->GetVehicleKit() && passenger->GetVehicleKit()->IsVehicleInUse())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Vehicle::TeleportVehicle(float x, float y, float z, float ang)
|
||||
{
|
||||
_me->GetMap()->LoadGrid(x, y);
|
||||
_me->NearTeleportTo(x, y, z, ang, true);
|
||||
|
||||
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), itr->second.Passenger.Guid))
|
||||
{
|
||||
if (passenger->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
passenger->ToPlayer()->SetMover(passenger);
|
||||
passenger->NearTeleportTo(x, y, z, ang, false, true);
|
||||
passenger->ToPlayer()->ScheduleDelayedOperation(DELAYED_VEHICLE_TELEPORT);
|
||||
}
|
||||
else if (passenger->GetTypeId() == TYPEID_UNIT && passenger->GetVehicleKit())
|
||||
passenger->GetVehicleKit()->TeleportVehicle(x, y, z, ang);
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::InitMovementInfoForBase()
|
||||
{
|
||||
uint32 vehicleFlags = GetVehicleInfo()->m_flags;
|
||||
|
||||
if (vehicleFlags & VEHICLE_FLAG_NO_STRAFE)
|
||||
_me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_NO_STRAFE);
|
||||
if (vehicleFlags & VEHICLE_FLAG_NO_JUMPING)
|
||||
_me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_NO_JUMPING);
|
||||
if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDTURNING)
|
||||
_me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_TURNING);
|
||||
if (vehicleFlags & VEHICLE_FLAG_ALLOW_PITCHING)
|
||||
_me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING);
|
||||
if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDPITCHING)
|
||||
_me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_PITCHING);
|
||||
}
|
||||
|
||||
VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit const* passenger)
|
||||
{
|
||||
SeatMap::iterator itr;
|
||||
for (itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
if (itr->second.Passenger.Guid == passenger->GetGUID())
|
||||
return itr->second.SeatInfo;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger)
|
||||
{
|
||||
SeatMap::iterator itr;
|
||||
for (itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
if (itr->second.Passenger.Guid == passenger->GetGUID())
|
||||
return itr;
|
||||
|
||||
return Seats.end();
|
||||
}
|
||||
|
||||
uint8 Vehicle::GetAvailableSeatCount() const
|
||||
{
|
||||
uint8 ret = 0;
|
||||
SeatMap::const_iterator itr;
|
||||
for (itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
if (itr->second.IsEmpty() && (itr->second.SeatInfo->CanEnterOrExit() || itr->second.SeatInfo->IsUsableByOverride()))
|
||||
++ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TRINITY_VEHICLE_H
|
||||
#define __TRINITY_VEHICLE_H
|
||||
|
||||
#include "ObjectDefines.h"
|
||||
#include "VehicleDefines.h"
|
||||
#include "EventProcessor.h"
|
||||
#include "Unit.h"
|
||||
|
||||
struct VehicleEntry;
|
||||
class Unit;
|
||||
|
||||
class Vehicle : public TransportBase
|
||||
{
|
||||
public:
|
||||
void Install();
|
||||
void Uninstall();
|
||||
void Reset(bool evading = false);
|
||||
void InstallAllAccessories(bool evading);
|
||||
void ApplyAllImmunities();
|
||||
void InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime); //! May be called from scripts
|
||||
|
||||
Unit* GetBase() const { return _me; }
|
||||
VehicleEntry const* GetVehicleInfo() const { return _vehicleInfo; }
|
||||
uint32 GetCreatureEntry() const { return _creatureEntry; }
|
||||
|
||||
bool HasEmptySeat(int8 seatId) const;
|
||||
Unit* GetPassenger(int8 seatId) const;
|
||||
int8 GetNextEmptySeat(int8 seatId, bool next) const;
|
||||
uint8 GetAvailableSeatCount() const;
|
||||
|
||||
bool AddPassenger(Unit* passenger, int8 seatId = -1);
|
||||
void EjectPassenger(Unit* passenger, Unit* controller);
|
||||
void RemovePassenger(Unit* passenger);
|
||||
void RelocatePassengers();
|
||||
void RemoveAllPassengers();
|
||||
void Dismiss();
|
||||
bool IsVehicleInUse();
|
||||
void TeleportVehicle(float x, float y, float z, float ang);
|
||||
|
||||
SeatMap Seats;
|
||||
|
||||
VehicleSeatEntry const* GetSeatForPassenger(Unit const* passenger);
|
||||
SeatMap::iterator GetSeatIteratorForPassenger(Unit* passenger);
|
||||
|
||||
protected:
|
||||
friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry);
|
||||
Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry);
|
||||
friend void Unit::RemoveVehicleKit();
|
||||
~Vehicle();
|
||||
|
||||
private:
|
||||
enum Status
|
||||
{
|
||||
STATUS_NONE,
|
||||
STATUS_INSTALLED,
|
||||
STATUS_UNINSTALLING,
|
||||
};
|
||||
|
||||
void InitMovementInfoForBase();
|
||||
|
||||
/// This method transforms supplied transport offsets into global coordinates
|
||||
void CalculatePassengerPosition(float& x, float& y, float& z, float* o /*= NULL*/) const
|
||||
{
|
||||
TransportBase::CalculatePassengerPosition(x, y, z, o,
|
||||
GetBase()->GetPositionX(), GetBase()->GetPositionY(),
|
||||
GetBase()->GetPositionZ(), GetBase()->GetOrientation());
|
||||
}
|
||||
|
||||
/// This method transforms supplied global coordinates into local offsets
|
||||
void CalculatePassengerOffset(float& x, float& y, float& z, float* o /*= NULL*/) const
|
||||
{
|
||||
TransportBase::CalculatePassengerOffset(x, y, z, o,
|
||||
GetBase()->GetPositionX(), GetBase()->GetPositionY(),
|
||||
GetBase()->GetPositionZ(), GetBase()->GetOrientation());
|
||||
}
|
||||
|
||||
Unit* _me;
|
||||
VehicleEntry const* _vehicleInfo;
|
||||
uint32 _usableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
|
||||
uint32 _creatureEntry; // Can be different than me->GetBase()->GetEntry() in case of players
|
||||
Status _status;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TRINITY_VEHICLEDEFINES_H
|
||||
#define __TRINITY_VEHICLEDEFINES_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
struct VehicleSeatEntry;
|
||||
|
||||
enum PowerType
|
||||
{
|
||||
POWER_STEAM = 61,
|
||||
POWER_PYRITE = 41,
|
||||
POWER_HEAT = 101,
|
||||
POWER_OOZE = 121,
|
||||
POWER_BLOOD = 141,
|
||||
POWER_WRATH = 142
|
||||
};
|
||||
|
||||
enum VehicleFlags
|
||||
{
|
||||
VEHICLE_FLAG_NO_STRAFE = 0x00000001, // Sets MOVEFLAG2_NO_STRAFE
|
||||
VEHICLE_FLAG_NO_JUMPING = 0x00000002, // Sets MOVEFLAG2_NO_JUMPING
|
||||
VEHICLE_FLAG_FULLSPEEDTURNING = 0x00000004, // Sets MOVEFLAG2_FULLSPEEDTURNING
|
||||
VEHICLE_FLAG_ALLOW_PITCHING = 0x00000010, // Sets MOVEFLAG2_ALLOW_PITCHING
|
||||
VEHICLE_FLAG_FULLSPEEDPITCHING = 0x00000020, // Sets MOVEFLAG2_FULLSPEEDPITCHING
|
||||
VEHICLE_FLAG_CUSTOM_PITCH = 0x00000040, // If set use pitchMin and pitchMax from DBC, otherwise pitchMin = -pi/2, pitchMax = pi/2
|
||||
VEHICLE_FLAG_ADJUST_AIM_ANGLE = 0x00000400, // Lua_IsVehicleAimAngleAdjustable
|
||||
VEHICLE_FLAG_ADJUST_AIM_POWER = 0x00000800, // Lua_IsVehicleAimPowerAdjustable
|
||||
};
|
||||
|
||||
enum VehicleSpells
|
||||
{
|
||||
VEHICLE_SPELL_RIDE_HARDCODED = 46598,
|
||||
VEHICLE_SPELL_PARACHUTE = 45472,
|
||||
|
||||
VEHICLE_SPELL_GEIST_CONTROL_END = 58119,
|
||||
VEHICLE_SPELL_SHADE_CONTROL_END = 58664
|
||||
};
|
||||
|
||||
enum VehicleNPCs
|
||||
{
|
||||
NPC_EIDOLON_WATCHER = 31110,
|
||||
NPC_LITHE_STALKER = 30895
|
||||
};
|
||||
|
||||
struct PassengerInfo
|
||||
{
|
||||
uint64 Guid;
|
||||
bool IsUnselectable;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Guid = 0;
|
||||
IsUnselectable = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct VehicleSeat
|
||||
{
|
||||
explicit VehicleSeat(VehicleSeatEntry const* seatInfo) : SeatInfo(seatInfo)
|
||||
{
|
||||
Passenger.Reset();
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return !Passenger.Guid; }
|
||||
|
||||
VehicleSeatEntry const* SeatInfo;
|
||||
PassengerInfo Passenger;
|
||||
};
|
||||
|
||||
struct VehicleAccessory
|
||||
{
|
||||
VehicleAccessory(uint32 entry, int8 seatId, bool isMinion, uint8 summonType, uint32 summonTime) :
|
||||
AccessoryEntry(entry), IsMinion(isMinion), SummonTime(summonTime), SeatId(seatId), SummonedType(summonType) {}
|
||||
uint32 AccessoryEntry;
|
||||
uint32 IsMinion;
|
||||
uint32 SummonTime;
|
||||
int8 SeatId;
|
||||
uint8 SummonedType;
|
||||
};
|
||||
|
||||
typedef std::vector<VehicleAccessory> VehicleAccessoryList;
|
||||
typedef std::map<uint32, VehicleAccessoryList> VehicleAccessoryContainer;
|
||||
typedef std::map<int8, VehicleSeat> SeatMap;
|
||||
|
||||
class TransportBase
|
||||
{
|
||||
protected:
|
||||
TransportBase() { }
|
||||
virtual ~TransportBase() { }
|
||||
|
||||
public:
|
||||
/// This method transforms supplied transport offsets into global coordinates
|
||||
virtual void CalculatePassengerPosition(float& x, float& y, float& z, float* o = NULL) const = 0;
|
||||
|
||||
/// This method transforms supplied global coordinates into local offsets
|
||||
virtual void CalculatePassengerOffset(float& x, float& y, float& z, float* o = NULL) const = 0;
|
||||
|
||||
protected:
|
||||
static void CalculatePassengerPosition(float& x, float& y, float& z, float* o, float transX, float transY, float transZ, float transO)
|
||||
{
|
||||
float inx = x, iny = y, inz = z;
|
||||
if (o)
|
||||
*o = Position::NormalizeOrientation(transO + *o);
|
||||
|
||||
x = transX + inx * std::cos(transO) - iny * std::sin(transO);
|
||||
y = transY + iny * std::cos(transO) + inx * std::sin(transO);
|
||||
z = transZ + inz;
|
||||
}
|
||||
|
||||
static void CalculatePassengerOffset(float& x, float& y, float& z, float* o, float transX, float transY, float transZ, float transO)
|
||||
{
|
||||
if (o)
|
||||
*o = Position::NormalizeOrientation(*o - transO);
|
||||
|
||||
z -= transZ;
|
||||
y -= transY; // y = searchedY * std::cos(o) + searchedX * std::sin(o)
|
||||
x -= transX; // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
|
||||
float inx = x, iny = y;
|
||||
y = (iny - inx * std::tan(transO)) / (std::cos(transO) + std::sin(transO) * std::tan(transO));
|
||||
x = (inx + iny * std::tan(transO)) / (std::cos(transO) + std::sin(transO) * std::tan(transO));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user