rearranged core files
--HG-- branch : trunk
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_CREATURE_H
|
||||
#define TRINITYCORE_CREATURE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Unit.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "ItemPrototype.h"
|
||||
#include "LootMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Cell.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
struct SpellEntry;
|
||||
|
||||
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_CHARM_AI = 0x00008000, // use ai when charmed
|
||||
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
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
#define MAX_KILL_CREDIT 2
|
||||
#define CREATURE_REGEN_INTERVAL 2 * IN_MILISECONDS
|
||||
|
||||
// from `creature_template` table
|
||||
struct CreatureInfo
|
||||
{
|
||||
uint32 Entry;
|
||||
uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
|
||||
uint32 KillCredit[MAX_KILL_CREDIT];
|
||||
uint32 Modelid1;
|
||||
uint32 Modelid2;
|
||||
uint32 Modelid3;
|
||||
uint32 Modelid4;
|
||||
char* Name;
|
||||
char* SubName;
|
||||
char* IconName;
|
||||
uint32 GossipMenuId;
|
||||
uint8 minlevel;
|
||||
uint8 maxlevel;
|
||||
uint32 expansion;
|
||||
uint32 faction_A;
|
||||
uint32 faction_H;
|
||||
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 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 resistance1;
|
||||
int32 resistance2;
|
||||
int32 resistance3;
|
||||
int32 resistance4;
|
||||
int32 resistance5;
|
||||
int32 resistance6;
|
||||
uint32 spells[CREATURE_MAX_SPELLS];
|
||||
uint32 PetSpellDataId;
|
||||
uint32 VehicleId;
|
||||
uint32 mingold;
|
||||
uint32 maxgold;
|
||||
char const* AIName;
|
||||
uint32 MovementType;
|
||||
uint32 InhabitType;
|
||||
float ModHealth;
|
||||
float ModMana;
|
||||
float ModArmor;
|
||||
bool RacialLeader;
|
||||
uint32 questItems[6];
|
||||
uint32 movementId;
|
||||
bool RegenHealth;
|
||||
uint32 equipmentId;
|
||||
uint32 MechanicImmuneMask;
|
||||
uint32 flags_extra;
|
||||
uint32 ScriptID;
|
||||
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_ENGINERING;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
// Represents max amount of expansions.
|
||||
// TODO: Add MAX_EXPANSION constant.
|
||||
#define MAX_CREATURE_BASE_HP 3
|
||||
|
||||
// Defines base stats for creatures (used to calculate HP/mana/armor).
|
||||
struct CreatureBaseStats
|
||||
{
|
||||
uint32 BaseHealth[MAX_CREATURE_BASE_HP];
|
||||
uint32 BaseMana;
|
||||
uint32 BaseArmor;
|
||||
|
||||
// Helpers
|
||||
|
||||
uint32 GenerateHealth(CreatureInfo const* info) const
|
||||
{
|
||||
return uint32((BaseHealth[info->expansion] * info->ModHealth) + 0.5f);
|
||||
}
|
||||
|
||||
uint32 GenerateMana(CreatureInfo const* info) const
|
||||
{
|
||||
// Mana can be 0.
|
||||
if (!BaseMana)
|
||||
return 0;
|
||||
|
||||
return uint32((BaseMana * info->ModMana) + 0.5f);
|
||||
}
|
||||
|
||||
uint32 GenerateArmor(CreatureInfo const* info) const
|
||||
{
|
||||
return uint32((BaseArmor * info->ModArmor) + 0.5f);
|
||||
}
|
||||
|
||||
static CreatureBaseStats const* GetBaseStats(uint8 level, uint8 unitClass);
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint16, CreatureBaseStats> CreatureBaseStatsMap;
|
||||
|
||||
struct CreatureLocale
|
||||
{
|
||||
std::vector<std::string> Name;
|
||||
std::vector<std::string> SubName;
|
||||
};
|
||||
|
||||
struct GossipMenuItemsLocale
|
||||
{
|
||||
std::vector<std::string> OptionText;
|
||||
std::vector<std::string> BoxText;
|
||||
};
|
||||
|
||||
struct PointOfInterestLocale
|
||||
{
|
||||
std::vector<std::string> IconName;
|
||||
};
|
||||
|
||||
struct EquipmentInfo
|
||||
{
|
||||
uint32 entry;
|
||||
uint32 equipentry[3];
|
||||
};
|
||||
|
||||
// from `creature` table
|
||||
struct CreatureData
|
||||
{
|
||||
explicit CreatureData() : dbData(true) {}
|
||||
uint32 id; // entry in creature_template
|
||||
uint16 mapid;
|
||||
uint16 phaseMask;
|
||||
uint32 displayid;
|
||||
int32 equipmentId;
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float orientation;
|
||||
uint32 spawntimesecs;
|
||||
float spawndist;
|
||||
uint32 currentwaypoint;
|
||||
uint32 curhealth;
|
||||
uint32 curmana;
|
||||
bool is_dead;
|
||||
uint8 movementType;
|
||||
uint8 spawnMask;
|
||||
bool dbData;
|
||||
};
|
||||
|
||||
struct CreatureDataAddonAura
|
||||
{
|
||||
uint32 spell_id;
|
||||
uint8 effectMask;
|
||||
};
|
||||
|
||||
// from `creature_addon` table
|
||||
struct CreatureDataAddon
|
||||
{
|
||||
uint32 guidOrEntry;
|
||||
uint32 path_id;
|
||||
uint32 mount;
|
||||
uint32 bytes1;
|
||||
uint32 bytes2;
|
||||
uint32 emote;
|
||||
CreatureDataAddonAura const* auras; // loaded as char* "spell1 eff1 spell2 eff2 ... "
|
||||
};
|
||||
|
||||
struct CreatureModelInfo
|
||||
{
|
||||
uint32 modelid;
|
||||
float bounding_radius;
|
||||
float combat_reach;
|
||||
uint8 gender;
|
||||
uint32 modelid_other_gender;
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
// Vendors
|
||||
struct VendorItem
|
||||
{
|
||||
VendorItem(uint32 _item, int32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost)
|
||||
: item(_item), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost) {}
|
||||
|
||||
uint32 item;
|
||||
int32 maxcount; // 0 for infinity item amount
|
||||
uint32 incrtime; // time for restore items amount if maxcount != 0
|
||||
uint32 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) {}
|
||||
|
||||
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;
|
||||
void Clear() { spellList.clear(); }
|
||||
};
|
||||
|
||||
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:
|
||||
|
||||
explicit Creature();
|
||||
virtual ~Creature();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
void DisappearAndDie();
|
||||
|
||||
bool Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehId, uint32 team, float x, float y, float z, float ang, const CreatureData *data = NULL);
|
||||
bool LoadCreaturesAddon(bool reload = false);
|
||||
void SelectLevel(const CreatureInfo *cinfo);
|
||||
void LoadEquipment(uint32 equip_entry, bool force=false);
|
||||
|
||||
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
|
||||
char const* GetSubName() const { return GetCreatureInfo()->SubName; }
|
||||
|
||||
void Update(uint32 time); // overwrited Unit::Update
|
||||
void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
|
||||
uint32 GetEquipmentId() const { return GetCreatureInfo()->equipmentId; }
|
||||
|
||||
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
|
||||
bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
|
||||
bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
|
||||
bool isTrigger() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
|
||||
bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
|
||||
bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
|
||||
//bool canFly() const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; }
|
||||
void SetReactState(ReactStates st) { m_reactState = st; }
|
||||
ReactStates GetReactState() { return m_reactState; }
|
||||
bool HasReactState(ReactStates state) const { return (m_reactState == state); }
|
||||
///// TODO RENAME THIS!!!!!
|
||||
bool isCanTrainingOf(Player* player, bool msg) const;
|
||||
bool isCanInteractWithBattleMaster(Player* player, bool msg) const;
|
||||
bool isCanTrainingAndResetTalentsOf(Player* pPlayer) const;
|
||||
bool canCreatureAttack(Unit const *pVictim, bool force = true) const;
|
||||
bool IsImmunedToSpell(SpellEntry const* spellInfo);
|
||||
// redefine Unit::IsImmunedToSpell
|
||||
bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const;
|
||||
// redefine Unit::IsImmunedToSpellEffect
|
||||
bool isElite() const
|
||||
{
|
||||
if (isPet())
|
||||
return false;
|
||||
|
||||
uint32 rank = GetCreatureInfo()->rank;
|
||||
return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE;
|
||||
}
|
||||
|
||||
bool isWorldBoss() const
|
||||
{
|
||||
if (isPet())
|
||||
return false;
|
||||
|
||||
return GetCreatureInfo()->rank == CREATURE_ELITE_WORLDBOSS;
|
||||
}
|
||||
|
||||
uint8 getLevelForTarget(Unit const* target) const; // overwrite Unit::getLevelForTarget for boss level support
|
||||
|
||||
bool IsInEvadeMode() const { return hasUnitState(UNIT_STAT_EVADE); }
|
||||
|
||||
bool AIM_Initialize(CreatureAI* ai = NULL);
|
||||
void Motion_Initialize();
|
||||
|
||||
void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
|
||||
CreatureAI * AI() const { return (CreatureAI*)i_AI; }
|
||||
|
||||
uint32 GetShieldBlockValue() const //dunno mob block value
|
||||
{
|
||||
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, time_t end_time);
|
||||
void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time);
|
||||
void AddCreatureSpellCooldown(uint32 spellid);
|
||||
bool HasSpellCooldown(uint32 spell_id) const;
|
||||
bool HasCategoryCooldown(uint32 spell_id) const;
|
||||
|
||||
bool HasSpell(uint32 spellID) const;
|
||||
|
||||
bool UpdateEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
|
||||
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);
|
||||
uint32 GetCurrentEquipmentId() { return m_equipmentId; }
|
||||
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;
|
||||
|
||||
CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; }
|
||||
CreatureData const *GetCreatureData() const { return m_creatureData; }
|
||||
CreatureDataAddon const* GetCreatureAddon() const;
|
||||
|
||||
std::string GetAIName() const;
|
||||
std::string GetScriptName() const;
|
||||
uint32 GetScriptId() const;
|
||||
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(textId,TargetGuid,IsBossEmote); }
|
||||
void Whisper(int32 textId, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(textId,receiver,IsBossWhisper); }
|
||||
void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
|
||||
|
||||
// overwrite WorldObject function for proper name localization
|
||||
const char* GetNameForLocaleIdx(int32 locale_idx) const;
|
||||
|
||||
void setDeathState(DeathState s); // overwrite virtual Unit::setDeathState
|
||||
bool FallGround();
|
||||
|
||||
bool LoadFromDB(uint32 guid, Map *map);
|
||||
void SaveToDB();
|
||||
// overwrited in Pet
|
||||
virtual void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
|
||||
virtual void DeleteFromDB(); // overwrited in Pet
|
||||
|
||||
Loot loot;
|
||||
bool lootForPickPocketed;
|
||||
bool lootForBody;
|
||||
Player *GetLootRecipient() const;
|
||||
bool hasLootRecipient() const { return m_lootRecipient != 0; }
|
||||
bool isTappedBy(Player *player) const; // return true if the creature is tapped by the player or a member of his party.
|
||||
|
||||
void SetLootRecipient (Unit* unit);
|
||||
void AllLootRemovedFromCorpse();
|
||||
|
||||
uint16 GetLootMode() { return m_LootMode; }
|
||||
bool HasLootMode(uint16 lootMode) { 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; }
|
||||
|
||||
SpellEntry const *reachWithSpellAttack(Unit *pVictim);
|
||||
SpellEntry const *reachWithSpellCure(Unit *pVictim);
|
||||
|
||||
uint32 m_spells[CREATURE_MAX_SPELLS];
|
||||
CreatureSpellCooldowns m_CreatureSpellCooldowns;
|
||||
CreatureSpellCooldowns m_CreatureCategoryCooldowns;
|
||||
uint32 m_GlobalCooldown;
|
||||
|
||||
bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const;
|
||||
bool canStartAttack(Unit const* u, bool force) const;
|
||||
float GetAttackDistance(Unit const* pl) const;
|
||||
|
||||
void SendAIReaction(AiReaction reactionType);
|
||||
|
||||
Unit* SelectNearestTarget(float dist = 0) const;
|
||||
Unit* SelectNearestTargetInAttackDistance(float dist = 0) 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;
|
||||
|
||||
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
|
||||
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
|
||||
|
||||
// for use only in LoadHelper, Map::Add Map::CreatureCellRelocation
|
||||
Cell const& GetCurrentCell() const { return m_currentCell; }
|
||||
void SetCurrentCell(Cell const& cell) { m_currentCell = cell; }
|
||||
|
||||
bool IsVisibleInGridForPlayer(Player const* pl) const;
|
||||
|
||||
void RemoveCorpse();
|
||||
bool isDeadByDefault() const { return m_isDeadByDefault; };
|
||||
|
||||
void ForcedDespawn(uint32 timeMSToDespawn = 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; }
|
||||
|
||||
// Linked Creature Respawning System
|
||||
time_t GetLinkedCreatureRespawnTime() const;
|
||||
const CreatureData* GetLinkedRespawnCreatureData() const;
|
||||
|
||||
uint32 m_groupLootTimer; // (msecs)timer used for group loot
|
||||
uint64 lootingGroupGUID; // 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; }
|
||||
virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; }
|
||||
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
|
||||
{
|
||||
if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED)
|
||||
return 0;
|
||||
else
|
||||
return m_charmInfo->GetCharmSpell(pos)->GetAction();
|
||||
}
|
||||
|
||||
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) { m_homePosition.GetPosition(x, y, z, ori); }
|
||||
Position GetHomePosition() { return m_homePosition; }
|
||||
|
||||
uint32 GetGlobalCooldown() const { return m_GlobalCooldown; }
|
||||
|
||||
uint32 GetWaypointPath(){return m_path_id;}
|
||||
void LoadPath(uint32 pathid) { m_path_id = pathid; }
|
||||
|
||||
uint32 GetCurrentWaypointID(){return m_waypointID;}
|
||||
void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;}
|
||||
|
||||
void SearchFormation();
|
||||
CreatureGroup *GetFormation() {return m_formation;}
|
||||
void SetFormation(CreatureGroup *formation) {m_formation = formation;}
|
||||
|
||||
Unit *SelectVictim();
|
||||
void SetDeadByDefault (bool death_state) {m_isDeadByDefault = death_state;}
|
||||
|
||||
void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; }
|
||||
bool IsReputationGainDisabled() { 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;
|
||||
|
||||
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
|
||||
|
||||
static float _GetDamageMod(int32 Rank);
|
||||
|
||||
float m_SightDistance, m_CombatDistance;
|
||||
|
||||
protected:
|
||||
bool CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData *data = NULL);
|
||||
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
|
||||
|
||||
// vendor items
|
||||
VendorItemCounts m_vendorItemCounts;
|
||||
|
||||
void _RealtimeSetCreatureInfo();
|
||||
|
||||
static float _GetHealthMod(int32 Rank);
|
||||
|
||||
uint32 m_lootMoney;
|
||||
uint64 m_lootRecipient;
|
||||
|
||||
/// Timers
|
||||
uint32 m_deathTimer; // (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;
|
||||
|
||||
ReactStates m_reactState; // for AI, not charmInfo
|
||||
void RegenerateMana();
|
||||
void RegenerateHealth();
|
||||
void Regenerate(Powers power);
|
||||
MovementGeneratorType m_defaultMovementType;
|
||||
Cell m_currentCell; // store current cell where creature listed
|
||||
uint32 m_DBTableGuid; ///< For new or temporary creatures is 0 for saved it is lowguid
|
||||
uint32 m_equipmentId;
|
||||
|
||||
bool m_AlreadyCallAssistance;
|
||||
bool m_AlreadySearchedAssistance;
|
||||
bool m_regenHealth;
|
||||
bool m_AI_locked;
|
||||
bool m_isDeadByDefault;
|
||||
|
||||
SpellSchoolMask m_meleeDamageSchoolMask;
|
||||
uint32 m_originalEntry;
|
||||
|
||||
Position m_homePosition;
|
||||
|
||||
bool DisableReputationGain;
|
||||
|
||||
CreatureInfo const* m_creatureInfo; // in difficulty mode > 0 can different from ObjMgr::GetCreatureTemplate(GetEntry())
|
||||
CreatureData const* m_creatureData;
|
||||
|
||||
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
|
||||
|
||||
private:
|
||||
//WaypointMovementGenerator vars
|
||||
uint32 m_waypointID;
|
||||
uint32 m_path_id;
|
||||
|
||||
//Formation var
|
||||
CreatureGroup *m_formation;
|
||||
};
|
||||
|
||||
class AssistDelayEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
AssistDelayEvent(const uint64& victim, Unit& owner) : BasicEvent(), m_victim(victim), m_owner(owner) { }
|
||||
|
||||
bool Execute(uint64 e_time, uint32 p_time);
|
||||
void AddAssistant(const 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
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Creature.h"
|
||||
#include "CreatureGroups.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "CreatureAI.h"
|
||||
|
||||
#define MAX_DESYNC 5.0f
|
||||
|
||||
INSTANTIATE_SINGLETON_1(CreatureGroupManager);
|
||||
|
||||
CreatureGroupInfoType CreatureGroupMap;
|
||||
|
||||
void CreatureGroupManager::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("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("Group not found: %u. Creating new group.", groupId);
|
||||
CreatureGroup* group = new CreatureGroup(groupId);
|
||||
map->CreatureGroupHolder[groupId] = group;
|
||||
group->AddMember(member);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureGroupManager::RemoveCreatureFromGroup(CreatureGroup *group, Creature *member)
|
||||
{
|
||||
sLog.outDebug("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("Deleting group with InstanceID %u", member->GetInstanceId());
|
||||
map->CreatureGroupHolder.erase(group->GetId());
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureGroupManager::LoadCreatureFormations()
|
||||
{
|
||||
//Clear existing map
|
||||
CreatureGroupMap.clear();
|
||||
|
||||
//Check Integrity of the table
|
||||
QueryResult_AutoPtr result = WorldDatabase.Query("SELECT MAX(leaderGUID) FROM creature_formations");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog.outErrorDb(" ...an error occured while loading the table creature_formations (maybe it doesn't exist ?)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//Get group data
|
||||
result = WorldDatabase.Query("SELECT leaderGUID, memberGUID, dist, angle, groupAI FROM creature_formations ORDER BY leaderGUID");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog.outErrorDb("The table creature_formations is empty or corrupted");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 total_records = result->GetRowCount();
|
||||
barGoLink bar(total_records);
|
||||
Field *fields;
|
||||
|
||||
FormationInfo *group_member;
|
||||
//Loading data...
|
||||
do
|
||||
{
|
||||
fields = result->Fetch();
|
||||
|
||||
bar.step();
|
||||
//Load group member data
|
||||
group_member = new FormationInfo;
|
||||
group_member->leaderGUID = fields[0].GetUInt32();
|
||||
uint32 memberGUID = fields[1].GetUInt32();
|
||||
group_member->groupAI = fields[4].GetUInt8();
|
||||
//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
|
||||
{
|
||||
QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE guid = %u", group_member->leaderGUID);
|
||||
if (!result)
|
||||
{
|
||||
sLog.outErrorDb("creature_formations table leader guid %u incorrect (not exist)", group_member->leaderGUID);
|
||||
delete group_member;
|
||||
continue;
|
||||
}
|
||||
|
||||
result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE guid = %u", memberGUID);
|
||||
if (!result)
|
||||
{
|
||||
sLog.outErrorDb("creature_formations table member guid %u incorrect (not exist)", memberGUID);
|
||||
delete group_member;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
CreatureGroupMap[memberGUID] = group_member;
|
||||
}
|
||||
while (result->NextRow()) ;
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u creatures in formations", total_records);
|
||||
sLog.outString();
|
||||
}
|
||||
|
||||
void CreatureGroup::AddMember(Creature *member)
|
||||
{
|
||||
sLog.outDebug("CreatureGroup::AddMember: Adding unit GUID: %u.", member->GetGUIDLow());
|
||||
|
||||
//Check if it is a leader
|
||||
if (member->GetDBTableGUIDLow() == m_groupID)
|
||||
{
|
||||
sLog.outDebug("Unit GUID: %u is formation leader. Adding group.", member->GetGUIDLow());
|
||||
m_leader = member;
|
||||
}
|
||||
|
||||
m_members[member] = 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 = 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("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->canAttack(target) && itr->first->AI())
|
||||
itr->first->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureGroup::FormationReset(bool dismiss)
|
||||
{
|
||||
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(MOTION_SLOT_IDLE);
|
||||
sLog.outDebug("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)
|
||||
{
|
||||
if (!m_leader)
|
||||
return;
|
||||
|
||||
float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
|
||||
|
||||
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;
|
||||
|
||||
float angle = itr->second->follow_angle;
|
||||
float dist = itr->second->follow_dist;
|
||||
|
||||
float dx = x + cos(angle + pathangle) * dist;
|
||||
float dy = y + sin(angle + pathangle) * dist;
|
||||
float dz = z;
|
||||
|
||||
Trinity::NormalizeMapCoord(dx);
|
||||
Trinity::NormalizeMapCoord(dy);
|
||||
|
||||
member->UpdateGroundPositionZ(dx, dy, dz);
|
||||
|
||||
if (member->IsWithinDist(m_leader, dist + MAX_DESYNC))
|
||||
member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
|
||||
else
|
||||
member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
|
||||
member->GetMotionMaster()->MovePoint(0, dx, dy, dz);
|
||||
member->SetHomePosition(dx, dy, dz, pathangle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _FORMATIONS_H
|
||||
#define _FORMATIONS_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
class CreatureGroup;
|
||||
|
||||
struct FormationInfo
|
||||
{
|
||||
uint32 leaderGUID;
|
||||
float follow_dist;
|
||||
float follow_angle;
|
||||
uint8 groupAI;
|
||||
};
|
||||
|
||||
class CreatureGroupManager
|
||||
{
|
||||
public:
|
||||
void AddCreatureToGroup(uint32 group_id, Creature *creature);
|
||||
void RemoveCreatureFromGroup(CreatureGroup *group, Creature *creature);
|
||||
void LoadCreatureFormations();
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32/*memberDBGUID*/, FormationInfo*> CreatureGroupInfoType;
|
||||
|
||||
extern CreatureGroupInfoType CreatureGroupMap;
|
||||
|
||||
class CreatureGroup
|
||||
{
|
||||
private:
|
||||
Creature *m_leader; //Important do not forget sometimes to work with pointers instead synonims :D:D
|
||||
typedef std::map<Creature*, FormationInfo*> CreatureGroupMemberType;
|
||||
CreatureGroupMemberType m_members;
|
||||
|
||||
uint32 m_groupID;
|
||||
bool m_Formed;
|
||||
|
||||
public:
|
||||
//Group cannot be created empty
|
||||
explicit CreatureGroup(uint32 id) : m_groupID(id), m_leader(NULL), m_Formed(false) {}
|
||||
~CreatureGroup() { sLog.outDebug("Destroying group"); }
|
||||
|
||||
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; }
|
||||
|
||||
void AddMember(Creature *member);
|
||||
void RemoveMember(Creature *member);
|
||||
void FormationReset(bool dismiss);
|
||||
|
||||
void LeaderMoveTo(float x, float y, float z);
|
||||
void MemberAttackStart(Creature* member, Unit *target);
|
||||
};
|
||||
|
||||
#define formation_mgr Trinity::Singleton<CreatureGroupManager>::Instance()
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,882 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "QuestDef.h"
|
||||
#include "GossipDef.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Formulas.h"
|
||||
|
||||
GossipMenu::GossipMenu()
|
||||
{
|
||||
m_gItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use
|
||||
m_gMenuId = 0;
|
||||
}
|
||||
|
||||
GossipMenu::~GossipMenu()
|
||||
{
|
||||
ClearMenu();
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, const std::string& Message, uint32 dtSender, uint32 dtAction, const std::string& BoxMessage, uint32 BoxMoney, bool Coded)
|
||||
{
|
||||
ASSERT(m_gItems.size() <= GOSSIP_MAX_MENU_ITEMS);
|
||||
|
||||
GossipMenuItem gItem;
|
||||
|
||||
gItem.m_gIcon = Icon;
|
||||
gItem.m_gMessage = Message;
|
||||
gItem.m_gCoded = Coded;
|
||||
gItem.m_gSender = dtSender;
|
||||
gItem.m_gOptionId = dtAction;
|
||||
gItem.m_gBoxMessage = BoxMessage;
|
||||
gItem.m_gBoxMoney = BoxMoney;
|
||||
|
||||
m_gItems.push_back(gItem);
|
||||
}
|
||||
|
||||
void GossipMenu::AddGossipMenuItemData(uint32 action_menu, uint32 action_poi, uint32 action_script)
|
||||
{
|
||||
GossipMenuItemData pItemData;
|
||||
|
||||
pItemData.m_gAction_menu = action_menu;
|
||||
pItemData.m_gAction_poi = action_poi;
|
||||
pItemData.m_gAction_script = action_script;
|
||||
|
||||
m_gItemsData.push_back(pItemData);
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, const std::string& Message, bool Coded)
|
||||
{
|
||||
AddMenuItem(Icon, Message, 0, 0, "", 0, Coded);
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, bool Coded)
|
||||
{
|
||||
AddMenuItem(Icon, std::string(Message ? Message : ""),Coded);
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded)
|
||||
{
|
||||
AddMenuItem(Icon, std::string(Message ? Message : ""), dtSender, dtAction, std::string(BoxMessage ? BoxMessage : ""), BoxMoney, Coded);
|
||||
}
|
||||
|
||||
uint32 GossipMenu::MenuItemSender(unsigned int ItemId)
|
||||
{
|
||||
if (ItemId >= m_gItems.size()) return 0;
|
||||
|
||||
return m_gItems[ ItemId ].m_gSender;
|
||||
}
|
||||
|
||||
uint32 GossipMenu::MenuItemAction(unsigned int ItemId)
|
||||
{
|
||||
if (ItemId >= m_gItems.size()) return 0;
|
||||
|
||||
return m_gItems[ ItemId ].m_gOptionId;
|
||||
}
|
||||
|
||||
bool GossipMenu::MenuItemCoded(unsigned int ItemId)
|
||||
{
|
||||
if (ItemId >= m_gItems.size()) return 0;
|
||||
|
||||
return m_gItems[ ItemId ].m_gCoded;
|
||||
}
|
||||
|
||||
void GossipMenu::ClearMenu()
|
||||
{
|
||||
m_gItems.clear();
|
||||
m_gItemsData.clear();
|
||||
}
|
||||
|
||||
PlayerMenu::PlayerMenu(WorldSession *session) : pSession(session)
|
||||
{
|
||||
}
|
||||
|
||||
PlayerMenu::~PlayerMenu()
|
||||
{
|
||||
ClearMenus();
|
||||
}
|
||||
|
||||
void PlayerMenu::ClearMenus()
|
||||
{
|
||||
mGossipMenu.ClearMenu();
|
||||
mQuestMenu.ClearMenu();
|
||||
}
|
||||
|
||||
uint32 PlayerMenu::GossipOptionSender(unsigned int Selection)
|
||||
{
|
||||
return mGossipMenu.MenuItemSender(Selection);
|
||||
}
|
||||
|
||||
uint32 PlayerMenu::GossipOptionAction(unsigned int Selection)
|
||||
{
|
||||
return mGossipMenu.MenuItemAction(Selection);
|
||||
}
|
||||
|
||||
bool PlayerMenu::GossipOptionCoded(unsigned int Selection)
|
||||
{
|
||||
return mGossipMenu.MenuItemCoded(Selection);
|
||||
}
|
||||
|
||||
void PlayerMenu::SendGossipMenu(uint32 TitleTextId, uint64 objectGUID)
|
||||
{
|
||||
WorldPacket data(SMSG_GOSSIP_MESSAGE, (100)); // guess size
|
||||
data << uint64(objectGUID);
|
||||
data << uint32(mGossipMenu.GetMenuId()); // new 2.4.0
|
||||
data << uint32(TitleTextId);
|
||||
data << uint32(mGossipMenu.MenuItemCount()); // max count 0x10
|
||||
|
||||
for (uint32 iI = 0; iI < mGossipMenu.MenuItemCount(); ++iI)
|
||||
{
|
||||
GossipMenuItem const& gItem = mGossipMenu.GetItem(iI);
|
||||
data << uint32(iI);
|
||||
data << uint8(gItem.m_gIcon);
|
||||
data << uint8(gItem.m_gCoded); // makes pop up box password
|
||||
data << uint32(gItem.m_gBoxMoney); // money required to open menu, 2.0.3
|
||||
data << gItem.m_gMessage; // text for gossip item
|
||||
data << gItem.m_gBoxMessage; // accept text (related to money) pop up box, 2.0.3
|
||||
}
|
||||
|
||||
data << uint32(mQuestMenu.MenuItemCount()); // max count 0x20
|
||||
|
||||
for (uint32 iI = 0; iI < mQuestMenu.MenuItemCount(); ++iI)
|
||||
{
|
||||
QuestMenuItem const& qItem = mQuestMenu.GetItem(iI);
|
||||
uint32 questID = qItem.m_qId;
|
||||
Quest const* pQuest = objmgr.GetQuestTemplate(questID);
|
||||
|
||||
data << uint32(questID);
|
||||
data << uint32(qItem.m_qIcon);
|
||||
data << int32(pQuest->GetQuestLevel());
|
||||
data << uint32(pQuest->GetFlags()); // 3.3.3 quest flags
|
||||
data << uint8(0); // 3.3.3 changes icon: blue question or yellow exclamation
|
||||
std::string Title = pQuest->GetTitle();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
if (QuestLocale const *ql = objmgr.GetQuestLocale(questID))
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title = ql->Title[loc_idx];
|
||||
data << Title; // max 0x200
|
||||
}
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
}
|
||||
|
||||
void PlayerMenu::CloseGossip()
|
||||
{
|
||||
WorldPacket data(SMSG_GOSSIP_COMPLETE, 0);
|
||||
pSession->SendPacket(&data);
|
||||
}
|
||||
|
||||
// Outdated
|
||||
void PlayerMenu::SendPointOfInterest(float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, char const * locName)
|
||||
{
|
||||
WorldPacket data(SMSG_GOSSIP_POI, (4+4+4+4+4+10)); // guess size
|
||||
data << uint32(Flags);
|
||||
data << float(X);
|
||||
data << float(Y);
|
||||
data << uint32(Icon);
|
||||
data << uint32(Data);
|
||||
data << locName;
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
//sLog.outDebug("WORLD: Sent SMSG_GOSSIP_POI");
|
||||
}
|
||||
|
||||
void PlayerMenu::SendPointOfInterest(uint32 poi_id)
|
||||
{
|
||||
PointOfInterest const* poi = objmgr.GetPointOfInterest(poi_id);
|
||||
if (!poi)
|
||||
{
|
||||
sLog.outErrorDb("Request to send non-existing POI (Id: %u), ignored.",poi_id);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string icon_name = poi->icon_name;
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
PointOfInterestLocale const *pl = objmgr.GetPointOfInterestLocale(poi_id);
|
||||
if (pl)
|
||||
{
|
||||
if (pl->IconName.size() > size_t(loc_idx) && !pl->IconName[loc_idx].empty())
|
||||
icon_name = pl->IconName[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_GOSSIP_POI, (4+4+4+4+4+10)); // guess size
|
||||
data << uint32(poi->flags);
|
||||
data << float(poi->x);
|
||||
data << float(poi->y);
|
||||
data << uint32(poi->icon);
|
||||
data << uint32(poi->data);
|
||||
data << icon_name;
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
//sLog.outDebug("WORLD: Sent SMSG_GOSSIP_POI");
|
||||
}
|
||||
|
||||
void PlayerMenu::SendTalking(uint32 textID)
|
||||
{
|
||||
GossipText const* pGossip = objmgr.GetGossipText(textID);
|
||||
|
||||
WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size
|
||||
data << textID; // can be < 0
|
||||
|
||||
if (!pGossip)
|
||||
{
|
||||
for (uint32 i = 0; i < 8; ++i)
|
||||
{
|
||||
data << float(0);
|
||||
data << "Greetings $N";
|
||||
data << "Greetings $N";
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string Text_0[8],Text_1[8];
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
Text_0[i]=pGossip->Options[i].Text_0;
|
||||
Text_1[i]=pGossip->Options[i].Text_1;
|
||||
}
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID);
|
||||
if (nl)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
if (nl->Text_0[i].size() > loc_idx && !nl->Text_0[i][loc_idx].empty())
|
||||
Text_0[i]=nl->Text_0[i][loc_idx];
|
||||
if (nl->Text_1[i].size() > loc_idx && !nl->Text_1[i][loc_idx].empty())
|
||||
Text_1[i]=nl->Text_1[i][loc_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
data << pGossip->Options[i].Probability;
|
||||
|
||||
if (Text_0[i].empty())
|
||||
data << Text_1[i];
|
||||
else
|
||||
data << Text_0[i];
|
||||
|
||||
if (Text_1[i].empty())
|
||||
data << Text_0[i];
|
||||
else
|
||||
data << Text_1[i];
|
||||
|
||||
data << pGossip->Options[i].Language;
|
||||
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
data << pGossip->Options[i].Emotes[j]._Delay;
|
||||
data << pGossip->Options[i].Emotes[j]._Emote;
|
||||
}
|
||||
}
|
||||
}
|
||||
pSession->SendPacket(&data);
|
||||
|
||||
sLog.outDebug("WORLD: Sent SMSG_NPC_TEXT_UPDATE ");
|
||||
}
|
||||
|
||||
void PlayerMenu::SendTalking(char const * title, char const * text)
|
||||
{
|
||||
WorldPacket data(SMSG_NPC_TEXT_UPDATE, 50); // guess size
|
||||
data << uint32(0);
|
||||
for (uint32 i = 0; i < 8; ++i)
|
||||
{
|
||||
data << float(0);
|
||||
data << title;
|
||||
data << text;
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
|
||||
sLog.outDebug("WORLD: Sent SMSG_NPC_TEXT_UPDATE ");
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** QUEST SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
QuestMenu::QuestMenu()
|
||||
{
|
||||
m_qItems.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)
|
||||
{
|
||||
Quest const* qinfo = objmgr.GetQuestTemplate(QuestId);
|
||||
if (!qinfo) return;
|
||||
|
||||
ASSERT(m_qItems.size() <= GOSSIP_MAX_MENU_ITEMS);
|
||||
|
||||
QuestMenuItem qItem;
|
||||
|
||||
qItem.m_qId = QuestId;
|
||||
qItem.m_qIcon = Icon;
|
||||
|
||||
m_qItems.push_back(qItem);
|
||||
}
|
||||
|
||||
bool QuestMenu::HasItem(uint32 questid)
|
||||
{
|
||||
for (QuestMenuItemList::const_iterator i = m_qItems.begin(); i != m_qItems.end(); ++i)
|
||||
{
|
||||
if (i->m_qId == questid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QuestMenu::ClearMenu()
|
||||
{
|
||||
m_qItems.clear();
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverQuestList(QEmote eEmote, const std::string& Title, uint64 npcGUID)
|
||||
{
|
||||
WorldPacket data(SMSG_QUESTGIVER_QUEST_LIST, 100); // 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 ( mQuestMenu.MenuItemCount());
|
||||
uint32 count = 0;
|
||||
for (; count < mQuestMenu.MenuItemCount(); ++count)
|
||||
{
|
||||
QuestMenuItem const& qmi = mQuestMenu.GetItem(count);
|
||||
|
||||
uint32 questID = qmi.m_qId;
|
||||
|
||||
if (Quest const *pQuest = objmgr.GetQuestTemplate(questID))
|
||||
{
|
||||
std::string title = pQuest->GetTitle();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
if (QuestLocale const *ql = objmgr.GetQuestLocale(questID))
|
||||
{
|
||||
if (ql->Title.size() > (size_t)loc_idx && !ql->Title[loc_idx].empty())
|
||||
title = ql->Title[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
data << uint32(questID);
|
||||
data << uint32(qmi.m_qIcon);
|
||||
data << int32(pQuest->GetQuestLevel());
|
||||
data << uint32(pQuest->GetFlags()); // 3.3.3 quest flags
|
||||
data << uint8(0); // 3.3.3 changes icon: blue question or yellow exclamation
|
||||
data << title;
|
||||
}
|
||||
}
|
||||
|
||||
data.put<uint8>(count_pos, count);
|
||||
pSession->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST NPC Guid=%u", GUID_LOPART(npcGUID));
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID)
|
||||
{
|
||||
WorldPacket data(SMSG_QUESTGIVER_STATUS, 9);
|
||||
data << uint64(npcGUID);
|
||||
data << uint8(questStatus);
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_STATUS NPC Guid=%u, status=%u", GUID_LOPART(npcGUID), questStatus);
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverQuestDetails(Quest const *pQuest, uint64 npcGUID, bool ActivateAccept)
|
||||
{
|
||||
std::string Title = pQuest->GetTitle();
|
||||
std::string Details = pQuest->GetDetails();
|
||||
std::string Objectives = pQuest->GetObjectives();
|
||||
std::string EndText = pQuest->GetEndText();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty())
|
||||
Details=ql->Details[loc_idx];
|
||||
if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty())
|
||||
Objectives=ql->Objectives[loc_idx];
|
||||
if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty())
|
||||
EndText=ql->EndText[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size
|
||||
data << uint64(npcGUID);
|
||||
data << uint64(0); // wotlk, something todo with quest sharing?
|
||||
data << uint32(pQuest->GetQuestId());
|
||||
data << Title;
|
||||
data << Details;
|
||||
data << Objectives;
|
||||
data << uint8(ActivateAccept ? 1 : 0); // auto finish
|
||||
data << uint32(pQuest->GetFlags()); // 3.3.3 questFlags
|
||||
data << uint32(pQuest->GetSuggestedPlayers());
|
||||
data << uint8(0); // IsFinished? value is sent back to server in quest accept packet
|
||||
|
||||
if (pQuest->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
|
||||
{
|
||||
ItemPrototype const* IProto;
|
||||
|
||||
data << uint32(pQuest->GetRewChoiceItemsCount());
|
||||
for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
|
||||
{
|
||||
if (!pQuest->RewChoiceItemId[i])
|
||||
continue;
|
||||
|
||||
data << uint32(pQuest->RewChoiceItemId[i]);
|
||||
data << uint32(pQuest->RewChoiceItemCount[i]);
|
||||
|
||||
IProto = objmgr.GetItemPrototype(pQuest->RewChoiceItemId[i]);
|
||||
|
||||
if (IProto)
|
||||
data << uint32(IProto->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0x00);
|
||||
}
|
||||
|
||||
data << uint32(pQuest->GetRewItemsCount());
|
||||
|
||||
for (uint32 i=0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
{
|
||||
if (!pQuest->RewItemId[i])
|
||||
continue;
|
||||
|
||||
data << uint32(pQuest->RewItemId[i]);
|
||||
data << uint32(pQuest->RewItemCount[i]);
|
||||
|
||||
IProto = objmgr.GetItemPrototype(pQuest->RewItemId[i]);
|
||||
|
||||
if (IProto)
|
||||
data << uint32(IProto->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(pQuest->GetRewOrReqMoney());
|
||||
data << uint32(pQuest->XPValue(pSession->GetPlayer())*sWorld.getRate(RATE_XP_QUEST));
|
||||
}
|
||||
|
||||
// rewarded honor points. Multiply with 10 to satisfy client
|
||||
data << uint32(10*Trinity::Honor::hk_honor_at_level(pSession->GetPlayer()->getLevel(), pQuest->GetRewHonorableKills()));
|
||||
data << float(0); // new 3.3.0, honor multiplier?
|
||||
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0)
|
||||
data << int32(pQuest->GetRewSpellCast()); // casted spell
|
||||
data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
|
||||
data << uint32(pQuest->GetBonusTalents()); // bonus talents
|
||||
data << uint32(pQuest->GetRewArenaPoints()); // reward arena points
|
||||
data << uint32(0); // unk
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
data << uint32(pQuest->RewRepFaction[i]);
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
data << int32(pQuest->RewRepValueId[i]);
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
data << int32(pQuest->RewRepValue[i]);
|
||||
|
||||
data << uint32(QUEST_EMOTE_COUNT);
|
||||
for (uint32 i=0; i < QUEST_EMOTE_COUNT; ++i)
|
||||
{
|
||||
data << uint32(pQuest->DetailsEmote[i]);
|
||||
data << uint32(pQuest->DetailsEmoteDelay[i]); // DetailsEmoteDelay (in ms)
|
||||
}
|
||||
pSession->SendPacket(&data);
|
||||
|
||||
sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_DETAILS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), pQuest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestQueryResponse(Quest const *pQuest)
|
||||
{
|
||||
std::string Title, Details, Objectives, EndText, CompletedText;
|
||||
std::string ObjectiveText[QUEST_OBJECTIVES_COUNT];
|
||||
Title = pQuest->GetTitle();
|
||||
Details = pQuest->GetDetails();
|
||||
Objectives = pQuest->GetObjectives();
|
||||
EndText = pQuest->GetEndText();
|
||||
CompletedText = pQuest->GetCompletedText();
|
||||
for (int i=0; i<QUEST_OBJECTIVES_COUNT; ++i)
|
||||
ObjectiveText[i]=pQuest->ObjectiveText[i];
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty())
|
||||
Details=ql->Details[loc_idx];
|
||||
if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty())
|
||||
Objectives=ql->Objectives[loc_idx];
|
||||
if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty())
|
||||
EndText=ql->EndText[loc_idx];
|
||||
if (ql->CompletedText.size() > (size_t)loc_idx && !ql->CompletedText[loc_idx].empty())
|
||||
CompletedText=ql->CompletedText[loc_idx];
|
||||
|
||||
for (int i=0; i<QUEST_OBJECTIVES_COUNT; ++i)
|
||||
if (ql->ObjectiveText[i].size() > loc_idx && !ql->ObjectiveText[i][loc_idx].empty())
|
||||
ObjectiveText[i]=ql->ObjectiveText[i][loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_QUEST_QUERY_RESPONSE, 100); // guess size
|
||||
|
||||
data << uint32(pQuest->GetQuestId()); // quest id
|
||||
data << uint32(pQuest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0 == IsAutoComplete() (skip objectives/details)
|
||||
data << uint32(pQuest->GetQuestLevel()); // may be -1, static data, in other cases must be used dynamic level: Player::GetQuestLevel (0 is not known, but assuming this is no longer valid for quest intended for client)
|
||||
data << uint32(pQuest->GetMinLevel()); // min level
|
||||
data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log
|
||||
|
||||
data << uint32(pQuest->GetType()); // quest type
|
||||
data << uint32(pQuest->GetSuggestedPlayers()); // suggested players count
|
||||
|
||||
data << uint32(pQuest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective
|
||||
data << uint32(pQuest->GetRepObjectiveValue()); // shown in quest log as part of quest objective
|
||||
|
||||
data << uint32(pQuest->GetRepObjectiveFaction2()); // shown in quest log as part of quest objective OPOSITE faction
|
||||
data << uint32(pQuest->GetRepObjectiveValue2()); // shown in quest log as part of quest objective OPPOSITE faction
|
||||
|
||||
data << uint32(pQuest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0
|
||||
data << uint32(pQuest->GetXPId()); // used for calculating rewarded experience
|
||||
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
data << uint32(0); // Hide money rewarded
|
||||
else
|
||||
data << uint32(pQuest->GetRewOrReqMoney()); // reward money (below max lvl)
|
||||
|
||||
data << uint32(pQuest->GetRewMoneyMaxLevel()); // used in XP calculation at client
|
||||
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0)
|
||||
data << int32(pQuest->GetRewSpellCast()); // casted spell
|
||||
|
||||
// rewarded honor points
|
||||
data << uint32(Trinity::Honor::hk_honor_at_level(pSession->GetPlayer()->getLevel(), pQuest->GetRewHonorableKills()));
|
||||
data << float(0); // new reward honor (multipled by ~62 at client side)
|
||||
data << uint32(pQuest->GetSrcItemId()); // source item id
|
||||
data << uint32(pQuest->GetFlags() & 0xFFFF); // quest flags
|
||||
data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
|
||||
data << uint32(pQuest->GetPlayersSlain()); // players slain
|
||||
data << uint32(pQuest->GetBonusTalents()); // bonus talents
|
||||
data << uint32(pQuest->GetRewArenaPoints()); // bonus arena points
|
||||
data << uint32(0); // review rep show mask
|
||||
|
||||
int iI;
|
||||
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
{
|
||||
for (iI = 0; iI < QUEST_REWARDS_COUNT; ++iI)
|
||||
data << uint32(0) << uint32(0);
|
||||
for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; ++iI)
|
||||
data << uint32(0) << uint32(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (iI = 0; iI < QUEST_REWARDS_COUNT; ++iI)
|
||||
{
|
||||
data << uint32(pQuest->RewItemId[iI]);
|
||||
data << uint32(pQuest->RewItemCount[iI]);
|
||||
}
|
||||
for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; ++iI)
|
||||
{
|
||||
data << uint32(pQuest->RewChoiceItemId[iI]);
|
||||
data << uint32(pQuest->RewChoiceItemCount[iI]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
|
||||
data << uint32(pQuest->RewRepFaction[i]);
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid+1 QuestFactionReward.dbc?
|
||||
data << int32(pQuest->RewRepValueId[i]);
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unk (0)
|
||||
data << int32(pQuest->RewRepValue[i]);
|
||||
|
||||
data << pQuest->GetPointMapId();
|
||||
data << pQuest->GetPointX();
|
||||
data << pQuest->GetPointY();
|
||||
data << pQuest->GetPointOpt();
|
||||
|
||||
data << Title;
|
||||
data << Objectives;
|
||||
data << Details;
|
||||
data << EndText;
|
||||
data << CompletedText; // display in quest objectives window once all objectives are completed
|
||||
|
||||
for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; ++iI)
|
||||
{
|
||||
if (pQuest->ReqCreatureOrGOId[iI] < 0)
|
||||
{
|
||||
// client expected gameobject template id in form (id|0x80000000)
|
||||
data << uint32((pQuest->ReqCreatureOrGOId[iI]*(-1))|0x80000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(pQuest->ReqCreatureOrGOId[iI]);
|
||||
}
|
||||
data << uint32(pQuest->ReqCreatureOrGOCount[iI]);
|
||||
data << uint32(pQuest->ReqSourceId[iI]);
|
||||
data << uint32(0); // req source count?
|
||||
}
|
||||
|
||||
for (iI = 0; iI < QUEST_ITEM_OBJECTIVES_COUNT; ++iI)
|
||||
{
|
||||
data << uint32(pQuest->ReqItemId[iI]);
|
||||
data << uint32(pQuest->ReqItemCount[iI]);
|
||||
}
|
||||
|
||||
for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; ++iI)
|
||||
data << ObjectiveText[iI];
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", pQuest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverOfferReward(Quest const* pQuest, uint64 npcGUID, bool EnableNext)
|
||||
{
|
||||
std::string Title = pQuest->GetTitle();
|
||||
std::string OfferRewardText = pQuest->GetOfferRewardText();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->OfferRewardText.size() > loc_idx && !ql->OfferRewardText[loc_idx].empty())
|
||||
OfferRewardText=ql->OfferRewardText[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 50); // guess size
|
||||
|
||||
data << uint64(npcGUID);
|
||||
data << uint32(pQuest->GetQuestId());
|
||||
data << Title;
|
||||
data << OfferRewardText;
|
||||
|
||||
data << uint8(EnableNext ? 1 : 0); // Auto Finish
|
||||
data << uint32(pQuest->GetFlags()); // 3.3.3 questFlags
|
||||
data << uint32(pQuest->GetSuggestedPlayers()); // SuggestedGroupNum
|
||||
|
||||
uint32 EmoteCount = 0;
|
||||
for (uint32 i = 0; i < QUEST_EMOTE_COUNT; ++i)
|
||||
{
|
||||
if (pQuest->OfferRewardEmote[i] <= 0)
|
||||
break;
|
||||
++EmoteCount;
|
||||
}
|
||||
|
||||
data << EmoteCount; // Emote Count
|
||||
for (uint32 i = 0; i < EmoteCount; ++i)
|
||||
{
|
||||
data << uint32(pQuest->OfferRewardEmoteDelay[i]); // Delay Emote
|
||||
data << uint32(pQuest->OfferRewardEmote[i]);
|
||||
}
|
||||
|
||||
ItemPrototype const *pItem;
|
||||
|
||||
data << uint32(pQuest->GetRewChoiceItemsCount());
|
||||
for (uint32 i=0; i < pQuest->GetRewChoiceItemsCount(); ++i)
|
||||
{
|
||||
pItem = objmgr.GetItemPrototype(pQuest->RewChoiceItemId[i]);
|
||||
|
||||
data << uint32(pQuest->RewChoiceItemId[i]);
|
||||
data << uint32(pQuest->RewChoiceItemCount[i]);
|
||||
|
||||
if (pItem)
|
||||
data << uint32(pItem->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(pQuest->GetRewItemsCount());
|
||||
for (uint32 i = 0; i < pQuest->GetRewItemsCount(); ++i)
|
||||
{
|
||||
pItem = objmgr.GetItemPrototype(pQuest->RewItemId[i]);
|
||||
data << uint32(pQuest->RewItemId[i]);
|
||||
data << uint32(pQuest->RewItemCount[i]);
|
||||
|
||||
if (pItem)
|
||||
data << uint32(pItem->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(pQuest->GetRewOrReqMoney());
|
||||
data << uint32(pQuest->XPValue(pSession->GetPlayer())*sWorld.getRate(RATE_XP_QUEST));
|
||||
|
||||
// rewarded honor points. Multiply with 10 to satisfy client
|
||||
data << uint32(10*Trinity::Honor::hk_honor_at_level(pSession->GetPlayer()->getLevel(), pQuest->GetRewHonorableKills()));
|
||||
data << float(0); // unk, honor multiplier?
|
||||
data << uint32(0x08); // unused by client?
|
||||
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0)
|
||||
data << int32(pQuest->GetRewSpellCast()); // casted spell
|
||||
data << uint32(0); // unknown
|
||||
data << uint32(pQuest->GetBonusTalents()); // bonus talents
|
||||
data << uint32(pQuest->GetRewArenaPoints()); // arena points
|
||||
data << uint32(0);
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
|
||||
data << uint32(pQuest->RewRepFaction[i]);
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid in QuestFactionReward.dbc (zero based)?
|
||||
data << int32(pQuest->RewRepValueId[i]);
|
||||
|
||||
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward reputation override?
|
||||
data << uint32(pQuest->RewRepValue[i]);
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), pQuest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverRequestItems(Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel)
|
||||
{
|
||||
// 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
|
||||
|
||||
std::string Title = pQuest->GetTitle();
|
||||
std::string RequestItemsText = pQuest->GetRequestItemsText();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->RequestItemsText.size() > loc_idx && !ql->RequestItemsText[loc_idx].empty())
|
||||
RequestItemsText=ql->RequestItemsText[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
if (!pQuest->GetReqItemsCount() && Completable)
|
||||
{
|
||||
SendQuestGiverOfferReward(pQuest, npcGUID, true);
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_QUESTGIVER_REQUEST_ITEMS, 50); // guess size
|
||||
data << uint64(npcGUID);
|
||||
data << uint32(pQuest->GetQuestId());
|
||||
data << Title;
|
||||
data << RequestItemsText;
|
||||
|
||||
data << uint32(0x00); // unknown
|
||||
|
||||
if (Completable)
|
||||
data << pQuest->GetCompleteEmote();
|
||||
else
|
||||
data << pQuest->GetIncompleteEmote();
|
||||
|
||||
// Close Window after cancel
|
||||
if (CloseOnCancel)
|
||||
data << uint32(0x01);
|
||||
else
|
||||
data << uint32(0x00);
|
||||
|
||||
data << uint32(pQuest->GetFlags()); // 3.3.3 questFlags
|
||||
data << uint32(pQuest->GetSuggestedPlayers()); // SuggestedGroupNum
|
||||
|
||||
// Required Money
|
||||
data << uint32(pQuest->GetRewOrReqMoney() < 0 ? -pQuest->GetRewOrReqMoney() : 0);
|
||||
|
||||
data << uint32(pQuest->GetReqItemsCount());
|
||||
ItemPrototype const *pItem;
|
||||
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
if (!pQuest->ReqItemId[i])
|
||||
continue;
|
||||
|
||||
pItem = objmgr.GetItemPrototype(pQuest->ReqItemId[i]);
|
||||
|
||||
data << uint32(pQuest->ReqItemId[i]);
|
||||
data << uint32(pQuest->ReqItemCount[i]);
|
||||
|
||||
if (pItem)
|
||||
data << uint32(pItem->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
if (!Completable)
|
||||
data << uint32(0x00);
|
||||
else
|
||||
data << uint32(0x03);
|
||||
|
||||
data << uint32(0x04);
|
||||
data << uint32(0x08);
|
||||
data << uint32(0x10);
|
||||
|
||||
pSession->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), pQuest->GetQuestId());
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_GOSSIP_H
|
||||
#define TRINITYCORE_GOSSIP_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "QuestDef.h"
|
||||
#include "NPCHandler.h"
|
||||
|
||||
class WorldSession;
|
||||
|
||||
#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough
|
||||
#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, //flight
|
||||
GOSSIP_ICON_TRAINER = 3, //book
|
||||
GOSSIP_ICON_INTERACT_1 = 4, //interaction wheel
|
||||
GOSSIP_ICON_INTERACT_2 = 5, //interaction wheel
|
||||
GOSSIP_ICON_MONEY_BAG = 6, //brown bag with yellow dot
|
||||
GOSSIP_ICON_TALK = 7, //white chat bubble with black dots
|
||||
GOSSIP_ICON_TABARD = 8, //tabard
|
||||
GOSSIP_ICON_BATTLE = 9, //two swords
|
||||
GOSSIP_ICON_DOT = 10, //yellow dot
|
||||
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 m_gIcon;
|
||||
bool m_gCoded;
|
||||
std::string m_gMessage;
|
||||
uint32 m_gSender;
|
||||
uint32 m_gOptionId;
|
||||
std::string m_gBoxMessage;
|
||||
uint32 m_gBoxMoney;
|
||||
};
|
||||
|
||||
typedef std::vector<GossipMenuItem> GossipMenuItemList;
|
||||
|
||||
struct GossipMenuItemData
|
||||
{
|
||||
uint32 m_gAction_menu;
|
||||
uint32 m_gAction_poi;
|
||||
uint32 m_gAction_script;
|
||||
};
|
||||
|
||||
typedef std::vector<GossipMenuItemData> GossipMenuItemDataList;
|
||||
|
||||
struct QuestMenuItem
|
||||
{
|
||||
uint32 m_qId;
|
||||
uint8 m_qIcon;
|
||||
};
|
||||
|
||||
typedef std::vector<QuestMenuItem> QuestMenuItemList;
|
||||
|
||||
class GossipMenu
|
||||
{
|
||||
public:
|
||||
GossipMenu();
|
||||
~GossipMenu();
|
||||
|
||||
void AddMenuItem(uint8 Icon, const std::string& Message, bool Coded = false);
|
||||
void AddMenuItem(uint8 Icon, const std::string& Message, uint32 dtSender, uint32 dtAction, const std::string& BoxMessage, uint32 BoxMoney, bool Coded = false);
|
||||
|
||||
// for using from scripts, don't must be inlined
|
||||
void AddMenuItem(uint8 Icon, char const* Message, bool Coded = false);
|
||||
void AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded = false);
|
||||
|
||||
void SetMenuId(uint32 menu_id) { m_gMenuId = menu_id; }
|
||||
uint32 GetMenuId() { return m_gMenuId; }
|
||||
|
||||
void AddGossipMenuItemData(uint32 action_menu, uint32 action_poi, uint32 action_script);
|
||||
|
||||
unsigned int MenuItemCount() const
|
||||
{
|
||||
return m_gItems.size();
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
return m_gItems.empty();
|
||||
}
|
||||
|
||||
GossipMenuItem const& GetItem(unsigned int Id)
|
||||
{
|
||||
return m_gItems[ Id ];
|
||||
}
|
||||
|
||||
GossipMenuItemData const& GetItemData(unsigned int indexId)
|
||||
{
|
||||
return m_gItemsData[indexId];
|
||||
}
|
||||
|
||||
uint32 MenuItemSender(unsigned int ItemId);
|
||||
uint32 MenuItemAction(unsigned int ItemId);
|
||||
bool MenuItemCoded(unsigned int ItemId);
|
||||
|
||||
void ClearMenu();
|
||||
|
||||
protected:
|
||||
GossipMenuItemList m_gItems;
|
||||
GossipMenuItemDataList m_gItemsData;
|
||||
|
||||
uint32 m_gMenuId;
|
||||
};
|
||||
|
||||
class QuestMenu
|
||||
{
|
||||
public:
|
||||
QuestMenu();
|
||||
~QuestMenu();
|
||||
|
||||
void AddMenuItem(uint32 QuestId, uint8 Icon);
|
||||
void ClearMenu();
|
||||
|
||||
uint8 MenuItemCount() const
|
||||
{
|
||||
return m_qItems.size();
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
return m_qItems.empty();
|
||||
}
|
||||
|
||||
bool HasItem(uint32 questid);
|
||||
|
||||
QuestMenuItem const& GetItem(uint16 Id)
|
||||
{
|
||||
return m_qItems[ Id ];
|
||||
}
|
||||
|
||||
protected:
|
||||
QuestMenuItemList m_qItems;
|
||||
};
|
||||
|
||||
class PlayerMenu
|
||||
{
|
||||
private:
|
||||
GossipMenu mGossipMenu;
|
||||
QuestMenu mQuestMenu;
|
||||
WorldSession* pSession;
|
||||
|
||||
public:
|
||||
PlayerMenu(WorldSession *Session);
|
||||
~PlayerMenu();
|
||||
|
||||
GossipMenu& GetGossipMenu() { return mGossipMenu; }
|
||||
QuestMenu& GetQuestMenu() { return mQuestMenu; }
|
||||
|
||||
bool Empty() const { return mGossipMenu.Empty() && mQuestMenu.Empty(); }
|
||||
|
||||
void ClearMenus();
|
||||
uint32 GossipOptionSender(unsigned int Selection);
|
||||
uint32 GossipOptionAction(unsigned int Selection);
|
||||
bool GossipOptionCoded(unsigned int Selection);
|
||||
|
||||
void SendGossipMenu(uint32 TitleTextId, uint64 npcGUID);
|
||||
void CloseGossip();
|
||||
void SendPointOfInterest(float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, const char * locName);
|
||||
void SendPointOfInterest(uint32 poi_id);
|
||||
void SendTalking(uint32 textID);
|
||||
void SendTalking(char const * title, char const * text);
|
||||
|
||||
/*********************************************************/
|
||||
/*** QUEST SYSTEM ***/
|
||||
/*********************************************************/
|
||||
void SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID);
|
||||
|
||||
void SendQuestGiverQuestList(QEmote eEmote, const std::string& Title, uint64 npcGUID);
|
||||
|
||||
void SendQuestQueryResponse (Quest const *pQuest);
|
||||
void SendQuestGiverQuestDetails(Quest const *pQuest, uint64 npcGUID, bool ActivateAccept);
|
||||
|
||||
void SendQuestGiverOfferReward(Quest const* pQuest, uint64 npcGUID, bool EnableNext);
|
||||
void SendQuestGiverRequestItems(Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,869 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Language.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Player.h"
|
||||
#include "GossipDef.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Creature.h"
|
||||
#include "Pet.h"
|
||||
#include "BattleGroundMgr.h"
|
||||
#include "BattleGround.h"
|
||||
#include "Guild.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TABARDDESIGNER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendTabardVendorActivate(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendTabardVendorActivate(uint64 guid)
|
||||
{
|
||||
WorldPacket data(MSG_TABARDVENDOR_ACTIVATE, 8);
|
||||
data << guid;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleBankerActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_BANKER_ACTIVATE");
|
||||
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_BANKER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendShowBank(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendShowBank(uint64 guid)
|
||||
{
|
||||
WorldPacket data(SMSG_SHOW_BANK, 8);
|
||||
data << guid;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTrainerListOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
SendTrainerList(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendTrainerList(uint64 guid)
|
||||
{
|
||||
std::string str = GetTrinityString(LANG_NPC_TAINER_HELLO);
|
||||
SendTrainerList(guid, str);
|
||||
}
|
||||
|
||||
void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList");
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// trainer list loaded at check;
|
||||
if (!unit->isCanTrainingOf(_player,true))
|
||||
return;
|
||||
|
||||
CreatureInfo const *ci = unit->GetCreatureInfo();
|
||||
|
||||
if (!ci)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!",GUID_LOPART(guid));
|
||||
return;
|
||||
}
|
||||
|
||||
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
|
||||
if (!trainer_spells)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)",
|
||||
GUID_LOPART(guid), unit->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1);
|
||||
data << guid;
|
||||
data << uint32(trainer_spells->trainerType);
|
||||
|
||||
size_t count_pos = data.wpos();
|
||||
data << uint32(trainer_spells->spellList.size());
|
||||
|
||||
// reputation discount
|
||||
float fDiscountMod = _player->GetReputationPriceDiscount(unit);
|
||||
bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0;
|
||||
|
||||
uint32 count = 0;
|
||||
for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
|
||||
{
|
||||
TrainerSpell const* tSpell = &itr->second;
|
||||
|
||||
bool valid = true;
|
||||
bool primary_prof_first_rank = false;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
|
||||
{
|
||||
if (!tSpell->learnedSpell[i])
|
||||
continue;
|
||||
if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell[i]))
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell[i]))
|
||||
primary_prof_first_rank = true;
|
||||
}
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
|
||||
|
||||
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
|
||||
data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
|
||||
data << uint32(floor(tSpell->spellCost * fDiscountMod));
|
||||
|
||||
data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
|
||||
// primary prof. learn confirmation dialog
|
||||
data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
|
||||
data << uint8(tSpell->reqLevel);
|
||||
data << uint32(tSpell->reqSkill);
|
||||
data << uint32(tSpell->reqSkillValue);
|
||||
//prev + req or req + 0
|
||||
uint8 maxReq = 0;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
|
||||
{
|
||||
if (!tSpell->learnedSpell[i])
|
||||
continue;
|
||||
if (SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell[i]))
|
||||
{
|
||||
if (chain_node->prev)
|
||||
{
|
||||
data << uint32(chain_node->prev);
|
||||
++maxReq;
|
||||
}
|
||||
}
|
||||
if (maxReq == 3)
|
||||
break;
|
||||
SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]);
|
||||
for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2)
|
||||
{
|
||||
data << uint32(itr2->second);
|
||||
++maxReq;
|
||||
}
|
||||
if (maxReq == 3)
|
||||
break;
|
||||
}
|
||||
while (maxReq < 3)
|
||||
{
|
||||
data << uint32(0);
|
||||
++maxReq;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
data << strTitle;
|
||||
|
||||
data.put<uint32>(count_pos,count);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
uint32 spellId = 0;
|
||||
|
||||
recv_data >> guid >> spellId;
|
||||
sLog.outDebug("WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId);
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
if (!unit->isCanTrainingOf(_player,true))
|
||||
return;
|
||||
|
||||
// check present spell in trainer spell list
|
||||
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
|
||||
if (!trainer_spells)
|
||||
return;
|
||||
|
||||
// not found, cheat?
|
||||
TrainerSpell const* trainer_spell = trainer_spells->Find(spellId);
|
||||
if (!trainer_spell)
|
||||
return;
|
||||
|
||||
// can't be learn, cheat? Or double learn with lags...
|
||||
if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
|
||||
return;
|
||||
|
||||
// apply reputation discount
|
||||
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
|
||||
|
||||
// check money requirement
|
||||
if (_player->GetMoney() < nSpellCost)
|
||||
return;
|
||||
|
||||
_player->ModifyMoney(-int32(nSpellCost));
|
||||
|
||||
WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
|
||||
data << uint64(guid);
|
||||
data << uint32(0xB3); // index from SpellVisualKit.dbc
|
||||
SendPacket(&data);
|
||||
|
||||
data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player
|
||||
data << uint64(_player->GetGUID());
|
||||
data << uint32(0x016A); // index from SpellVisualKit.dbc
|
||||
SendPacket(&data);
|
||||
|
||||
// learn explicitly or cast explicitly
|
||||
if (trainer_spell->IsCastable())
|
||||
_player->CastSpell(_player,trainer_spell->spell,true);
|
||||
else
|
||||
_player->learnSpell(spellId, false);
|
||||
|
||||
data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
|
||||
data << uint64(guid);
|
||||
data << uint32(spellId); // should be same as in packet from client
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Received CMSG_GOSSIP_HELLO");
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
|
||||
// remove fake death
|
||||
//if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
// GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider())
|
||||
{
|
||||
unit->StopMoving();
|
||||
}
|
||||
|
||||
// If spiritguide, no need for gossip menu, just put player into resurrect queue
|
||||
if (unit->isSpiritGuide())
|
||||
{
|
||||
BattleGround *bg = _player->GetBattleGround();
|
||||
if (bg)
|
||||
{
|
||||
bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID());
|
||||
sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sScriptMgr.GossipHello(_player, unit))
|
||||
{
|
||||
// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID());
|
||||
_player->PrepareGossipMenu(unit, unit->GetCreatureInfo()->GossipMenuId, true);
|
||||
_player->SendPreparedGossip(unit);
|
||||
}
|
||||
}
|
||||
|
||||
/*void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
|
||||
|
||||
uint32 option;
|
||||
uint32 unk;
|
||||
uint64 guid;
|
||||
std::string code = "";
|
||||
|
||||
recv_data >> guid >> unk >> option;
|
||||
|
||||
if (_player->PlayerTalkClass->GossipOptionCoded(option))
|
||||
{
|
||||
sLog.outDebug("reading string");
|
||||
recv_data >> code;
|
||||
sLog.outDebug("string read: %s", code.c_str());
|
||||
}
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
if (!code.empty())
|
||||
{
|
||||
if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str()))
|
||||
unit->OnGossipSelect (_player, option);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option)))
|
||||
unit->OnGossipSelect (_player, option);
|
||||
}
|
||||
}*/
|
||||
|
||||
void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
|
||||
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendSpiritResurrect();
|
||||
}
|
||||
|
||||
void WorldSession::SendSpiritResurrect()
|
||||
{
|
||||
_player->ResurrectPlayer(0.5f, true);
|
||||
|
||||
_player->DurabilityLossAll(0.25f,true);
|
||||
|
||||
// get corpse nearest graveyard
|
||||
WorldSafeLocsEntry const *corpseGrave = NULL;
|
||||
Corpse *corpse = _player->GetCorpse();
|
||||
if (corpse)
|
||||
corpseGrave = objmgr.GetClosestGraveYard(
|
||||
corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam());
|
||||
|
||||
// now can spawn bones
|
||||
_player->SpawnCorpseBones();
|
||||
|
||||
// teleport to nearest from corpse graveyard, if different from nearest to player ghost
|
||||
if (corpseGrave)
|
||||
{
|
||||
WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard(
|
||||
_player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam());
|
||||
|
||||
if (corpseGrave != ghostGrave)
|
||||
_player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
|
||||
// or update at original position
|
||||
else
|
||||
_player->UpdateObjectVisibility();
|
||||
}
|
||||
// or update at original position
|
||||
else
|
||||
_player->UpdateObjectVisibility();
|
||||
}
|
||||
|
||||
void WorldSession::HandleBinderActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 npcGUID;
|
||||
recv_data >> npcGUID;
|
||||
|
||||
if (!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendBindPoint(unit);
|
||||
}
|
||||
|
||||
void WorldSession::SendBindPoint(Creature *npc)
|
||||
{
|
||||
// prevent set homebind to instances in any case
|
||||
if (GetPlayer()->GetMap()->Instanceable())
|
||||
return;
|
||||
|
||||
uint32 bindspell = 3286;
|
||||
|
||||
// update sql homebind
|
||||
CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'",
|
||||
_player->GetMapId(), _player->GetAreaId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
|
||||
_player->m_homebindMapId = _player->GetMapId();
|
||||
_player->m_homebindAreaId = _player->GetAreaId();
|
||||
_player->m_homebindX = _player->GetPositionX();
|
||||
_player->m_homebindY = _player->GetPositionY();
|
||||
_player->m_homebindZ = _player->GetPositionZ();
|
||||
|
||||
// send spell for homebinding (3286)
|
||||
npc->CastSpell(_player, bindspell, true);
|
||||
|
||||
WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
|
||||
data << uint64(npc->GetGUID());
|
||||
data << uint32(bindspell);
|
||||
SendPacket(&data);
|
||||
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
}
|
||||
|
||||
void WorldSession::HandleListStabledPetsOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
|
||||
uint64 npcGUID;
|
||||
|
||||
recv_data >> npcGUID;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// remove mounts this fix bug where getting pet from stable while mounted deletes pet.
|
||||
if (GetPlayer()->IsMounted())
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
||||
|
||||
SendStablePet(npcGUID);
|
||||
}
|
||||
|
||||
void WorldSession::SendStablePet(uint64 guid)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
|
||||
|
||||
WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
|
||||
data << uint64 (guid);
|
||||
|
||||
Pet *pet = _player->GetPet();
|
||||
|
||||
size_t wpos = data.wpos();
|
||||
data << uint8(0); // place holder for slot show number
|
||||
|
||||
data << uint8(GetPlayer()->m_stableSlots);
|
||||
|
||||
uint8 num = 0; // counter for place holder
|
||||
|
||||
// not let move dead pet in slot
|
||||
if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET)
|
||||
{
|
||||
data << uint32(pet->GetCharmInfo()->GetPetNumber());
|
||||
data << uint32(pet->GetEntry());
|
||||
data << uint32(pet->getLevel());
|
||||
data << pet->GetName(); // petname
|
||||
data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
|
||||
++num;
|
||||
}
|
||||
|
||||
// 0 1 2 3 4
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot",
|
||||
_player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
data << uint32(fields[1].GetUInt32()); // petnumber
|
||||
data << uint32(fields[2].GetUInt32()); // creature entry
|
||||
data << uint32(fields[3].GetUInt32()); // level
|
||||
data << fields[4].GetString(); // name
|
||||
data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
|
||||
|
||||
++num;
|
||||
}while (result->NextRow());
|
||||
}
|
||||
|
||||
data.put<uint8>(wpos, num); // set real data to placeholder
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleStablePet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_STABLE_PET");
|
||||
uint64 npcGUID;
|
||||
|
||||
recv_data >> npcGUID;
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleStablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
Pet *pet = _player->GetPet();
|
||||
|
||||
// can't place in stable dead pet
|
||||
if (!pet||!pet->isAlive()||pet->getPetType() != HUNTER_PET)
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 free_slot = 1;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
|
||||
_player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 slot = fields[1].GetUInt32();
|
||||
|
||||
// slots ordered in query, and if not equal then free
|
||||
if (slot != free_slot)
|
||||
break;
|
||||
|
||||
// this slot not free, skip
|
||||
++free_slot;
|
||||
}while (result->NextRow());
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
if (free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
|
||||
{
|
||||
_player->RemovePet(pet,PetSaveMode(free_slot));
|
||||
data << uint8(0x08);
|
||||
}
|
||||
else
|
||||
data << uint8(0x06);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleUnstablePet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
|
||||
uint64 npcGUID;
|
||||
uint32 petnumber;
|
||||
|
||||
recv_data >> npcGUID >> petnumber;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 creature_id = 0;
|
||||
|
||||
{
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
|
||||
_player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
|
||||
if (result)
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
creature_id = fields[0].GetUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
if (!creature_id)
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id);
|
||||
if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
if (pet && pet->isAlive())
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
// delete dead pet
|
||||
if (pet)
|
||||
_player->RemovePet(pet,PET_SAVE_AS_DELETED);
|
||||
|
||||
Pet *newpet = new Pet(_player, HUNTER_PET);
|
||||
if (!newpet->LoadPetFromDB(_player,creature_id,petnumber))
|
||||
{
|
||||
delete newpet;
|
||||
newpet = NULL;
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x09);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleBuyStableSlot(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
|
||||
uint64 npcGUID;
|
||||
|
||||
recv_data >> npcGUID;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 200);
|
||||
|
||||
if (GetPlayer()->m_stableSlots < MAX_PET_STABLES)
|
||||
{
|
||||
StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
|
||||
if (_player->GetMoney() >= SlotPrice->Price)
|
||||
{
|
||||
++GetPlayer()->m_stableSlots;
|
||||
_player->ModifyMoney(-int32(SlotPrice->Price));
|
||||
data << uint8(0x0A); // success buy
|
||||
}
|
||||
else
|
||||
data << uint8(0x06);
|
||||
}
|
||||
else
|
||||
data << uint8(0x06);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleStableRevivePet(WorldPacket &/* recv_data */)
|
||||
{
|
||||
sLog.outDebug("HandleStableRevivePet: Not implemented");
|
||||
}
|
||||
|
||||
void WorldSession::HandleStableSwapPet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
|
||||
uint64 npcGUID;
|
||||
uint32 pet_number;
|
||||
|
||||
recv_data >> npcGUID >> pet_number;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
|
||||
if (!pet || pet->getPetType() != HUNTER_PET)
|
||||
return;
|
||||
|
||||
// find swapped pet slot in stable
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
|
||||
_player->GetGUIDLow(),pet_number);
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 slot = fields[0].GetUInt32();
|
||||
uint32 creature_id = fields[1].GetUInt32();
|
||||
|
||||
if (!creature_id)
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id);
|
||||
if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
// move alive pet to slot or delete dead pet
|
||||
_player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
|
||||
|
||||
// summon unstabled pet
|
||||
Pet *newpet = new Pet(_player);
|
||||
if (!newpet->LoadPetFromDB(_player,creature_id,pet_number))
|
||||
{
|
||||
delete newpet;
|
||||
data << uint8(0x06);
|
||||
}
|
||||
else
|
||||
data << uint8(0x09);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
|
||||
|
||||
uint64 npcGUID, itemGUID;
|
||||
uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
|
||||
|
||||
recv_data >> npcGUID >> itemGUID >> guildBank;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// reputation discount
|
||||
float discountMod = _player->GetReputationPriceDiscount(unit);
|
||||
|
||||
uint32 TotalCost = 0;
|
||||
if (itemGUID)
|
||||
{
|
||||
sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
|
||||
|
||||
Item* item = _player->GetItemByGuid(itemGUID);
|
||||
|
||||
if (item)
|
||||
TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
|
||||
|
||||
TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
|
||||
}
|
||||
if (guildBank)
|
||||
{
|
||||
uint32 GuildId = _player->GetGuildId();
|
||||
if (!GuildId)
|
||||
return;
|
||||
Guild *pGuild = objmgr.GetGuildById(GuildId);
|
||||
if (!pGuild)
|
||||
return;
|
||||
pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
|
||||
pGuild->SendMoneyInfo(this, _player->GetGUIDLow());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __NPCHANDLER_H
|
||||
#define __NPCHANDLER_H
|
||||
|
||||
// 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 PageText
|
||||
{
|
||||
uint32 Page_ID;
|
||||
char * Text;
|
||||
|
||||
uint32 Next_Page;
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
struct QEmote
|
||||
{
|
||||
uint32 _Emote;
|
||||
uint32 _Delay;
|
||||
};
|
||||
|
||||
struct GossipTextOption
|
||||
{
|
||||
std::string Text_0;
|
||||
std::string Text_1;
|
||||
uint32 Language;
|
||||
float Probability;
|
||||
QEmote Emotes[3];
|
||||
};
|
||||
|
||||
struct GossipText
|
||||
{
|
||||
GossipTextOption Options[8];
|
||||
};
|
||||
|
||||
struct PageTextLocale
|
||||
{
|
||||
std::vector<std::string> Text;
|
||||
};
|
||||
|
||||
struct NpcTextLocale
|
||||
{
|
||||
NpcTextLocale() { Text_0.resize(8); Text_1.resize(8); }
|
||||
|
||||
std::vector<std::vector<std::string> > Text_0;
|
||||
std::vector<std::vector<std::string> > Text_1;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
TempSummon::TempSummon(SummonPropertiesEntry const *properties, Unit *owner) :
|
||||
Creature(), m_type(TEMPSUMMON_MANUAL_DESPAWN), m_timer(0), m_lifetime(0)
|
||||
, m_Properties(properties)
|
||||
{
|
||||
m_summonerGUID = owner ? owner->GetGUID() : 0;
|
||||
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:
|
||||
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 && isTrigger() && m_spells[0])
|
||||
{
|
||||
setFaction(owner->getFaction());
|
||||
SetLevel(owner->getLevel());
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER)
|
||||
m_ControlledByPlayer = 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()) // 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);
|
||||
if (IsAIEnabled)
|
||||
AI()->IsSummonedBy(owner);
|
||||
}
|
||||
}
|
||||
|
||||
void TempSummon::SetTempSummonType(TempSummonType type)
|
||||
{
|
||||
m_type = type;
|
||||
}
|
||||
|
||||
void TempSummon::UnSummon()
|
||||
{
|
||||
//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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void TempSummon::SaveToDB()
|
||||
{
|
||||
}
|
||||
|
||||
Minion::Minion(SummonPropertiesEntry const *properties, Unit *owner) : TempSummon(properties, owner)
|
||||
, 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);
|
||||
|
||||
SetCreatorGUID(m_owner->GetGUID());
|
||||
setFaction(m_owner->getFaction());
|
||||
|
||||
m_owner->SetMinion(this, true);
|
||||
}
|
||||
|
||||
void Minion::RemoveFromWorld()
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
m_owner->SetMinion(this, false);
|
||||
TempSummon::RemoveFromWorld();
|
||||
}
|
||||
|
||||
bool Minion::IsGuardianPet() const
|
||||
{
|
||||
return isPet() || m_Properties && m_Properties->Category == SUMMON_CATEGORY_PET;
|
||||
}
|
||||
|
||||
Guardian::Guardian(SummonPropertiesEntry const *properties, Unit *owner) : Minion(properties, owner)
|
||||
, m_bonusdamage(0)
|
||||
{
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER
|
||||
&& m_owner->GetMinionGUID() == GetGUID()
|
||||
&& !m_owner->GetCharmGUID())
|
||||
m_owner->ToPlayer()->CharmSpellInitialize();
|
||||
}
|
||||
|
||||
Puppet::Puppet(SummonPropertiesEntry const *properties, Unit *owner) : Minion(properties, owner)
|
||||
{
|
||||
assert(owner->GetTypeId() == TYPEID_PLAYER);
|
||||
m_owner = (Player*)owner;
|
||||
m_unitTypeMask |= UNIT_MASK_PUPPET;
|
||||
}
|
||||
|
||||
void Puppet::InitStats(uint32 duration)
|
||||
{
|
||||
Minion::InitStats(duration);
|
||||
SetLevel(m_owner->getLevel());
|
||||
SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
void Puppet::InitSummon()
|
||||
{
|
||||
Minion::InitSummon();
|
||||
if (!SetCharmedBy(m_owner, CHARM_TYPE_POSSESS))
|
||||
assert(false);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_TEMPSUMMON_H
|
||||
#define TRINITYCORE_TEMPSUMMON_H
|
||||
|
||||
#include "Creature.h"
|
||||
|
||||
class TempSummon : public Creature
|
||||
{
|
||||
public:
|
||||
explicit TempSummon(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
virtual ~TempSummon(){};
|
||||
void Update(uint32 time);
|
||||
virtual void InitStats(uint32 lifetime);
|
||||
virtual void InitSummon();
|
||||
void UnSummon();
|
||||
void RemoveFromWorld();
|
||||
void SetTempSummonType(TempSummonType type);
|
||||
void SaveToDB();
|
||||
Unit* GetSummoner() const;
|
||||
uint64 const& GetSummonerGUID() { return m_summonerGUID; }
|
||||
|
||||
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, Unit *owner);
|
||||
void InitStats(uint32 duration);
|
||||
void RemoveFromWorld();
|
||||
Unit *GetOwner() { return m_owner; }
|
||||
float GetFollowAngle() const { return m_followAngle; }
|
||||
void SetFollowAngle(float angle) { m_followAngle = angle; }
|
||||
bool IsPetGhoul() const {return GetEntry() == 26125;} // Ghoul may be guardian or pet
|
||||
bool IsGuardianPet() const;
|
||||
protected:
|
||||
Unit * const m_owner;
|
||||
float m_followAngle;
|
||||
};
|
||||
|
||||
class Guardian : public Minion
|
||||
{
|
||||
public:
|
||||
Guardian(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
void InitStats(uint32 duration);
|
||||
bool InitStatsForLevel(uint8 level);
|
||||
void InitSummon();
|
||||
|
||||
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);
|
||||
|
||||
int32 GetBonusDamage() { return m_bonusdamage; }
|
||||
void SetBonusDamage(int32 damage) { m_bonusdamage = damage; }
|
||||
protected:
|
||||
int32 m_bonusdamage;
|
||||
};
|
||||
|
||||
class Puppet : public Minion
|
||||
{
|
||||
public:
|
||||
Puppet(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
void InitStats(uint32 duration);
|
||||
void InitSummon();
|
||||
void Update(uint32 time);
|
||||
void RemoveFromWorld();
|
||||
protected:
|
||||
Player *m_owner;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_GAMEOBJECT_H
|
||||
#define TRINITYCORE_GAMEOBJECT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Object.h"
|
||||
#include "LootMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
|
||||
// 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
|
||||
|
||||
// from `gameobject_template`
|
||||
struct GameObjectInfo
|
||||
{
|
||||
uint32 id;
|
||||
uint32 type;
|
||||
uint32 displayId;
|
||||
char *name;
|
||||
char *IconName;
|
||||
char *castBarCaption;
|
||||
char *unk1;
|
||||
uint32 faction;
|
||||
uint32 flags;
|
||||
float size;
|
||||
uint32 questItems[6];
|
||||
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
|
||||
uint32 maxSuccessOpens; //5
|
||||
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
|
||||
uint32 questID; //5
|
||||
} _generic;
|
||||
//6 GAMEOBJECT_TYPE_TRAP
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0 -> Lock.dbc
|
||||
uint32 level; //1
|
||||
uint32 radius; //2 radius for trap activation
|
||||
uint32 spellId; //3
|
||||
uint32 charges; //4 need respawn (if > 0)
|
||||
uint32 cooldown; //5 time in secs
|
||||
int32 autoCloseTime; //6
|
||||
uint32 startDelay; //7
|
||||
uint32 serverOnly; //8
|
||||
uint32 stealthed; //9
|
||||
uint32 large; //10
|
||||
uint32 stealthAffected; //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 pause; //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
|
||||
} 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 // not implemented yet
|
||||
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[24];
|
||||
} raw;
|
||||
};
|
||||
uint32 ScriptId;
|
||||
|
||||
// helpers
|
||||
bool IsDespawnAtAction() const
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case GAMEOBJECT_TYPE_CHEST: return chest.consumable;
|
||||
case GAMEOBJECT_TYPE_GOOBER: return goober.consumable;
|
||||
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 / IN_MILISECONDS; // 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class OPvPCapturePoint;
|
||||
|
||||
union GameObjectValue
|
||||
{
|
||||
//29 GAMEOBJECT_TYPE_CAPTURE_POINT
|
||||
struct
|
||||
{
|
||||
OPvPCapturePoint *OPvPObj;
|
||||
}capturePoint;
|
||||
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
|
||||
struct
|
||||
{
|
||||
uint32 health;
|
||||
}building;
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
struct GameObjectLocale
|
||||
{
|
||||
std::vector<std::string> Name;
|
||||
std::vector<std::string> CastBarCaption;
|
||||
};
|
||||
|
||||
// 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() : dbData(true) {}
|
||||
uint32 id; // entry in gamobject_template
|
||||
uint16 mapid;
|
||||
uint16 phaseMask;
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float orientation;
|
||||
float rotation0;
|
||||
float rotation1;
|
||||
float rotation2;
|
||||
float rotation3;
|
||||
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;
|
||||
|
||||
// 5 sec for bobber catch
|
||||
#define FISHING_BOBBER_READY_TIME 5
|
||||
|
||||
class GameObject : public WorldObject, public GridObject<GameObject>
|
||||
{
|
||||
public:
|
||||
explicit GameObject();
|
||||
~GameObject();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
void CleanupsBeforeDelete(bool finalCleanup = true);
|
||||
|
||||
bool Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit = 0);
|
||||
void Update(uint32 p_time);
|
||||
static GameObject* GetGameObject(WorldObject& object, uint64 guid);
|
||||
GameObjectInfo const* GetGOInfo() const { return m_goInfo; }
|
||||
GameObjectData const* GetGOData() const { return m_goData; }
|
||||
GameObjectValue * GetGOValue() const { return m_goValue; }
|
||||
|
||||
bool IsTransport() const;
|
||||
bool IsDynTransport() const;
|
||||
|
||||
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
|
||||
|
||||
void UpdateRotationFields(float rotation2 = 0.0f, float rotation3 = 0.0f);
|
||||
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
|
||||
void Whisper(int32 textId, uint64 receiver) { MonsterWhisper(textId,receiver); }
|
||||
void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
|
||||
|
||||
// overwrite WorldObject function for proper name localization
|
||||
const char* GetNameForLocaleIdx(int32 locale_idx) const;
|
||||
|
||||
void SaveToDB();
|
||||
void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
|
||||
bool LoadFromDB(uint32 guid, Map *map);
|
||||
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(bool inWorld = true) 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);
|
||||
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) { SetByteValue(GAMEOBJECT_BYTES_1, 0, 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 Use(Unit* user);
|
||||
|
||||
LootState getLootState() const { return m_lootState; }
|
||||
void SetLootState(LootState s) { m_lootState = s; }
|
||||
|
||||
uint16 GetLootMode() { return m_LootMode; }
|
||||
bool HasLootMode(uint16 lootMode) { 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;
|
||||
|
||||
uint32 m_groupLootTimer; // (msecs)timer used for group loot
|
||||
uint64 lootingGroupGUID; // used to find group which is looting
|
||||
|
||||
bool hasQuest(uint32 quest_id) const;
|
||||
bool hasInvolvedQuest(uint32 quest_id) const;
|
||||
bool ActivateToQuest(Player *pTarget) const;
|
||||
void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false);
|
||||
// 0 = use `gameobject`.`spawntimesecs`
|
||||
void ResetDoorOrButton();
|
||||
|
||||
void TriggeringLinkedGameObject(uint32 trapEntry, Unit* target);
|
||||
|
||||
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
|
||||
bool canDetectTrap(Player const* u, float distance) const;
|
||||
|
||||
GameObject* LookupFishingHoleAround(float range);
|
||||
|
||||
void CastSpell(Unit *target, uint32 spell);
|
||||
void SendCustomAnim();
|
||||
bool IsInRange(float x, float y, float z, float radius) const;
|
||||
void TakenDamage(uint32 damage, Unit* who = NULL);
|
||||
void Rebuild();
|
||||
|
||||
void EventInform(uint32 eventId);
|
||||
|
||||
uint64 GetRotation() const { return m_rotation; }
|
||||
protected:
|
||||
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;
|
||||
time_t 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;
|
||||
|
||||
std::set<uint32> 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
|
||||
GameObjectInfo const* m_goInfo;
|
||||
GameObjectData const* m_goData;
|
||||
GameObjectValue * const m_goValue;
|
||||
|
||||
uint64 m_rotation;
|
||||
|
||||
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
|
||||
private:
|
||||
void SwitchDoorOrButton(bool activate, bool alternative = false);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
|
||||
#include "Bag.h"
|
||||
#include "Log.h"
|
||||
#include "UpdateData.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)
|
||||
{
|
||||
ItemPrototype const * itemProto = objmgr.GetItemPrototype(itemid);
|
||||
|
||||
if (!itemProto || itemProto->ContainerSlots > MAX_BAG_SIZE)
|
||||
return false;
|
||||
|
||||
Object::_Create(guidlow, 0, HIGHGUID_CONTAINER);
|
||||
|
||||
SetEntry(itemid);
|
||||
SetFloatValue(OBJECT_FIELD_SCALE_X, 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_FLAGS, itemProto->Flags);
|
||||
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()
|
||||
{
|
||||
Item::SaveToDB();
|
||||
}
|
||||
|
||||
bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result)
|
||||
{
|
||||
if (!Item::LoadFromDB(guid, owner_guid, result))
|
||||
return false;
|
||||
|
||||
// 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);
|
||||
if (m_bagslot[i])
|
||||
{
|
||||
delete m_bagslot[i];
|
||||
m_bagslot[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bag::DeleteFromDB()
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
|
||||
if (m_bagslot[i])
|
||||
m_bagslot[i]->DeleteFromDB();
|
||||
|
||||
Item::DeleteFromDB();
|
||||
}
|
||||
|
||||
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->GetProto()->GemProperties)
|
||||
{
|
||||
for (uint32 i=0; i < GetBagSize(); ++i)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if (pItem && pItem != eItem && pItem->GetProto()->Socket[0].Color)
|
||||
count += pItem->GetGemCountWithID(item);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#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;
|
||||
|
||||
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();
|
||||
// overwrite virtual Item::LoadFromDB
|
||||
bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result);
|
||||
// overwrite virtual Item::DeleteFromDB
|
||||
void DeleteFromDB();
|
||||
|
||||
void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const;
|
||||
|
||||
protected:
|
||||
|
||||
// Bag Storage space
|
||||
Item* m_bagslot[MAX_BAG_SIZE];
|
||||
};
|
||||
|
||||
inline Item* NewItemOrBag(ItemPrototype const * proto)
|
||||
{
|
||||
return (proto->InventoryType == INVTYPE_BAG) ? new Bag : new Item;
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_ITEM_H
|
||||
#define TRINITYCORE_ITEM_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "LootMgr.h"
|
||||
#include "ItemPrototype.h"
|
||||
|
||||
struct SpellEntry;
|
||||
class Bag;
|
||||
class QueryResult;
|
||||
class Unit;
|
||||
|
||||
struct ItemSetEffect
|
||||
{
|
||||
uint32 setid;
|
||||
uint32 item_count;
|
||||
SpellEntry const *spells[8];
|
||||
};
|
||||
|
||||
enum InventoryChangeFailure
|
||||
{
|
||||
EQUIP_ERR_OK = 0,
|
||||
EQUIP_ERR_CANT_EQUIP_LEVEL_I = 1,
|
||||
EQUIP_ERR_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_QUIVER2 = 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,
|
||||
// no output = 81,
|
||||
EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS = 82,
|
||||
// no output = 83,
|
||||
// crash client = 84,
|
||||
};
|
||||
|
||||
enum BuyFailure
|
||||
{
|
||||
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 SellFailure
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
enum ItemRequiredTargetType
|
||||
{
|
||||
ITEM_TARGET_TYPE_CREATURE = 1,
|
||||
ITEM_TARGET_TYPE_DEAD = 2
|
||||
};
|
||||
|
||||
#define MAX_ITEM_REQ_TARGET_TYPE 2
|
||||
|
||||
struct ItemRequiredTarget
|
||||
{
|
||||
ItemRequiredTarget(ItemRequiredTargetType uiType, uint32 uiTargetEntry) : m_uiType(uiType), m_uiTargetEntry(uiTargetEntry) {}
|
||||
ItemRequiredTargetType m_uiType;
|
||||
uint32 m_uiTargetEntry;
|
||||
|
||||
// helpers
|
||||
bool IsFitToRequirements(Unit* pUnitTarget) const;
|
||||
};
|
||||
|
||||
bool ItemCanGoIntoBag(ItemPrototype const *proto, ItemPrototype 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);
|
||||
|
||||
ItemPrototype const* GetProto() const;
|
||||
|
||||
uint64 const& 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_FLAGS_BINDED,val); }
|
||||
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BINDED); }
|
||||
bool IsBoundAccountWide() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BOA); }
|
||||
bool IsBindedNotWith(Player const* player) const;
|
||||
bool IsBoundByEnchant() const;
|
||||
virtual void SaveToDB();
|
||||
virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result);
|
||||
virtual void DeleteFromDB();
|
||||
void DeleteFromInventoryDB();
|
||||
void SaveRefundDataToDB();
|
||||
void DeleteRefundDataFromDB();
|
||||
|
||||
bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; }
|
||||
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
|
||||
bool CanBeTraded(bool mail = false) const;
|
||||
void SetInTrade(bool b = true) { mb_in_trade = b; }
|
||||
bool IsInTrade() const { return mb_in_trade; }
|
||||
|
||||
bool HasEnchantRequiredSkill(const Player *pPlayer) const;
|
||||
uint32 GetEnchantRequiredLevel() const;
|
||||
|
||||
bool IsFitToSpellRequirements(SpellEntry const* spellInfo) const;
|
||||
bool IsTargetValidForItemUse(Unit* pUnitTarget);
|
||||
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 GetProto()->GetMaxStackSize(); }
|
||||
uint8 GetGemCountWithID(uint32 GemID) const;
|
||||
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const;
|
||||
uint8 CanBeMergedPartlyWith(ItemPrototype 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);
|
||||
bool UpdateItemSuffixFactor();
|
||||
static int32 GenerateItemRandomPropertyId(uint32 item_id);
|
||||
void SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges);
|
||||
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 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; }
|
||||
uint16 GetQueuePos() const { return uQueuePos; }
|
||||
void FSetState(ItemUpdateState state) // forced
|
||||
{
|
||||
uState = state;
|
||||
}
|
||||
|
||||
bool hasQuest(uint32 quest_id) const { return GetProto()->StartQuest == quest_id; }
|
||||
bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; }
|
||||
bool IsPotion() const { return GetProto()->IsPotion(); }
|
||||
bool IsWeaponVellum() const { return GetProto()->IsWeaponVellum(); }
|
||||
bool IsArmorVellum() const { return GetProto()->IsArmorVellum(); }
|
||||
bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); }
|
||||
|
||||
// Item Refund system
|
||||
void SetNotRefundable(Player *owner, bool changestate = true);
|
||||
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();
|
||||
|
||||
void BuildUpdate(UpdateDataMapType&);
|
||||
|
||||
private:
|
||||
std::string m_text;
|
||||
uint8 m_slot;
|
||||
Bag *m_container;
|
||||
ItemUpdateState uState;
|
||||
int16 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;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
#include "ItemEnchantmentMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ProgressBar.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "Util.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()
|
||||
{
|
||||
RandomItemEnch.clear(); // for reload case
|
||||
|
||||
EnchantmentStore::const_iterator tab;
|
||||
uint32 entry, ench;
|
||||
float chance;
|
||||
uint32 count = 0;
|
||||
|
||||
QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, ench, chance FROM item_enchantment_template");
|
||||
|
||||
if (result)
|
||||
{
|
||||
barGoLink bar(result->GetRowCount());
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
bar.step();
|
||||
|
||||
entry = fields[0].GetUInt32();
|
||||
ench = fields[1].GetUInt32();
|
||||
chance = fields[2].GetFloat();
|
||||
|
||||
if (chance > 0.000001f && chance <= 100.0f)
|
||||
RandomItemEnch[entry].push_back(EnchStoreItem(ench, chance));
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u Item Enchantment definitions", count);
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outString();
|
||||
sLog.outErrorDb(">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetItemEnchantMod(int32 entry)
|
||||
{
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
EnchantmentStore::const_iterator tab;
|
||||
|
||||
if (entry == -1)
|
||||
{
|
||||
tab = RandomItemEnch.begin();
|
||||
entry = urand(1, RandomItemEnch.size()) - 1;
|
||||
for (uint32 i = 0; i < entry; ++i)
|
||||
++tab;
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
ItemPrototype const *itemProto = objmgr.GetItemPrototype(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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ITEMPROTOTYPE_H
|
||||
#define _ITEMPROTOTYPE_H
|
||||
|
||||
#include "Common.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
|
||||
|
||||
// masks for ITEM_FIELD_FLAGS field
|
||||
enum ITEM_FLAGS
|
||||
{
|
||||
ITEM_FLAGS_BINDED = 0x00000001, // set in game at binding, not set in template
|
||||
ITEM_FLAGS_CONJURED = 0x00000002,
|
||||
ITEM_FLAGS_OPENABLE = 0x00000004,
|
||||
ITEM_FLAGS_WRAPPED = 0x00000008,
|
||||
ITEM_FLAGS_BROKEN = 0x00000010, // appears red icon (like when item durability == 0)
|
||||
ITEM_FLAGS_TOTEM = 0x00000020, // ?
|
||||
ITEM_FLAGS_USABLE = 0x00000040, // ?
|
||||
ITEM_FLAGS_WRAPPER = 0x00000200, // used or not used wrapper
|
||||
ITEM_FLAGS_PARTY_LOOT = 0x00000800, // determines if item is party loot or not
|
||||
ITEM_FLAGS_REFUNDABLE = 0x00001000, // item cost can be refunded within 2 hours after purchase
|
||||
ITEM_FLAGS_CHARTER = 0x00002000, // arena/guild charter
|
||||
ITEM_FLAGS_REFUNDABLE_2 = 0x00008000,
|
||||
ITEM_FLAGS_UNK1 = 0x00010000,
|
||||
ITEM_FLAGS_PROSPECTABLE = 0x00040000,
|
||||
ITEM_FLAGS_UNIQUE_EQUIPPED = 0x00080000,
|
||||
ITEM_FLAGS_USEABLE_IN_ARENA = 0x00200000,
|
||||
ITEM_FLAGS_THROWABLE = 0x00400000, // not used in game for check trow possibility, only for item in game tooltip
|
||||
ITEM_FLAGS_SPECIALUSE = 0x00800000, // last used flag in 2.3.0
|
||||
ITEM_FLAGS_BOA = 0x08000000, // bind on account (set in template for items that can binded in like way)
|
||||
ITEM_FLAGS_TRIGGERED_CAST = 0x10000000, // used by enchanting scrolls made with vellum
|
||||
ITEM_FLAGS_ENCHANT_SCROLL = 0x10000000, // for enchant scrolls
|
||||
ITEM_FLAGS_MILLABLE = 0x20000000,
|
||||
ITEM_FLAGS_BOP_TRADEABLE = 0x80000000
|
||||
};
|
||||
|
||||
enum ItemFlagsExtra
|
||||
{
|
||||
ITEM_FLAGS_EXTRA_HORDE_ONLY = 0x00000001,
|
||||
ITEM_FLAGS_EXTRA_ALLIANCE_ONLY = 0x00000002,
|
||||
ITEM_FLAGS_EXTRA_REFUNDABLE = 0x00000004,
|
||||
ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#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 ItemPrototype
|
||||
{
|
||||
uint32 ItemId;
|
||||
uint32 Class; // id from ItemClass.dbc
|
||||
uint32 SubClass; // id from ItemSubClass.dbc
|
||||
int32 Unk0;
|
||||
char* 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;
|
||||
char* 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;
|
||||
int32 Duration; // negative = realtime, positive = ingame time
|
||||
uint32 ItemLimitCategory; // id from ItemLimitCategory.dbc
|
||||
uint32 HolidayId; // id from Holidays.dbc
|
||||
uint32 ScriptId;
|
||||
uint32 DisenchantID;
|
||||
uint32 FoodType;
|
||||
uint32 MinMoneyLoot;
|
||||
uint32 MaxMoneyLoot;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
uint32 GetMaxStackSize() const
|
||||
{
|
||||
return (Stackable == 2147483647 || Stackable <= 0 || Stackable == 1000) ? uint32(0x7FFFFFFF-1) : uint32(Stackable);
|
||||
}
|
||||
|
||||
float getDPS() const
|
||||
{
|
||||
if (Delay == 0)
|
||||
return 0;
|
||||
float temp = 0;
|
||||
for (int 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;
|
||||
}
|
||||
|
||||
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_FLAGS_CONJURED); }
|
||||
};
|
||||
|
||||
struct ItemLocale
|
||||
{
|
||||
std::vector<std::string> Name;
|
||||
std::vector<std::string> Description;
|
||||
};
|
||||
|
||||
// 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
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Corpse.h"
|
||||
#include "Player.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "GossipDef.h"
|
||||
#include "World.h"
|
||||
|
||||
Corpse::Corpse(CorpseType type) : WorldObject()
|
||||
, m_type(type)
|
||||
{
|
||||
m_objectType |= TYPEMASK_CORPSE;
|
||||
m_objectTypeId = TYPEID_CORPSE;
|
||||
|
||||
m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION);
|
||||
|
||||
m_valuesCount = CORPSE_END;
|
||||
|
||||
m_time = time(NULL);
|
||||
|
||||
lootForBody = false;
|
||||
|
||||
if (type != CORPSE_BONES)
|
||||
m_isWorldObject = true;
|
||||
}
|
||||
|
||||
Corpse::~Corpse()
|
||||
{
|
||||
}
|
||||
|
||||
void Corpse::AddToWorld()
|
||||
{
|
||||
///- Register the corpse for guid lookup
|
||||
if (!IsInWorld())
|
||||
ObjectAccessor::Instance().AddObject(this);
|
||||
|
||||
Object::AddToWorld();
|
||||
}
|
||||
|
||||
void Corpse::RemoveFromWorld()
|
||||
{
|
||||
///- Remove the corpse from the accessor
|
||||
if (IsInWorld())
|
||||
ObjectAccessor::Instance().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(), 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());
|
||||
|
||||
SetFloatValue(OBJECT_FIELD_SCALE_X, 1);
|
||||
SetUInt64Value(CORPSE_FIELD_OWNER, owner->GetGUID());
|
||||
|
||||
m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Corpse::SaveToDB()
|
||||
{
|
||||
// prevent DB data inconsistence problems and duplicates
|
||||
CharacterDatabase.BeginTransaction();
|
||||
DeleteFromDB();
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES ("
|
||||
<< GetGUIDLow() << ", "
|
||||
<< GUID_LOPART(GetOwnerGUID()) << ", "
|
||||
<< GetPositionX() << ", "
|
||||
<< GetPositionY() << ", "
|
||||
<< GetPositionZ() << ", "
|
||||
<< GetOrientation() << ", "
|
||||
<< GetZoneId() << ", "
|
||||
<< GetMapId() << ", '";
|
||||
for (uint16 i = 0; i < m_valuesCount; ++i)
|
||||
ss << GetUInt32Value(i) << " ";
|
||||
ss << "',"
|
||||
<< uint64(m_time) <<", "
|
||||
<< uint32(GetType()) << ", "
|
||||
<< int(GetInstanceId()) << ", "
|
||||
<< uint16(GetPhaseMask()) << ")"; // prevent out of range error
|
||||
CharacterDatabase.Execute(ss.str().c_str());
|
||||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
void Corpse::DeleteBonesFromWorld()
|
||||
{
|
||||
assert(GetType() == CORPSE_BONES);
|
||||
Corpse* corpse = ObjectAccessor::GetCorpse(*this, GetGUID());
|
||||
|
||||
if (!corpse)
|
||||
{
|
||||
sLog.outError("Bones %u not found in world.", GetGUIDLow());
|
||||
return;
|
||||
}
|
||||
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
void Corpse::DeleteFromDB()
|
||||
{
|
||||
if (GetType() == CORPSE_BONES)
|
||||
// only specific bones
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%d'", GetGUIDLow());
|
||||
else
|
||||
// all corpses (not bones)
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE player = '%d' AND corpse_type <> '0'", GUID_LOPART(GetOwnerGUID()));
|
||||
}
|
||||
|
||||
/*
|
||||
bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId)
|
||||
{
|
||||
bool external = (result != NULL);
|
||||
if (!external)
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance,phaseMask FROM corpse WHERE guid = '%u'",guid);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog.outError("Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid);
|
||||
return false;
|
||||
}
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
if (!LoadFromDB(guid, fields))
|
||||
{
|
||||
if (!external)
|
||||
delete result;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!external)
|
||||
delete result;
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
bool Corpse::LoadFromDB(uint32 guid, Field *fields)
|
||||
{
|
||||
float positionX = fields[0].GetFloat();
|
||||
float positionY = fields[1].GetFloat();
|
||||
float positionZ = fields[2].GetFloat();
|
||||
float ort = fields[3].GetFloat();
|
||||
uint32 mapid = fields[4].GetUInt32();
|
||||
|
||||
Object::_Create(guid, 0, HIGHGUID_CORPSE);
|
||||
|
||||
if (!LoadValues(fields[5].GetString()))
|
||||
{
|
||||
sLog.outError("Corpse #%d have broken data in `data` field. Can't be loaded.",guid);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_time = time_t(fields[6].GetUInt64());
|
||||
m_type = CorpseType(fields[7].GetUInt32());
|
||||
|
||||
if (m_type >= MAX_CORPSE_TYPE)
|
||||
{
|
||||
sLog.outError("Corpse (guidlow %d, owner %d) have wrong corpse type, not load.",GetGUIDLow(),GUID_LOPART(GetOwnerGUID()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_type != CORPSE_BONES)
|
||||
m_isWorldObject = true;
|
||||
|
||||
uint32 instanceid = fields[8].GetUInt32();
|
||||
|
||||
uint32 phaseMask = fields[9].GetUInt32();
|
||||
|
||||
// overwrite possible wrong/corrupted guid
|
||||
SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE));
|
||||
|
||||
// place
|
||||
SetLocationInstanceId(instanceid);
|
||||
SetLocationMapId(mapid);
|
||||
SetPhaseMask(phaseMask, false);
|
||||
Relocate(positionX, positionY, positionZ, ort);
|
||||
|
||||
if (!IsPositionValid())
|
||||
{
|
||||
sLog.outError("Corpse (guidlow %d, owner %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
|
||||
GetGUIDLow(), GUID_LOPART(GetOwnerGUID()), GetPositionX(), GetPositionY());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const
|
||||
{
|
||||
return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u->m_seer, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_CORPSE_H
|
||||
#define TRINITYCORE_CORPSE_H
|
||||
|
||||
#include "Object.h"
|
||||
#include "Database/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 LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId);
|
||||
bool LoadFromDB(uint32 guid, Field *fields);
|
||||
|
||||
void DeleteBonesFromWorld();
|
||||
void DeleteFromDB();
|
||||
|
||||
uint64 const& 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; }
|
||||
|
||||
GridPair const& GetGrid() const { return m_grid; }
|
||||
void SetGrid(GridPair const& grid) { m_grid = grid; }
|
||||
|
||||
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
|
||||
|
||||
Loot loot; // remove insignia ONLY at BG
|
||||
Player* lootRecipient;
|
||||
bool lootForBody;
|
||||
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
|
||||
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
|
||||
void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
|
||||
|
||||
private:
|
||||
CorpseType m_type;
|
||||
time_t m_time;
|
||||
GridPair m_grid; // gride for corpse position for fast search
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "Opcodes.h"
|
||||
#include "World.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
|
||||
DynamicObject::DynamicObject() : WorldObject()
|
||||
{
|
||||
m_objectType |= TYPEMASK_DYNAMICOBJECT;
|
||||
m_objectTypeId = TYPEID_DYNAMICOBJECT;
|
||||
|
||||
m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION);
|
||||
|
||||
m_valuesCount = DYNAMICOBJECT_END;
|
||||
|
||||
m_aura = 0;
|
||||
m_duration = 0;
|
||||
}
|
||||
|
||||
void DynamicObject::AddToWorld()
|
||||
{
|
||||
///- Register the dynamicObject for guid lookup
|
||||
if (!IsInWorld())
|
||||
{
|
||||
ObjectAccessor::Instance().AddObject(this);
|
||||
WorldObject::AddToWorld();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveFromWorld()
|
||||
{
|
||||
///- Remove the dynamicObject from the accessor
|
||||
if (IsInWorld())
|
||||
{
|
||||
if (m_isWorldObject)
|
||||
{
|
||||
if (Unit *caster = GetCaster())
|
||||
{
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
caster->ToPlayer()->SetViewpoint(this, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outCrash("DynamicObject::RemoveFromWorld cannot find viewpoint owner");
|
||||
}
|
||||
}
|
||||
WorldObject::RemoveFromWorld();
|
||||
ObjectAccessor::Instance().RemoveObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool DynamicObject::Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active)
|
||||
{
|
||||
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);
|
||||
SetFloatValue(OBJECT_FIELD_SCALE_X, 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...
|
||||
SetUInt32Value(DYNAMICOBJECT_BYTES, 0x00000001);
|
||||
SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId);
|
||||
SetFloatValue(DYNAMICOBJECT_RADIUS, radius);
|
||||
SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime());
|
||||
|
||||
m_isWorldObject = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* DynamicObject::GetCaster() const
|
||||
{
|
||||
// can be not found in some cases
|
||||
return ObjectAccessor::GetUnit(*this, GetCasterGUID());
|
||||
}
|
||||
|
||||
void DynamicObject::Update(uint32 p_time)
|
||||
{
|
||||
// caster can be not in world at time dynamic object update, but dynamic object not yet deleted in Unit destructor
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster)
|
||||
{
|
||||
Delete();
|
||||
return;
|
||||
}
|
||||
|
||||
bool expired = false;
|
||||
|
||||
if (m_aura)
|
||||
{
|
||||
if (!m_aura->IsRemoved())
|
||||
m_aura->UpdateOwner(p_time, this);
|
||||
|
||||
// m_aura may be set to null in Unit::RemoveGameObject call
|
||||
if (m_aura && (m_aura->IsRemoved() || m_aura->IsExpired()))
|
||||
expired = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetDuration() > int32(p_time))
|
||||
m_duration -= p_time;
|
||||
else
|
||||
expired = true;
|
||||
}
|
||||
|
||||
if (expired)
|
||||
{
|
||||
caster->RemoveDynObjectWithGUID(GetGUID());
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::Delete()
|
||||
{
|
||||
if (m_aura)
|
||||
{
|
||||
// dynObj may be removed in Aura::Remove - we cannot delete there
|
||||
// so recheck aura here
|
||||
if (!m_aura->IsRemoved())
|
||||
m_aura->_Remove(AURA_REMOVE_BY_DEFAULT);
|
||||
delete m_aura;
|
||||
m_aura = NULL;
|
||||
}
|
||||
SendObjectDeSpawnAnim(GetGUID());
|
||||
RemoveFromWorld();
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
int32 DynamicObject::GetDuration() const
|
||||
{
|
||||
if (!m_aura)
|
||||
return m_duration;
|
||||
else
|
||||
return m_aura->GetDuration();
|
||||
}
|
||||
|
||||
void DynamicObject::SetDuration(int32 newDuration)
|
||||
{
|
||||
if (!m_aura)
|
||||
m_duration = newDuration;
|
||||
else
|
||||
m_aura->SetDuration(newDuration);
|
||||
}
|
||||
|
||||
void DynamicObject::Delay(int32 delaytime)
|
||||
{
|
||||
SetDuration(GetDuration() - delaytime);
|
||||
}
|
||||
|
||||
bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const
|
||||
{
|
||||
return IsInWorld() && u->IsInWorld()
|
||||
&& (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false));
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_DYNAMICOBJECT_H
|
||||
#define TRINITYCORE_DYNAMICOBJECT_H
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Unit;
|
||||
class Aura;
|
||||
struct SpellEntry;
|
||||
|
||||
class DynamicObject : public WorldObject, public GridObject<DynamicObject>
|
||||
{
|
||||
public:
|
||||
explicit DynamicObject();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active);
|
||||
void Update(uint32 p_time);
|
||||
void Delete();
|
||||
void SetDuration(int32 newDuration);
|
||||
int32 GetDuration() const;
|
||||
void SetAura(Aura * aura) {assert (!m_aura && aura); m_aura = aura;}
|
||||
void Delay(int32 delaytime);
|
||||
uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); }
|
||||
uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); }
|
||||
float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); }
|
||||
Unit* GetCaster() const;
|
||||
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
|
||||
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
|
||||
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
|
||||
void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
|
||||
|
||||
protected:
|
||||
int32 m_duration; // for non-aura dynobjects
|
||||
Aura * m_aura;
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,743 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _OBJECT_H
|
||||
#define _OBJECT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "UpdateFields.h"
|
||||
#include "UpdateData.h"
|
||||
#include "GameSystem/GridReference.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "GridDefines.h"
|
||||
#include "Map.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#define CONTACT_DISTANCE 0.5f
|
||||
#define INTERACTION_DISTANCE 5.0f
|
||||
#define ATTACK_DISTANCE 5.0f
|
||||
#define MAX_VISIBILITY_DISTANCE 333.0f // max distance for visible object show, limited in 333 yards
|
||||
#define DEFAULT_VISIBILITY_DISTANCE 90.0f // default visible distance, 90 yards on continents
|
||||
#define DEFAULT_VISIBILITY_INSTANCE 120.0f // default visible distance in instances, 120 yards
|
||||
#define DEFAULT_VISIBILITY_BGARENAS 180.0f // default visible distance in BG/Arenas, 180 yards
|
||||
|
||||
#define DEFAULT_WORLD_OBJECT_SIZE 0.388999998569489f // player size, also currently used (correctly?) for any non Unit world objects
|
||||
#define DEFAULT_COMBAT_REACH 1.5f
|
||||
#define MIN_MELEE_REACH 2.0f
|
||||
#define NOMINAL_MELEE_RANGE 5.0f
|
||||
#define MELEE_RANGE (NOMINAL_MELEE_RANGE - MIN_MELEE_REACH * 2) //center to center for players
|
||||
|
||||
enum TypeMask
|
||||
{
|
||||
TYPEMASK_OBJECT = 0x0001,
|
||||
TYPEMASK_ITEM = 0x0002,
|
||||
TYPEMASK_CONTAINER = 0x0006, // TYPEMASK_ITEM | 0x0004
|
||||
TYPEMASK_UNIT = 0x0008, //creature or player
|
||||
TYPEMASK_PLAYER = 0x0010,
|
||||
TYPEMASK_GAMEOBJECT = 0x0020,
|
||||
TYPEMASK_DYNAMICOBJECT = 0x0040,
|
||||
TYPEMASK_CORPSE = 0x0080,
|
||||
TYPEMASK_SEER = TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT
|
||||
};
|
||||
|
||||
enum TypeID
|
||||
{
|
||||
TYPEID_OBJECT = 0,
|
||||
TYPEID_ITEM = 1,
|
||||
TYPEID_CONTAINER = 2,
|
||||
TYPEID_UNIT = 3,
|
||||
TYPEID_PLAYER = 4,
|
||||
TYPEID_GAMEOBJECT = 5,
|
||||
TYPEID_DYNAMICOBJECT = 6,
|
||||
TYPEID_CORPSE = 7
|
||||
};
|
||||
|
||||
#define NUM_CLIENT_OBJECT_TYPES 8
|
||||
|
||||
uint32 GuidHigh2TypeId(uint32 guid_hi);
|
||||
|
||||
enum TempSummonType
|
||||
{
|
||||
TEMPSUMMON_TIMED_OR_DEAD_DESPAWN = 1, // despawns after a specified time OR when the creature disappears
|
||||
TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN = 2, // despawns after a specified time OR when the creature dies
|
||||
TEMPSUMMON_TIMED_DESPAWN = 3, // despawns after a specified time
|
||||
TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT = 4, // despawns after a specified time after the creature is out of combat
|
||||
TEMPSUMMON_CORPSE_DESPAWN = 5, // despawns instantly after death
|
||||
TEMPSUMMON_CORPSE_TIMED_DESPAWN = 6, // despawns after a specified time after death
|
||||
TEMPSUMMON_DEAD_DESPAWN = 7, // despawns when the creature disappears
|
||||
TEMPSUMMON_MANUAL_DESPAWN = 8 // despawns when UnSummon() is called
|
||||
};
|
||||
|
||||
enum PhaseMasks
|
||||
{
|
||||
PHASEMASK_NORMAL = 0x00000001,
|
||||
PHASEMASK_ANYWHERE = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum NotifyFlags
|
||||
{
|
||||
NOTIFY_NONE = 0x00,
|
||||
NOTIFY_AI_RELOCATION = 0x01,
|
||||
NOTIFY_VISIBILITY_CHANGED = 0x02,
|
||||
NOTIFY_ALL = 0xFF
|
||||
};
|
||||
|
||||
class WorldPacket;
|
||||
class UpdateData;
|
||||
class ByteBuffer;
|
||||
class WorldSession;
|
||||
class Creature;
|
||||
class Player;
|
||||
class UpdateMask;
|
||||
class InstanceData;
|
||||
class GameObject;
|
||||
class TempSummon;
|
||||
class Vehicle;
|
||||
class CreatureAI;
|
||||
class ZoneScript;
|
||||
class Unit;
|
||||
|
||||
typedef UNORDERED_MAP<Player*, UpdateData> UpdateDataMapType;
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
virtual ~Object ();
|
||||
|
||||
const bool IsInWorld() const { return m_inWorld; }
|
||||
virtual void AddToWorld()
|
||||
{
|
||||
if (m_inWorld)
|
||||
return;
|
||||
|
||||
assert(m_uint32Values);
|
||||
|
||||
m_inWorld = true;
|
||||
|
||||
// synchronize values mirror with values array (changes will send in updatecreate opcode any way
|
||||
ClearUpdateMask(true);
|
||||
}
|
||||
virtual void RemoveFromWorld()
|
||||
{
|
||||
if (!m_inWorld)
|
||||
return;
|
||||
|
||||
m_inWorld = false;
|
||||
|
||||
// if we remove from world then sending changes not required
|
||||
ClearUpdateMask(true);
|
||||
}
|
||||
|
||||
const uint64& GetGUID() const { return GetUInt64Value(0); }
|
||||
uint32 GetGUIDLow() const { return GUID_LOPART(GetUInt64Value(0)); }
|
||||
uint32 GetGUIDMid() const { return GUID_ENPART(GetUInt64Value(0)); }
|
||||
uint32 GetGUIDHigh() const { return GUID_HIPART(GetUInt64Value(0)); }
|
||||
const ByteBuffer& GetPackGUID() const { return m_PackGUID; }
|
||||
uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); }
|
||||
void SetEntry(uint32 entry) { SetUInt32Value(OBJECT_FIELD_ENTRY, entry); }
|
||||
|
||||
TypeID GetTypeId() const { return m_objectTypeId; }
|
||||
bool isType(uint16 mask) const { return (mask & m_objectType); }
|
||||
|
||||
virtual void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const;
|
||||
void SendUpdateToPlayer(Player* player);
|
||||
|
||||
void BuildValuesUpdateBlockForPlayer(UpdateData *data, Player *target) const;
|
||||
void BuildOutOfRangeUpdateBlock(UpdateData *data) const;
|
||||
void BuildMovementUpdateBlock(UpdateData * data, uint32 flags = 0) const;
|
||||
|
||||
virtual void DestroyForPlayer(Player *target, bool anim = false) const;
|
||||
|
||||
const int32& GetInt32Value(uint16 index) const
|
||||
{
|
||||
ASSERT(index < m_valuesCount || PrintIndexError(index , false));
|
||||
return m_int32Values[ index ];
|
||||
}
|
||||
|
||||
const uint32& GetUInt32Value(uint16 index) const
|
||||
{
|
||||
ASSERT(index < m_valuesCount || PrintIndexError(index , false));
|
||||
return m_uint32Values[ index ];
|
||||
}
|
||||
|
||||
const uint64& GetUInt64Value(uint16 index) const
|
||||
{
|
||||
ASSERT(index + 1 < m_valuesCount || PrintIndexError(index , false));
|
||||
return *((uint64*)&(m_uint32Values[ index ]));
|
||||
}
|
||||
|
||||
const float& GetFloatValue(uint16 index) const
|
||||
{
|
||||
ASSERT(index < m_valuesCount || PrintIndexError(index , false));
|
||||
return m_floatValues[ index ];
|
||||
}
|
||||
|
||||
uint8 GetByteValue(uint16 index, uint8 offset) const
|
||||
{
|
||||
ASSERT(index < m_valuesCount || PrintIndexError(index , false));
|
||||
ASSERT(offset < 4);
|
||||
return *(((uint8*)&m_uint32Values[ index ])+offset);
|
||||
}
|
||||
|
||||
uint16 GetUInt16Value(uint16 index, uint8 offset) const
|
||||
{
|
||||
ASSERT(index < m_valuesCount || PrintIndexError(index , false));
|
||||
ASSERT(offset < 2);
|
||||
return *(((uint16*)&m_uint32Values[ index ])+offset);
|
||||
}
|
||||
|
||||
void SetInt32Value(uint16 index, int32 value);
|
||||
void SetUInt32Value(uint16 index, uint32 value);
|
||||
void UpdateUInt32Value(uint16 index, uint32 value);
|
||||
void SetUInt64Value(uint16 index, const uint64 &value);
|
||||
void SetFloatValue(uint16 index, float value);
|
||||
void SetByteValue(uint16 index, uint8 offset, uint8 value);
|
||||
void SetUInt16Value(uint16 index, uint8 offset, uint16 value);
|
||||
void SetInt16Value(uint16 index, uint8 offset, int16 value) { SetUInt16Value(index,offset,(uint16)value); }
|
||||
void SetStatFloatValue(uint16 index, float value);
|
||||
void SetStatInt32Value(uint16 index, int32 value);
|
||||
|
||||
bool AddUInt64Value(uint16 index, const uint64 &value);
|
||||
bool RemoveUInt64Value(uint16 index, const uint64 &value);
|
||||
|
||||
void ApplyModUInt32Value(uint16 index, int32 val, bool apply);
|
||||
void ApplyModInt32Value(uint16 index, int32 val, bool apply);
|
||||
void ApplyModUInt64Value(uint16 index, int32 val, bool apply);
|
||||
void ApplyModPositiveFloatValue(uint16 index, float val, bool apply);
|
||||
void ApplyModSignedFloatValue(uint16 index, float val, bool apply);
|
||||
|
||||
void ApplyPercentModFloatValue(uint16 index, float val, bool apply)
|
||||
{
|
||||
val = val != -100.0f ? val : -99.9f ;
|
||||
SetFloatValue(index, GetFloatValue(index) * (apply?(100.0f+val)/100.0f : 100.0f / (100.0f+val)));
|
||||
}
|
||||
|
||||
void SetFlag(uint16 index, uint32 newFlag);
|
||||
void RemoveFlag(uint16 index, uint32 oldFlag);
|
||||
|
||||
void ToggleFlag(uint16 index, uint32 flag)
|
||||
{
|
||||
if (HasFlag(index, flag))
|
||||
RemoveFlag(index, flag);
|
||||
else
|
||||
SetFlag(index, flag);
|
||||
}
|
||||
|
||||
bool HasFlag(uint16 index, uint32 flag) const
|
||||
{
|
||||
if (index >= m_valuesCount && !PrintIndexError(index , false)) return false;
|
||||
return (m_uint32Values[ index ] & flag) != 0;
|
||||
}
|
||||
|
||||
void SetByteFlag(uint16 index, uint8 offset, uint8 newFlag);
|
||||
void RemoveByteFlag(uint16 index, uint8 offset, uint8 newFlag);
|
||||
|
||||
void ToggleFlag(uint16 index, uint8 offset, uint8 flag)
|
||||
{
|
||||
if (HasByteFlag(index, offset, flag))
|
||||
RemoveByteFlag(index, offset, flag);
|
||||
else
|
||||
SetByteFlag(index, offset, flag);
|
||||
}
|
||||
|
||||
bool HasByteFlag(uint16 index, uint8 offset, uint8 flag) const
|
||||
{
|
||||
ASSERT(index < m_valuesCount || PrintIndexError(index , false));
|
||||
ASSERT(offset < 4);
|
||||
return (((uint8*)&m_uint32Values[index])[offset] & flag) != 0;
|
||||
}
|
||||
|
||||
void ApplyModFlag(uint16 index, uint32 flag, bool apply)
|
||||
{
|
||||
if (apply) SetFlag(index,flag); else RemoveFlag(index,flag);
|
||||
}
|
||||
|
||||
void SetFlag64(uint16 index, uint64 newFlag)
|
||||
{
|
||||
uint64 oldval = GetUInt64Value(index);
|
||||
uint64 newval = oldval | newFlag;
|
||||
SetUInt64Value(index,newval);
|
||||
}
|
||||
|
||||
void RemoveFlag64(uint16 index, uint64 oldFlag)
|
||||
{
|
||||
uint64 oldval = GetUInt64Value(index);
|
||||
uint64 newval = oldval & ~oldFlag;
|
||||
SetUInt64Value(index,newval);
|
||||
}
|
||||
|
||||
void ToggleFlag64(uint16 index, uint64 flag)
|
||||
{
|
||||
if (HasFlag64(index, flag))
|
||||
RemoveFlag64(index, flag);
|
||||
else
|
||||
SetFlag64(index, flag);
|
||||
}
|
||||
|
||||
bool HasFlag64(uint16 index, uint64 flag) const
|
||||
{
|
||||
ASSERT(index < m_valuesCount || PrintIndexError(index , false));
|
||||
return (GetUInt64Value(index) & flag) != 0;
|
||||
}
|
||||
|
||||
void ApplyModFlag64(uint16 index, uint64 flag, bool apply)
|
||||
{
|
||||
if (apply) SetFlag64(index,flag); else RemoveFlag64(index,flag);
|
||||
}
|
||||
|
||||
void ClearUpdateMask(bool remove);
|
||||
|
||||
bool LoadValues(const char* data);
|
||||
|
||||
uint16 GetValuesCount() const { return m_valuesCount; }
|
||||
|
||||
virtual bool hasQuest(uint32 /* quest_id */) const { return false; }
|
||||
virtual bool hasInvolvedQuest(uint32 /* quest_id */) const { return false; }
|
||||
virtual void BuildUpdate(UpdateDataMapType&) {}
|
||||
void BuildFieldsUpdate(Player *, UpdateDataMapType &) const;
|
||||
|
||||
// FG: some hacky helpers
|
||||
void ForceValuesUpdateAtIndex(uint32);
|
||||
|
||||
Player* ToPlayer(){ if (GetTypeId() == TYPEID_PLAYER) return reinterpret_cast<Player*>(this); else return NULL; }
|
||||
const Player* ToPlayer() const { if (GetTypeId() == TYPEID_PLAYER) return (const Player*)((Player*)this); else return NULL; }
|
||||
Creature* ToCreature(){ if (GetTypeId() == TYPEID_UNIT) return reinterpret_cast<Creature*>(this); else return NULL; }
|
||||
const Creature* ToCreature() const {if (GetTypeId() == TYPEID_UNIT) return (const Creature*)((Creature*)this); else return NULL; }
|
||||
|
||||
protected:
|
||||
|
||||
Object ();
|
||||
|
||||
void _InitValues();
|
||||
void _Create (uint32 guidlow, uint32 entry, HighGuid guidhigh);
|
||||
|
||||
virtual void _SetUpdateBits(UpdateMask *updateMask, Player *target) const;
|
||||
|
||||
virtual void _SetCreateBits(UpdateMask *updateMask, Player *target) const;
|
||||
void _BuildMovementUpdate(ByteBuffer * data, uint16 flags) const;
|
||||
void _BuildValuesUpdate(uint8 updatetype, ByteBuffer *data, UpdateMask *updateMask, Player *target) const;
|
||||
|
||||
uint16 m_objectType;
|
||||
|
||||
TypeID m_objectTypeId;
|
||||
uint16 m_updateFlag;
|
||||
|
||||
union
|
||||
{
|
||||
int32 *m_int32Values;
|
||||
uint32 *m_uint32Values;
|
||||
float *m_floatValues;
|
||||
};
|
||||
|
||||
uint32 *m_uint32Values_mirror;
|
||||
|
||||
uint16 m_valuesCount;
|
||||
|
||||
bool m_objectUpdated;
|
||||
|
||||
private:
|
||||
bool m_inWorld;
|
||||
|
||||
ByteBuffer m_PackGUID;
|
||||
|
||||
// for output helpfull error messages from asserts
|
||||
bool PrintIndexError(uint32 index, bool set) const;
|
||||
Object(const Object&); // prevent generation copy constructor
|
||||
Object& operator=(Object const&); // prevent generation assigment operator
|
||||
};
|
||||
|
||||
struct Position
|
||||
{
|
||||
float m_positionX;
|
||||
float m_positionY;
|
||||
float m_positionZ;
|
||||
float m_orientation;
|
||||
|
||||
void Relocate(float x, float y)
|
||||
{ m_positionX = x; m_positionY = y;}
|
||||
void Relocate(float x, float y, float z)
|
||||
{ m_positionX = x; m_positionY = y; m_positionZ = z; }
|
||||
void Relocate(float x, float y, float z, float orientation)
|
||||
{ m_positionX = x; m_positionY = y; m_positionZ = z; m_orientation = orientation; }
|
||||
void Relocate(const Position &pos)
|
||||
{ m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; m_orientation = pos.m_orientation; }
|
||||
void Relocate(const Position *pos)
|
||||
{ m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; m_orientation = pos->m_orientation; }
|
||||
void SetOrientation(float orientation)
|
||||
{ m_orientation = orientation; }
|
||||
|
||||
float GetPositionX() const { return m_positionX; }
|
||||
float GetPositionY() const { return m_positionY; }
|
||||
float GetPositionZ() const { return m_positionZ; }
|
||||
float GetOrientation() const { return m_orientation; }
|
||||
|
||||
void GetPosition(float &x, float &y) const
|
||||
{ x = m_positionX; y = m_positionY; }
|
||||
void GetPosition(float &x, float &y, float &z) const
|
||||
{ x = m_positionX; y = m_positionY; z = m_positionZ; }
|
||||
void GetPosition(float &x, float &y, float &z, float &o) const
|
||||
{ x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; }
|
||||
void GetPosition(Position *pos) const
|
||||
{
|
||||
if (pos)
|
||||
pos->Relocate(m_positionX, m_positionY, m_positionZ, m_orientation);
|
||||
}
|
||||
|
||||
bool IsPositionValid() const;
|
||||
|
||||
float GetExactDist2dSq(float x, float y) const
|
||||
{ float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; }
|
||||
float GetExactDist2d(const float x, const float y) const
|
||||
{ return sqrt(GetExactDist2dSq(x, y)); }
|
||||
float GetExactDist2dSq(const Position *pos) const
|
||||
{ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; }
|
||||
float GetExactDist2d(const Position *pos) const
|
||||
{ return sqrt(GetExactDist2dSq(pos)); }
|
||||
float GetExactDistSq(float x, float y, float z) const
|
||||
{ float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; }
|
||||
float GetExactDist(float x, float y, float z) const
|
||||
{ return sqrt(GetExactDistSq(x, y, z)); }
|
||||
float GetExactDistSq(const Position *pos) const
|
||||
{ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; }
|
||||
float GetExactDist(const Position *pos) const
|
||||
{ return sqrt(GetExactDistSq(pos)); }
|
||||
|
||||
float GetAngle(const Position *pos) const;
|
||||
float GetAngle(float x, float y) const;
|
||||
float GetRelativeAngle(const Position *pos) const
|
||||
{ return GetAngle(pos) - m_orientation; }
|
||||
float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
|
||||
void GetSinCos(float x, float y, float &vsin, float &vcos) const;
|
||||
|
||||
bool IsInDist2d(float x, float y, float dist) const
|
||||
{ return GetExactDist2dSq(x, y) < dist * dist; }
|
||||
bool IsInDist2d(const Position *pos, float dist) const
|
||||
{ return GetExactDist2dSq(pos) < dist * dist; }
|
||||
bool IsInDist(float x, float y, float z, float dist) const
|
||||
{ return GetExactDistSq(x, y, z) < dist * dist; }
|
||||
bool IsInDist(const Position *pos, float dist) const
|
||||
{ return GetExactDistSq(pos) < dist * dist; }
|
||||
bool HasInArc(float arcangle, const Position *pos) const;
|
||||
bool HasInLine(const Unit *target, float distance, float width) const;
|
||||
};
|
||||
|
||||
#define MAPID_INVALID 0xFFFFFFFF
|
||||
|
||||
class WorldLocation : public Position
|
||||
{
|
||||
public:
|
||||
explicit WorldLocation(uint32 _mapid = MAPID_INVALID, float _x = 0, float _y = 0, float _z = 0, float _o = 0)
|
||||
: m_mapId(_mapid) { Relocate(_x, _y, _z, _o); }
|
||||
WorldLocation(const WorldLocation &loc) { WorldRelocate(loc); }
|
||||
|
||||
void WorldRelocate(const WorldLocation &loc)
|
||||
{ m_mapId = loc.GetMapId(); Relocate(loc); }
|
||||
uint32 GetMapId() const { return m_mapId; }
|
||||
|
||||
uint32 m_mapId;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class GridObject
|
||||
{
|
||||
public:
|
||||
GridReference<T> &GetGridRef() { return m_gridRef; }
|
||||
protected:
|
||||
GridReference<T> m_gridRef;
|
||||
};
|
||||
|
||||
class WorldObject : public Object, public WorldLocation
|
||||
{
|
||||
public:
|
||||
virtual ~WorldObject();
|
||||
|
||||
virtual void Update (uint32 /*time_diff*/) { }
|
||||
|
||||
void _Create(uint32 guidlow, HighGuid guidhigh, uint32 phaseMask);
|
||||
|
||||
void GetNearPoint2D(float &x, float &y, float distance, float absAngle) const;
|
||||
void GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d,float absAngle) const;
|
||||
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d = 0, float angle = 0) const
|
||||
{
|
||||
// angle calculated from current orientation
|
||||
GetNearPoint(NULL,x,y,z,size,distance2d,GetOrientation() + angle);
|
||||
}
|
||||
void MovePosition(Position &pos, float dist, float angle);
|
||||
void GetNearPosition(Position &pos, float dist, float angle)
|
||||
{
|
||||
GetPosition(&pos);
|
||||
MovePosition(pos, dist, angle);
|
||||
}
|
||||
void GetRandomNearPosition(Position &pos, float radius)
|
||||
{
|
||||
GetPosition(&pos);
|
||||
MovePosition(pos, radius * rand_norm(), rand_norm() * 2 * M_PI);
|
||||
}
|
||||
|
||||
void GetContactPoint(const WorldObject* obj, float &x, float &y, float &z, float distance2d = CONTACT_DISTANCE) const
|
||||
{
|
||||
// angle to face `obj` to `this` using distance includes size of `obj`
|
||||
GetNearPoint(obj,x,y,z,obj->GetObjectSize(),distance2d,GetAngle(obj));
|
||||
}
|
||||
|
||||
float GetObjectSize() const
|
||||
{
|
||||
return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE;
|
||||
}
|
||||
void UpdateGroundPositionZ(float x, float y, float &z) const;
|
||||
|
||||
void GetRandomPoint(const Position &srcPos, float distance, float &rand_x, float &rand_y, float &rand_z) const;
|
||||
void GetRandomPoint(const Position &srcPos, float distance, Position &pos) const
|
||||
{
|
||||
float x, y, z;
|
||||
GetRandomPoint(srcPos, distance, x, y, z);
|
||||
pos.Relocate(x, y, z, GetOrientation());
|
||||
}
|
||||
|
||||
uint32 GetInstanceId() const { return m_InstanceId; }
|
||||
|
||||
virtual void SetPhaseMask(uint32 newPhaseMask, bool update);
|
||||
uint32 GetPhaseMask() const { return m_phaseMask; }
|
||||
bool InSamePhase(WorldObject const* obj) const { return InSamePhase(obj->GetPhaseMask()); }
|
||||
bool InSamePhase(uint32 phasemask) const { return (GetPhaseMask() & phasemask); }
|
||||
|
||||
uint32 GetZoneId() const;
|
||||
uint32 GetAreaId() const;
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const;
|
||||
|
||||
InstanceData* GetInstanceData();
|
||||
|
||||
const char* GetName() const { return m_name.c_str(); }
|
||||
void SetName(const std::string& newname) { m_name=newname; }
|
||||
|
||||
virtual const char* GetNameForLocaleIdx(int32 /*locale_idx*/) const { return GetName(); }
|
||||
|
||||
float GetDistance(const WorldObject *obj) const
|
||||
{
|
||||
float d = GetExactDist(obj) - GetObjectSize() - obj->GetObjectSize();
|
||||
return d > 0.0f ? d : 0.0f;
|
||||
}
|
||||
float GetDistance(const Position &pos) const
|
||||
{
|
||||
float d = GetExactDist(&pos) - GetObjectSize();
|
||||
return d > 0.0f ? d : 0.0f;
|
||||
}
|
||||
float GetDistance(float x, float y, float z) const
|
||||
{
|
||||
float d = GetExactDist(x, y, z) - GetObjectSize();
|
||||
return d > 0.0f ? d : 0.0f;
|
||||
}
|
||||
float GetDistance2d(const WorldObject* obj) const
|
||||
{
|
||||
float d = GetExactDist2d(obj) - GetObjectSize() - obj->GetObjectSize();
|
||||
return d > 0.0f ? d : 0.0f;
|
||||
}
|
||||
float GetDistance2d(float x, float y) const
|
||||
{
|
||||
float d = GetExactDist2d(x, y) - GetObjectSize();
|
||||
return d > 0.0f ? d : 0.0f;
|
||||
}
|
||||
float GetDistanceZ(const WorldObject* obj) const;
|
||||
|
||||
bool IsInMap(const WorldObject* obj) const
|
||||
{
|
||||
if (obj)
|
||||
return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
bool IsWithinDist3d(float x, float y, float z, float dist) const
|
||||
{ return IsInDist(x, y, z, dist + GetObjectSize()); }
|
||||
bool IsWithinDist3d(const Position *pos, float dist) const
|
||||
{ return IsInDist(pos, dist + GetObjectSize()); }
|
||||
bool IsWithinDist2d(float x, float y, float dist) const
|
||||
{ return IsInDist2d(x, y, dist + GetObjectSize()); }
|
||||
bool IsWithinDist2d(const Position *pos, float dist) const
|
||||
{ return IsInDist2d(pos, dist + GetObjectSize()); }
|
||||
bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const;
|
||||
// use only if you will sure about placing both object at same map
|
||||
bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const
|
||||
{
|
||||
return obj && _IsWithinDist(obj,dist2compare,is3D);
|
||||
}
|
||||
bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const
|
||||
{
|
||||
return obj && IsInMap(obj) && _IsWithinDist(obj,dist2compare,is3D);
|
||||
}
|
||||
bool IsWithinLOS(float x, float y, float z) const;
|
||||
bool IsWithinLOSInMap(const WorldObject* obj) const;
|
||||
bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const;
|
||||
bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const;
|
||||
bool IsInRange2d(float x, float y, float minRange, float maxRange) const;
|
||||
bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const;
|
||||
bool isInFront(WorldObject const* target,float distance, float arc = M_PI) const;
|
||||
bool isInBack(WorldObject const* target, float distance, float arc = M_PI) const;
|
||||
|
||||
bool IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size = 0) const;
|
||||
|
||||
virtual void CleanupsBeforeDelete(bool finalCleanup = true); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units
|
||||
|
||||
virtual void SendMessageToSet(WorldPacket *data, bool self);
|
||||
virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self);
|
||||
virtual void SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr);
|
||||
|
||||
void MonsterSay(const char* text, uint32 language, uint64 TargetGuid);
|
||||
void MonsterYell(const char* text, uint32 language, uint64 TargetGuid);
|
||||
void MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote = false);
|
||||
void MonsterWhisper(const char* text, uint64 receiver, bool IsBossWhisper = false);
|
||||
void MonsterSay(int32 textId, uint32 language, uint64 TargetGuid);
|
||||
void MonsterYell(int32 textId, uint32 language, uint64 TargetGuid);
|
||||
void MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false);
|
||||
void MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper = false);
|
||||
void MonsterYellToZone(int32 textId, uint32 language, uint64 TargetGuid);
|
||||
void BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 TargetGuid) const;
|
||||
|
||||
void PlayDistanceSound(uint32 sound_id, Player* target = NULL);
|
||||
void PlayDirectSound(uint32 sound_id, Player* target = NULL);
|
||||
|
||||
void SendObjectDeSpawnAnim(uint64 guid);
|
||||
|
||||
virtual void SaveRespawnTime() {}
|
||||
void AddObjectToRemoveList();
|
||||
|
||||
// main visibility check function in normal case (ignore grey zone distance check)
|
||||
bool isVisibleFor(Player const* u) const { return isVisibleForInState(u,false); }
|
||||
|
||||
// low level function for visibility change code, must be define in all main world object subclasses
|
||||
virtual bool isVisibleForInState(Player const* u, bool inVisibleList) const = 0;
|
||||
|
||||
// Low Level Packets
|
||||
void SendPlaySound(uint32 Sound, bool OnlySelf);
|
||||
|
||||
virtual void SetMap(Map * map);
|
||||
virtual void ResetMap();
|
||||
Map * GetMap() const { ASSERT(m_currMap); return m_currMap; }
|
||||
Map * FindMap() const { return m_currMap; }
|
||||
//used to check all object's GetMap() calls when object is not in world!
|
||||
|
||||
//this function should be removed in nearest time...
|
||||
Map const* GetBaseMap() const;
|
||||
|
||||
void SetZoneScript();
|
||||
ZoneScript * GetZoneScript() const { return m_zoneScript; }
|
||||
|
||||
TempSummon* SummonCreature(uint32 id, const Position &pos, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, uint32 vehId = 0) const;
|
||||
TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0)
|
||||
{
|
||||
if (!x && !y && !z)
|
||||
{
|
||||
GetClosePoint(x, y, z, GetObjectSize());
|
||||
ang = GetOrientation();
|
||||
}
|
||||
Position pos = {x, y, z, ang};
|
||||
return SummonCreature(id, pos, spwtype, despwtime, 0);
|
||||
}
|
||||
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime);
|
||||
Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = NULL);
|
||||
|
||||
Creature* FindNearestCreature(uint32 entry, float range, bool alive = true);
|
||||
GameObject* FindNearestGameObject(uint32 entry, float range);
|
||||
|
||||
void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange);
|
||||
void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange);
|
||||
|
||||
void DestroyForNearbyPlayers();
|
||||
virtual void UpdateObjectVisibility(bool forced = true);
|
||||
void BuildUpdate(UpdateDataMapType&);
|
||||
|
||||
//relocation and visibility system functions
|
||||
void AddToNotify(uint16 f) { m_notifyflags |= f;}
|
||||
bool isNeedNotify(uint16 f) const { return m_notifyflags & f;}
|
||||
uint16 GetNotifyFlags() const { return m_notifyflags; }
|
||||
bool NotifyExecuted(uint16 f) const { return m_executed_notifies & f;}
|
||||
void SetNotified(uint16 f) { m_executed_notifies |= f;}
|
||||
void ResetAllNotifies() { m_notifyflags = 0; m_executed_notifies = 0; }
|
||||
|
||||
bool isActiveObject() const { return m_isActive; }
|
||||
void setActive(bool isActiveObject);
|
||||
void SetWorldObject(bool apply);
|
||||
template<class NOTIFIER> void VisitNearbyObject(const float &radius, NOTIFIER ¬ifier) const { GetMap()->VisitAll(GetPositionX(), GetPositionY(), radius, notifier); }
|
||||
template<class NOTIFIER> void VisitNearbyGridObject(const float &radius, NOTIFIER ¬ifier) const { GetMap()->VisitGrid(GetPositionX(), GetPositionY(), radius, notifier); }
|
||||
template<class NOTIFIER> void VisitNearbyWorldObject(const float &radius, NOTIFIER ¬ifier) const { GetMap()->VisitWorld(GetPositionX(), GetPositionY(), radius, notifier); }
|
||||
|
||||
#ifdef MAP_BASED_RAND_GEN
|
||||
int32 irand(int32 min, int32 max) const { return int32 (GetMap()->mtRand.randInt(max - min)) + min; }
|
||||
uint32 urand(uint32 min, uint32 max) const { return GetMap()->mtRand.randInt(max - min) + min;}
|
||||
int32 rand32() const { return GetMap()->mtRand.randInt();}
|
||||
double rand_norm() const { return GetMap()->mtRand.randExc();}
|
||||
double rand_chance() const { return GetMap()->mtRand.randExc(100.0);}
|
||||
#endif
|
||||
|
||||
bool m_isWorldObject;
|
||||
uint32 LastUsedScriptID;
|
||||
protected:
|
||||
explicit WorldObject();
|
||||
std::string m_name;
|
||||
bool m_isActive;
|
||||
ZoneScript *m_zoneScript;
|
||||
|
||||
//these functions are used mostly for Relocate() and Corpse/Player specific stuff...
|
||||
//use them ONLY in LoadFromDB()/Create() funcs and nowhere else!
|
||||
//mapId/instanceId should be set in SetMap() function!
|
||||
void SetLocationMapId(uint32 _mapId) { m_mapId = _mapId; }
|
||||
void SetLocationInstanceId(uint32 _instanceId) { m_InstanceId = _instanceId; }
|
||||
|
||||
private:
|
||||
Map * m_currMap; //current object's Map location
|
||||
|
||||
//uint32 m_mapId; // object at map with map_id
|
||||
uint32 m_InstanceId; // in map copy with instance id
|
||||
uint32 m_phaseMask; // in area phase state
|
||||
|
||||
uint16 m_notifyflags;
|
||||
uint16 m_executed_notifies;
|
||||
};
|
||||
|
||||
namespace Trinity
|
||||
{
|
||||
template<class T>
|
||||
void RandomResizeList(std::list<T> &_list, uint32 _size)
|
||||
{
|
||||
while (_list.size() > _size)
|
||||
{
|
||||
typename std::list<T>::iterator itr = _list.begin();
|
||||
advance(itr, urand(0, _list.size() - 1));
|
||||
_list.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
// Binary predicate to sort WorldObjects based on the distance to a reference WorldObject
|
||||
class ObjectDistanceOrderPred
|
||||
{
|
||||
public:
|
||||
ObjectDistanceOrderPred(const WorldObject *pRefObj, bool ascending = true) : m_refObj(pRefObj), m_ascending(ascending) {}
|
||||
bool operator()(const WorldObject *pLeft, const WorldObject *pRight) const
|
||||
{
|
||||
return m_ascending ? m_refObj->GetDistanceOrder(pLeft, pRight) : !m_refObj->GetDistanceOrder(pLeft, pRight);
|
||||
}
|
||||
private:
|
||||
const WorldObject *m_refObj;
|
||||
const bool m_ascending;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "Player.h"
|
||||
#include "Creature.h"
|
||||
#include "GameObject.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Item.h"
|
||||
#include "Corpse.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "MapManager.h"
|
||||
#include "Map.h"
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "MapInstanced.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define CLASS_LOCK Trinity::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex>
|
||||
INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
|
||||
INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex);
|
||||
|
||||
ObjectAccessor::ObjectAccessor()
|
||||
{
|
||||
}
|
||||
|
||||
ObjectAccessor::~ObjectAccessor()
|
||||
{
|
||||
for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr)
|
||||
{
|
||||
itr->second->RemoveFromWorld();
|
||||
delete itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
Creature* ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const& u, uint64 guid)
|
||||
{
|
||||
if (IS_PLAYER_GUID(guid))
|
||||
return NULL;
|
||||
|
||||
if (IS_PET_GUID(guid))
|
||||
return GetPet(guid);
|
||||
|
||||
return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL;
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::GetCorpse(WorldObject const& u, uint64 guid)
|
||||
{
|
||||
Corpse* ret = GetObjectInWorld(guid, (Corpse*)NULL);
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
if (ret->GetMapId() != u.GetMapId())
|
||||
return NULL;
|
||||
|
||||
if (ret->GetInstanceId() != u.GetInstanceId())
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, uint64 guid)
|
||||
{
|
||||
switch (GUID_HIPART(guid))
|
||||
{
|
||||
case HIGHGUID_PLAYER: return FindPlayer(guid);
|
||||
case HIGHGUID_GAMEOBJECT: return p.GetMap()->GetGameObject(guid);
|
||||
case HIGHGUID_VEHICLE:
|
||||
case HIGHGUID_UNIT: return p.GetMap()->GetCreature(guid);
|
||||
case HIGHGUID_PET: return GetPet(guid);
|
||||
case HIGHGUID_DYNAMICOBJECT: return p.GetMap()->GetDynamicObject(guid);
|
||||
case HIGHGUID_TRANSPORT: return NULL;
|
||||
case HIGHGUID_CORPSE: return GetCorpse(p,guid);
|
||||
case HIGHGUID_MO_TRANSPORT: return NULL;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, uint64 guid, uint32 typemask)
|
||||
{
|
||||
switch (GUID_HIPART(guid))
|
||||
{
|
||||
case HIGHGUID_ITEM:
|
||||
if (typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER)
|
||||
return ((Player const&)p).GetItemByGuid(guid);
|
||||
break;
|
||||
case HIGHGUID_PLAYER:
|
||||
if (typemask & TYPEMASK_PLAYER)
|
||||
return FindPlayer(guid);
|
||||
break;
|
||||
case HIGHGUID_GAMEOBJECT:
|
||||
if (typemask & TYPEMASK_GAMEOBJECT)
|
||||
return p.GetMap()->GetGameObject(guid);
|
||||
break;
|
||||
case HIGHGUID_UNIT:
|
||||
case HIGHGUID_VEHICLE:
|
||||
if (typemask & TYPEMASK_UNIT)
|
||||
return p.GetMap()->GetCreature(guid);
|
||||
break;
|
||||
case HIGHGUID_PET:
|
||||
if (typemask & TYPEMASK_UNIT)
|
||||
return GetPet(guid);
|
||||
break;
|
||||
case HIGHGUID_DYNAMICOBJECT:
|
||||
if (typemask & TYPEMASK_DYNAMICOBJECT)
|
||||
return p.GetMap()->GetDynamicObject(guid);
|
||||
break;
|
||||
case HIGHGUID_TRANSPORT:
|
||||
case HIGHGUID_CORPSE:
|
||||
case HIGHGUID_MO_TRANSPORT:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Player* ObjectAccessor::FindPlayer(uint64 guid)
|
||||
{
|
||||
Player* plr = GetObjectInWorld(guid, (Player*)NULL);
|
||||
if (!plr || !plr->IsInWorld())
|
||||
return NULL;
|
||||
|
||||
return plr;
|
||||
}
|
||||
|
||||
Player* ObjectAccessor::FindPlayerByName(const char* name)
|
||||
{
|
||||
Guard guard(*HashMapHolder<Player>::GetLock());
|
||||
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
|
||||
for (HashMapHolder<Player>::MapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
if (iter->second->IsInWorld() && strcmp(name, iter->second->GetName()) == 0)
|
||||
return iter->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ObjectAccessor::SaveAllPlayers()
|
||||
{
|
||||
Guard guard(*HashMapHolder<Player>::GetLock());
|
||||
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
|
||||
for (HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||
itr->second->SaveToDB();
|
||||
}
|
||||
|
||||
Pet* ObjectAccessor::GetPet(uint64 guid)
|
||||
{
|
||||
return GetObjectInWorld(guid, (Pet*)NULL);
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid)
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid);
|
||||
if (iter == i_player2corpse.end())
|
||||
return NULL;
|
||||
|
||||
assert(iter->second->GetType() != CORPSE_BONES);
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void ObjectAccessor::RemoveCorpse(Corpse* corpse)
|
||||
{
|
||||
assert(corpse && corpse->GetType() != CORPSE_BONES);
|
||||
|
||||
if (corpse->FindMap())
|
||||
corpse->FindMap()->Remove(corpse, false);
|
||||
else
|
||||
corpse->RemoveFromWorld();
|
||||
|
||||
// Critical section
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID());
|
||||
if (iter == i_player2corpse.end()) // TODO: Fix this
|
||||
return;
|
||||
|
||||
// build mapid*cellid -> guid_set map
|
||||
CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
|
||||
|
||||
objmgr.DeleteCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID());
|
||||
|
||||
i_player2corpse.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAccessor::AddCorpse(Corpse* corpse)
|
||||
{
|
||||
assert(corpse && corpse->GetType() != CORPSE_BONES);
|
||||
|
||||
// Critical section
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
assert(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end());
|
||||
i_player2corpse[corpse->GetOwnerGUID()] = corpse;
|
||||
|
||||
// build mapid*cellid -> guid_set map
|
||||
CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
|
||||
|
||||
objmgr.AddCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID(), corpse->GetInstanceId());
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAccessor::AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map)
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter)
|
||||
{
|
||||
if (iter->second->GetGrid() == gridpair)
|
||||
{
|
||||
// verify, if the corpse in our instance (add only corpses which are)
|
||||
if (map->Instanceable())
|
||||
{
|
||||
if (iter->second->GetInstanceId() == map->GetInstanceId())
|
||||
grid.AddWorldObject(iter->second);
|
||||
}
|
||||
else
|
||||
grid.AddWorldObject(iter->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool /*insignia*/)
|
||||
{
|
||||
Corpse* corpse = GetCorpseForPlayerGUID(player_guid);
|
||||
if (!corpse)
|
||||
{
|
||||
//in fact this function is called from several places
|
||||
//even when player doesn't have a corpse, not an error
|
||||
// TODO: really, now...
|
||||
//sLog.outError("Try remove corpse that not in map for GUID %ul", player_guid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Deleting Corpse and spawned bones.");
|
||||
|
||||
//Map* map = corpse->FindMap();
|
||||
|
||||
// remove corpse from player_guid -> corpse map
|
||||
RemoveCorpse(corpse);
|
||||
|
||||
// done in removecorpse
|
||||
// remove resurrectable corpse from grid object registry (loaded state checked into call)
|
||||
// do not load the map if it's not loaded
|
||||
//Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId());
|
||||
//if (map)
|
||||
// map->Remove(corpse, false);
|
||||
|
||||
// remove corpse from DB
|
||||
corpse->DeleteFromDB();
|
||||
|
||||
// we don't want bones to save some cpu.. :)
|
||||
delete corpse;
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
Corpse* bones = NULL;
|
||||
// create the bones only if the map and the grid is loaded at the corpse's location
|
||||
// ignore bones creating option in case insignia
|
||||
if (map && (insignia ||
|
||||
(map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) &&
|
||||
!map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
|
||||
{
|
||||
// Create bones, don't change Corpse
|
||||
bones = new Corpse;
|
||||
bones->Create(corpse->GetGUIDLow(), map);
|
||||
|
||||
for (int i = 3; i < CORPSE_END; ++i) // don't overwrite guid and object type
|
||||
bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
|
||||
|
||||
bones->SetGrid(corpse->GetGrid());
|
||||
// bones->m_time = m_time; // don't overwrite time
|
||||
// bones->m_inWorld = m_inWorld; // don't overwrite in-world state
|
||||
// bones->m_type = m_type; // don't overwrite type
|
||||
bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
|
||||
bones->SetPhaseMask(corpse->GetPhaseMask(), false);
|
||||
|
||||
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
|
||||
bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0);
|
||||
|
||||
for (int i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
|
||||
bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
|
||||
}
|
||||
|
||||
// add bones in grid store if grid loaded where corpse placed
|
||||
map->Add(bones);
|
||||
}
|
||||
|
||||
// all references to the corpse should be removed at this point
|
||||
delete corpse;
|
||||
|
||||
return bones;
|
||||
*/
|
||||
}
|
||||
|
||||
void ObjectAccessor::Update(uint32 /*diff*/)
|
||||
{
|
||||
UpdateDataMapType update_players;
|
||||
|
||||
// Critical section
|
||||
{
|
||||
Guard guard(i_updateGuard);
|
||||
|
||||
while (!i_objects.empty())
|
||||
{
|
||||
Object* obj = *i_objects.begin();
|
||||
assert(obj && obj->IsInWorld());
|
||||
i_objects.erase(i_objects.begin());
|
||||
obj->BuildUpdate(update_players);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
|
||||
for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
|
||||
{
|
||||
iter->second.BuildPacket(&packet);
|
||||
iter->first->GetSession()->SendPacket(&packet);
|
||||
packet.clear(); // clean the string
|
||||
}
|
||||
}
|
||||
|
||||
/// Define the static members of HashMapHolder
|
||||
|
||||
template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap;
|
||||
template <class T> ACE_Thread_Mutex HashMapHolder<T>::i_lock;
|
||||
|
||||
/// Global definitions for the hashmap storage
|
||||
|
||||
template class HashMapHolder<Player>;
|
||||
template class HashMapHolder<Pet>;
|
||||
template class HashMapHolder<GameObject>;
|
||||
template class HashMapHolder<DynamicObject>;
|
||||
template class HashMapHolder<Creature>;
|
||||
template class HashMapHolder<Corpse>;
|
||||
|
||||
template Player* ObjectAccessor::GetObjectInWorld<Player>(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/);
|
||||
template Pet* ObjectAccessor::GetObjectInWorld<Pet>(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/);
|
||||
template Creature* ObjectAccessor::GetObjectInWorld<Creature>(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/);
|
||||
template Corpse* ObjectAccessor::GetObjectInWorld<Corpse>(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/);
|
||||
template GameObject* ObjectAccessor::GetObjectInWorld<GameObject>(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/);
|
||||
template DynamicObject* ObjectAccessor::GetObjectInWorld<DynamicObject>(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/);
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_OBJECTACCESSOR_H
|
||||
#define TRINITY_OBJECTACCESSOR_H
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include <ace/Thread_Mutex.h>
|
||||
#include "Utilities/UnorderedMap.h"
|
||||
#include "Policies/ThreadingModel.h"
|
||||
|
||||
#include "UpdateData.h"
|
||||
|
||||
#include "GridDefines.h"
|
||||
#include "Object.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
class Creature;
|
||||
class Corpse;
|
||||
class Unit;
|
||||
class GameObject;
|
||||
class DynamicObject;
|
||||
class WorldObject;
|
||||
class Map;
|
||||
|
||||
template <class T>
|
||||
class HashMapHolder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef UNORDERED_MAP<uint64, T*> MapType;
|
||||
typedef ACE_Thread_Mutex LockType;
|
||||
typedef Trinity::GeneralLock<LockType> Guard;
|
||||
|
||||
static void Insert(T* o)
|
||||
{
|
||||
Guard guard(i_lock);
|
||||
m_objectMap[o->GetGUID()] = o;
|
||||
}
|
||||
|
||||
static void Remove(T* o)
|
||||
{
|
||||
Guard guard(i_lock);
|
||||
m_objectMap.erase(o->GetGUID());
|
||||
}
|
||||
|
||||
static T* Find(uint64 guid)
|
||||
{
|
||||
Guard guard(i_lock);
|
||||
typename MapType::iterator itr = m_objectMap.find(guid);
|
||||
return (itr != m_objectMap.end()) ? itr->second : NULL;
|
||||
}
|
||||
|
||||
static MapType& GetContainer() { return m_objectMap; }
|
||||
|
||||
static LockType* GetLock() { return &i_lock; }
|
||||
|
||||
private:
|
||||
|
||||
//Non instanceable only static
|
||||
HashMapHolder() {}
|
||||
|
||||
static LockType i_lock;
|
||||
static MapType m_objectMap;
|
||||
};
|
||||
|
||||
class ObjectAccessor : public Trinity::Singleton<ObjectAccessor, Trinity::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex> >
|
||||
{
|
||||
friend class Trinity::OperatorNew<ObjectAccessor>;
|
||||
ObjectAccessor();
|
||||
~ObjectAccessor();
|
||||
ObjectAccessor(const ObjectAccessor&);
|
||||
ObjectAccessor& operator=(const ObjectAccessor&);
|
||||
|
||||
public:
|
||||
|
||||
typedef UNORDERED_MAP<uint64, Corpse*> Player2CorpsesMapType;
|
||||
typedef UNORDERED_MAP<Player*, UpdateData>::value_type UpdateDataValueType;
|
||||
|
||||
template<class T> static T* GetObjectInWorld(uint64 guid, T* /*fake*/)
|
||||
{
|
||||
return HashMapHolder<T>::Find(guid);
|
||||
}
|
||||
|
||||
static Unit* GetObjectInWorld(uint64 guid, Unit* /*fake*/)
|
||||
{
|
||||
if (!guid)
|
||||
return NULL;
|
||||
|
||||
if (IS_PLAYER_GUID(guid))
|
||||
{
|
||||
Unit* u = (Unit*)HashMapHolder<Player>::Find(guid);
|
||||
if (!u || !u->IsInWorld())
|
||||
return NULL;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
if (IS_PET_GUID(guid))
|
||||
return (Unit*)HashMapHolder<Pet>::Find(guid);
|
||||
|
||||
return (Unit*)HashMapHolder<Creature>::Find(guid);
|
||||
}
|
||||
|
||||
static Unit* GetUnitInOrOutOfWorld(uint64 guid, Unit* /*fake*/)
|
||||
{
|
||||
if (!guid)
|
||||
return NULL;
|
||||
|
||||
if (IS_PLAYER_GUID(guid))
|
||||
{
|
||||
Unit* u = (Unit*)HashMapHolder<Player>::Find(guid);
|
||||
if (!u)
|
||||
return NULL;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
// Other object types than player are unloaded while out of world
|
||||
return GetObjectInWorld(guid, (Unit*)NULL);
|
||||
}
|
||||
|
||||
template<class T> static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/)
|
||||
{
|
||||
T* obj = HashMapHolder<T>::Find(guid);
|
||||
if (!obj || obj->GetMapId() != mapid)
|
||||
return NULL;
|
||||
|
||||
CellPair p = Trinity::ComputeCellPair(x, y);
|
||||
if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
|
||||
{
|
||||
sLog.outError("ObjectAccessor::GetObjectInWorld: invalid coordinates supplied X:%f Y:%f grid cell [%u:%u]", x, y, p.x_coord, p.y_coord);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CellPair q = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
|
||||
if (q.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || q.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
|
||||
{
|
||||
sLog.outError("ObjectAccessor::GetObjecInWorld: object (GUID: %u TypeId: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), q.x_coord, q.y_coord);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32 dx = int32(p.x_coord) - int32(q.x_coord);
|
||||
int32 dy = int32(p.y_coord) - int32(q.y_coord);
|
||||
|
||||
if (dx > -2 && dx < 2 && dy > -2 && dy < 2)
|
||||
return obj;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static WorldObject* GetWorldObject(WorldObject const&, uint64);
|
||||
static Object* GetObjectByTypeMask(WorldObject const&, uint64, uint32 typemask);
|
||||
static Creature* GetCreatureOrPetOrVehicle(WorldObject const&, uint64);
|
||||
static Unit* GetUnit(WorldObject const&, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); }
|
||||
static Unit* GetUnitInOrOutOfWorld(WorldObject const&, uint64 guid) { return GetUnitInOrOutOfWorld(guid, (Unit*)NULL); }
|
||||
static Pet* GetPet(Unit const&, uint64 guid) { return GetPet(guid); }
|
||||
static Player* GetPlayer(Unit const&, uint64 guid) { return FindPlayer(guid); }
|
||||
static Corpse* GetCorpse(WorldObject const& u, uint64 guid);
|
||||
static Pet* GetPet(uint64 guid);
|
||||
static Player* FindPlayer(uint64);
|
||||
|
||||
Player* FindPlayerByName(const char* name) ;
|
||||
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
HashMapHolder<Player>::MapType& GetPlayers()
|
||||
{
|
||||
return HashMapHolder<Player>::GetContainer();
|
||||
}
|
||||
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
HashMapHolder<Creature>::MapType& GetCreatures()
|
||||
{
|
||||
return HashMapHolder<Creature>::GetContainer();
|
||||
}
|
||||
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
HashMapHolder<GameObject>::MapType& GetGameObjects()
|
||||
{
|
||||
return HashMapHolder<GameObject>::GetContainer();
|
||||
}
|
||||
|
||||
template<class T> void AddObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Insert(object);
|
||||
}
|
||||
|
||||
template<class T> void RemoveObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Remove(object);
|
||||
}
|
||||
|
||||
void RemoveObject(Player* pl)
|
||||
{
|
||||
HashMapHolder<Player>::Remove(pl);
|
||||
RemoveUpdateObject((Object*)pl);
|
||||
}
|
||||
|
||||
void SaveAllPlayers();
|
||||
|
||||
void AddUpdateObject(Object* obj)
|
||||
{
|
||||
Guard guard(i_updateGuard);
|
||||
i_objects.insert(obj);
|
||||
}
|
||||
|
||||
void RemoveUpdateObject(Object* obj)
|
||||
{
|
||||
Guard guard(i_updateGuard);
|
||||
i_objects.erase(obj);
|
||||
}
|
||||
|
||||
void Update(uint32 diff);
|
||||
|
||||
Corpse* GetCorpseForPlayerGUID(uint64 guid);
|
||||
void RemoveCorpse(Corpse* corpse);
|
||||
void AddCorpse(Corpse* corpse);
|
||||
void AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map);
|
||||
Corpse* ConvertCorpseForPlayer(uint64 player_guid, bool insignia = false);
|
||||
|
||||
typedef ACE_Thread_Mutex LockType;
|
||||
typedef Trinity::GeneralLock<LockType> Guard;
|
||||
|
||||
private:
|
||||
|
||||
Player2CorpsesMapType i_player2corpse;
|
||||
|
||||
static void _buildChangeObjectForPlayer(WorldObject*, UpdateDataMapType&);
|
||||
static void _buildPacket(Player*, Object*, UpdateDataMapType&);
|
||||
void _update();
|
||||
|
||||
std::set<Object*> i_objects;
|
||||
|
||||
LockType i_updateGuard;
|
||||
LockType i_corpseGuard;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_OBJECTDEFINES_H
|
||||
#define TRINITY_OBJECTDEFINES_H
|
||||
|
||||
#include "Platform/Define.h"
|
||||
|
||||
// used for creating values for respawn for example
|
||||
#define MAKE_PAIR64(l, h) uint64(uint32(l) | (uint64(h) << 32))
|
||||
#define PAIR64_HIPART(x) (uint32)((uint64(x) >> 32) & UI64LIT(0x00000000FFFFFFFF))
|
||||
#define PAIR64_LOPART(x) (uint32)(uint64(x) & UI64LIT(0x00000000FFFFFFFF))
|
||||
|
||||
#define MAKE_PAIR16(l, h) uint16(uint8(l) | (uint16(h) << 8))
|
||||
#define MAKE_PAIR32(l, h) uint32(uint16(l) | (uint32(h) << 16))
|
||||
#define PAIR32_HIPART(x) (uint16)((uint32(x) >> 16) & 0x0000FFFF)
|
||||
#define PAIR32_LOPART(x) (uint16)(uint32(x) & 0x0000FFFF)
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
#define IS_EMPTY_GUID(Guid) (Guid == 0)
|
||||
|
||||
#define IS_CREATURE_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_UNIT)
|
||||
#define IS_PET_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_PET)
|
||||
#define IS_VEHICLE_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_VEHICLE)
|
||||
#define IS_CRE_OR_VEH_GUID(Guid) (IS_CREATURE_GUID(Guid) || IS_VEHICLE_GUID(Guid))
|
||||
#define IS_CRE_OR_VEH_OR_PET_GUID(Guid)(IS_CRE_OR_VEH_GUID(Guid) || IS_PET_GUID(Guid))
|
||||
#define IS_PLAYER_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_PLAYER && Guid != 0)
|
||||
#define IS_UNIT_GUID(Guid) (IS_CRE_OR_VEH_OR_PET_GUID(Guid) || IS_PLAYER_GUID(Guid))
|
||||
// special case for empty guid need check
|
||||
#define IS_ITEM_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_ITEM)
|
||||
#define IS_GAMEOBJECT_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_GAMEOBJECT)
|
||||
#define IS_DYNAMICOBJECT_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_DYNAMICOBJECT)
|
||||
#define IS_CORPSE_GUID(Guid) (GUID_HIPART(Guid) == HIGHGUID_CORPSE)
|
||||
#define IS_TRANSPORT(Guid) (GUID_HIPART(Guid) == HIGHGUID_TRANSPORT)
|
||||
#define IS_MO_TRANSPORT(Guid) (GUID_HIPART(Guid) == HIGHGUID_MO_TRANSPORT)
|
||||
#define IS_GROUP(Guid) (GUID_HIPART(Guid) == HIGHGUID_GROUP)
|
||||
|
||||
// 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
|
||||
#define MAKE_NEW_GUID(l, e, h) uint64(uint64(l) | (uint64(e) << 24) | (uint64(h) << 48))
|
||||
|
||||
#define GUID_HIPART(x) (uint32)((uint64(x) >> 48) & 0x0000FFFF)
|
||||
|
||||
// We have different low and middle part size for different guid types
|
||||
#define _GUID_ENPART_2(x) 0
|
||||
#define _GUID_ENPART_3(x) (uint32)((uint64(x) >> 24) & UI64LIT(0x0000000000FFFFFF))
|
||||
#define _GUID_LOPART_2(x) (uint32)(uint64(x) & UI64LIT(0x00000000FFFFFFFF))
|
||||
#define _GUID_LOPART_3(x) (uint32)(uint64(x) & UI64LIT(0x0000000000FFFFFF))
|
||||
|
||||
inline bool IsGuidHaveEnPart(uint64 const& 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;
|
||||
}
|
||||
}
|
||||
|
||||
#define GUID_ENPART(x) (IsGuidHaveEnPart(x) ? _GUID_ENPART_3(x) : _GUID_ENPART_2(x))
|
||||
#define GUID_LOPART(x) (IsGuidHaveEnPart(x) ? _GUID_LOPART_3(x) : _GUID_LOPART_2(x))
|
||||
|
||||
inline 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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "World.h"
|
||||
#include <zlib/zlib.h>
|
||||
|
||||
UpdateData::UpdateData() : m_blockCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateData::AddOutOfRangeGUID(std::set<uint64>& guids)
|
||||
{
|
||||
m_outOfRangeGUIDs.insert(guids.begin(),guids.end());
|
||||
}
|
||||
|
||||
void UpdateData::AddOutOfRangeGUID(const uint64 &guid)
|
||||
{
|
||||
m_outOfRangeGUIDs.insert(guid);
|
||||
}
|
||||
|
||||
void UpdateData::AddUpdateBlock(const ByteBuffer &block)
|
||||
{
|
||||
m_data.append(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.getConfig(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::set<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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#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_LOWGUID = 0x0008,
|
||||
UPDATEFLAG_HIGHGUID = 0x0010,
|
||||
UPDATEFLAG_LIVING = 0x0020,
|
||||
UPDATEFLAG_HAS_POSITION = 0x0040,
|
||||
UPDATEFLAG_VEHICLE = 0x0080,
|
||||
UPDATEFLAG_POSITION = 0x0100,
|
||||
UPDATEFLAG_ROTATION = 0x0200
|
||||
};
|
||||
|
||||
class UpdateData
|
||||
{
|
||||
public:
|
||||
UpdateData();
|
||||
|
||||
void AddOutOfRangeGUID(std::set<uint64>& guids);
|
||||
void AddOutOfRangeGUID(const uint64 &guid);
|
||||
void AddUpdateBlock(const ByteBuffer &block);
|
||||
bool BuildPacket(WorldPacket *packet);
|
||||
bool HasData() { return m_blockCount > 0 || !m_outOfRangeGUIDs.empty(); }
|
||||
void Clear();
|
||||
|
||||
std::set<uint64> const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; }
|
||||
|
||||
protected:
|
||||
uint32 m_blockCount;
|
||||
std::set<uint64> m_outOfRangeGUIDs;
|
||||
ByteBuffer m_data;
|
||||
|
||||
void Compress(void* dst, uint32 *dst_size, void* src, int src_size);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _UPDATEFIELDS_AUTO_H
|
||||
#define _UPDATEFIELDS_AUTO_H
|
||||
|
||||
// Auto generated for version 3, 3, 3, 11723
|
||||
|
||||
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
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __UPDATEMASK_H
|
||||
#define __UPDATEMASK_H
|
||||
|
||||
#include "UpdateFields.h"
|
||||
#include "Errors.h"
|
||||
|
||||
class UpdateMask
|
||||
{
|
||||
public:
|
||||
UpdateMask() : mCount(0), mBlocks(0), mUpdateMask(0) { }
|
||||
UpdateMask(const UpdateMask& mask) : mUpdateMask(0) { *this = mask; }
|
||||
|
||||
~UpdateMask()
|
||||
{
|
||||
if (mUpdateMask)
|
||||
delete [] mUpdateMask;
|
||||
}
|
||||
|
||||
void SetBit (uint32 index)
|
||||
{
|
||||
((uint8 *)mUpdateMask)[ index >> 3 ] |= 1 << (index & 0x7);
|
||||
}
|
||||
|
||||
void UnsetBit (uint32 index)
|
||||
{
|
||||
((uint8 *)mUpdateMask)[ index >> 3 ] &= (0xff ^ (1 << (index & 0x7)));
|
||||
}
|
||||
|
||||
bool GetBit (uint32 index) const
|
||||
{
|
||||
return (((uint8 *)mUpdateMask)[ index >> 3 ] & (1 << (index & 0x7))) != 0;
|
||||
}
|
||||
|
||||
uint32 GetBlockCount() const { return mBlocks; }
|
||||
uint32 GetLength() const { return mBlocks << 2; }
|
||||
uint32 GetCount() const { return mCount; }
|
||||
uint8* GetMask() { return (uint8*)mUpdateMask; }
|
||||
|
||||
void SetCount (uint32 valuesCount)
|
||||
{
|
||||
if (mUpdateMask)
|
||||
delete [] mUpdateMask;
|
||||
|
||||
mCount = valuesCount;
|
||||
mBlocks = (valuesCount + 31) / 32;
|
||||
|
||||
mUpdateMask = new uint32[mBlocks];
|
||||
memset(mUpdateMask, 0, mBlocks << 2);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
if (mUpdateMask)
|
||||
memset(mUpdateMask, 0, mBlocks << 2);
|
||||
}
|
||||
|
||||
UpdateMask& operator = (const UpdateMask& mask)
|
||||
{
|
||||
SetCount(mask.mCount);
|
||||
memcpy(mUpdateMask, mask.mUpdateMask, mBlocks << 2);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator &= (const UpdateMask& mask)
|
||||
{
|
||||
ASSERT(mask.mCount <= mCount);
|
||||
for (uint32 i = 0; i < mBlocks; ++i)
|
||||
mUpdateMask[i] &= mask.mUpdateMask[i];
|
||||
}
|
||||
|
||||
void operator |= (const UpdateMask& mask)
|
||||
{
|
||||
ASSERT(mask.mCount <= mCount);
|
||||
for (uint32 i = 0; i < mBlocks; ++i)
|
||||
mUpdateMask[i] |= mask.mUpdateMask[i];
|
||||
}
|
||||
|
||||
UpdateMask operator & (const UpdateMask& mask) const
|
||||
{
|
||||
ASSERT(mask.mCount <= mCount);
|
||||
|
||||
UpdateMask newmask;
|
||||
newmask = *this;
|
||||
newmask &= mask;
|
||||
|
||||
return newmask;
|
||||
}
|
||||
|
||||
UpdateMask operator | (const UpdateMask& mask) const
|
||||
{
|
||||
ASSERT(mask.mCount <= mCount);
|
||||
|
||||
UpdateMask newmask;
|
||||
newmask = *this;
|
||||
newmask |= mask;
|
||||
|
||||
return newmask;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 mCount;
|
||||
uint32 mBlocks;
|
||||
uint32 *mUpdateMask;
|
||||
};
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_PET_H
|
||||
#define TRINITYCORE_PET_H
|
||||
|
||||
#include "ObjectDefines.h"
|
||||
#include "Unit.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum PetType
|
||||
{
|
||||
SUMMON_PET = 0,
|
||||
HUNTER_PET = 1,
|
||||
MAX_PET_TYPE = 4,
|
||||
};
|
||||
|
||||
extern char const* petTypeSuffix[MAX_PET_TYPE];
|
||||
|
||||
#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,
|
||||
};
|
||||
|
||||
struct PetSpell
|
||||
{
|
||||
ActiveStates active;
|
||||
PetSpellState state;
|
||||
PetSpellType type;
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
enum PetNameInvalidReason
|
||||
{
|
||||
// custom, not send
|
||||
PET_NAME_SUCCESS = 0,
|
||||
|
||||
PET_NAME_INVALID = 1,
|
||||
PET_NAME_NO_NAME = 2,
|
||||
PET_NAME_TOO_SHORT = 3,
|
||||
PET_NAME_TOO_LONG = 4,
|
||||
PET_NAME_MIXED_LANGUAGES = 6,
|
||||
PET_NAME_PROFANE = 7,
|
||||
PET_NAME_RESERVED = 8,
|
||||
PET_NAME_THREE_CONSECUTIVE = 11,
|
||||
PET_NAME_INVALID_SPACE = 12,
|
||||
PET_NAME_CONSECUTIVE_SPACES = 13,
|
||||
PET_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 14,
|
||||
PET_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 15,
|
||||
PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 16
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32, PetSpell> PetSpellMap;
|
||||
typedef std::vector<uint32> AutoSpellList;
|
||||
|
||||
#define HAPPINESS_LEVEL_SIZE 333000
|
||||
|
||||
#define ACTIVE_SPELLS_MAX 4
|
||||
|
||||
#define PET_FOLLOW_DIST 1
|
||||
#define PET_FOLLOW_ANGLE (M_PI/2)
|
||||
#define PET_FOCUS_REGEN_INTERVAL 4 * IN_MILISECONDS
|
||||
|
||||
class Player;
|
||||
|
||||
class Pet : public Guardian
|
||||
{
|
||||
public:
|
||||
explicit Pet(Player *owner, PetType type = MAX_PET_TYPE);
|
||||
virtual ~Pet();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
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); // 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 LoadPetFromDB(Player* owner,uint32 petentry = 0,uint32 petnumber = 0, bool current = false);
|
||||
bool isBeingLoaded() const { return m_loading;}
|
||||
void SavePetToDB(PetSaveMode mode);
|
||||
void Remove(PetSaveMode mode, bool returnreagent = false);
|
||||
static void DeleteFromDB(uint32 guidlow);
|
||||
|
||||
void setDeathState(DeathState s); // 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 LooseHappiness();
|
||||
HappinessState GetHappinessState();
|
||||
void GivePetXP(uint32 xp);
|
||||
void GivePetLevel(uint8 level);
|
||||
void SynchronizeLevelWithOwner();
|
||||
bool HaveInDiet(ItemPrototype const* item) const;
|
||||
uint32 GetCurrentFoodBenefitLevel(uint32 itemlevel);
|
||||
void SetDuration(int32 dur) { m_duration = dur; }
|
||||
|
||||
/*
|
||||
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);
|
||||
*/
|
||||
|
||||
bool CanTakeMoreActiveSpells(uint32 SpellIconID);
|
||||
void ToggleAutocast(uint32 spellid, bool apply);
|
||||
|
||||
bool HasSpell(uint32 spell) const;
|
||||
|
||||
void LearnPetPassives();
|
||||
void CastPetAuras(bool current);
|
||||
void CastPetAura(PetAura const* aura);
|
||||
bool IsPetAura(Aura const* aura);
|
||||
|
||||
void _LoadSpellCooldowns();
|
||||
void _SaveSpellCooldowns();
|
||||
void _LoadAuras(uint32 timediff);
|
||||
void _SaveAuras();
|
||||
void _LoadSpells();
|
||||
void _SaveSpells();
|
||||
|
||||
bool addSpell(uint32 spell_id,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(bool no_cost = false);
|
||||
static void resetTalentsForAllPetsOf(Player* owner, Pet* online_pet = NULL);
|
||||
uint32 resetTalentsCost() const;
|
||||
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_resetTalentsCost;
|
||||
time_t m_resetTalentsTime;
|
||||
uint32 m_usedTalentCount;
|
||||
|
||||
const 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() { return m_owner; }
|
||||
protected:
|
||||
Player *m_owner;
|
||||
uint32 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;
|
||||
uint32 m_regenTimer;
|
||||
|
||||
DeclinedName *m_declinedname;
|
||||
|
||||
private:
|
||||
void SaveToDB(uint32, uint8) // overwrited of Creature::SaveToDB - don't must be called
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
void DeleteFromDB() // overwrited of Creature::DeleteFromDB - don't must be called
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,813 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Spell.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Util.h"
|
||||
#include "Pet.h"
|
||||
#include "World.h"
|
||||
|
||||
void WorldSession::HandleDismissCritter(WorldPacket &recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_DISMISS_CRITTER for GUID %u", guid);
|
||||
|
||||
Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
|
||||
|
||||
if (!pet)
|
||||
{
|
||||
sLog.outError("Vanitypet %u does not exist", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetCritterGUID() == pet->GetGUID())
|
||||
{
|
||||
if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isSummon())
|
||||
pet->ToTempSummon()->UnSummon();
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetAction(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid1;
|
||||
uint32 data;
|
||||
uint64 guid2;
|
||||
recv_data >> guid1; //pet guid
|
||||
recv_data >> data;
|
||||
recv_data >> guid2; //tag guid
|
||||
|
||||
uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data);
|
||||
uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1
|
||||
|
||||
// used also for charmed creature
|
||||
Unit* pet= ObjectAccessor::GetUnit(*_player, guid1);
|
||||
sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2)));
|
||||
if (!pet)
|
||||
{
|
||||
sLog.outError("Pet %u not exist.", uint32(GUID_LOPART(guid1)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet != GetPlayer()->GetFirstControlled())
|
||||
{
|
||||
sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pet->isAlive())
|
||||
return;
|
||||
|
||||
//TODO: allow control charmed player?
|
||||
if (pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
|
||||
return;
|
||||
|
||||
if (GetPlayer()->m_Controlled.size() == 1)
|
||||
HandlePetActionHelper(pet, guid1, spellid, flag, guid2);
|
||||
else
|
||||
{
|
||||
//If a pet is dismissed, m_Controlled will change
|
||||
std::vector<Unit*> controlled;
|
||||
for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr)
|
||||
if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->isAlive())
|
||||
controlled.push_back(*itr);
|
||||
for (std::vector<Unit*>::iterator itr = controlled.begin(); itr != controlled.end(); ++itr)
|
||||
HandlePetActionHelper(*itr, guid1, spellid, flag, guid2);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2)
|
||||
{
|
||||
CharmInfo *charmInfo = pet->GetCharmInfo();
|
||||
if (!charmInfo)
|
||||
{
|
||||
sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
|
||||
return;
|
||||
}
|
||||
|
||||
switch(flag)
|
||||
{
|
||||
case ACT_COMMAND: //0x07
|
||||
switch(spellid)
|
||||
{
|
||||
case COMMAND_STAY: //flat=1792 //STAY
|
||||
pet->AttackStop();
|
||||
pet->InterruptNonMeleeSpells(false);
|
||||
pet->GetMotionMaster()->MoveIdle();
|
||||
charmInfo->SetCommandState(COMMAND_STAY);
|
||||
|
||||
charmInfo->SetIsCommandAttack(false);
|
||||
charmInfo->SetIsAtStay(true);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
charmInfo->SetIsReturning(false);
|
||||
charmInfo->SaveStayPosition();
|
||||
break;
|
||||
case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
|
||||
pet->AttackStop();
|
||||
pet->InterruptNonMeleeSpells(false);
|
||||
pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,pet->GetFollowAngle());
|
||||
charmInfo->SetCommandState(COMMAND_FOLLOW);
|
||||
|
||||
charmInfo->SetIsCommandAttack(false);
|
||||
charmInfo->SetIsAtStay(false);
|
||||
charmInfo->SetIsReturning(true);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
break;
|
||||
case COMMAND_ATTACK: //spellid=1792 //ATTACK
|
||||
{
|
||||
// Can't attack if owner is pacified
|
||||
if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY))
|
||||
{
|
||||
//pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
|
||||
//TODO: Send proper error message to client
|
||||
return;
|
||||
}
|
||||
|
||||
// only place where pet can be player
|
||||
Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, guid2);
|
||||
if (!TargetUnit)
|
||||
return;
|
||||
|
||||
if (!pet->canAttack(TargetUnit))
|
||||
return;
|
||||
|
||||
// Not let attack through obstructions
|
||||
if (sWorld.getConfig(CONFIG_PET_LOS))
|
||||
{
|
||||
|
||||
if (!pet->IsWithinLOSInMap(TargetUnit))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
pet->clearUnitState(UNIT_STAT_FOLLOW);
|
||||
// This is true if pet has no target or has target but targets differs.
|
||||
if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
|
||||
{
|
||||
if (pet->getVictim())
|
||||
pet->AttackStop();
|
||||
|
||||
if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled)
|
||||
{
|
||||
charmInfo->SetIsCommandAttack(true);
|
||||
charmInfo->SetIsAtStay(false);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
charmInfo->SetIsReturning(false);
|
||||
|
||||
pet->ToCreature()->AI()->AttackStart(TargetUnit);
|
||||
|
||||
//10% chance to play special pet attack talk, else growl
|
||||
if (pet->ToCreature()->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
|
||||
pet->SendPetTalk((uint32)PET_TALK_ATTACK);
|
||||
else
|
||||
{
|
||||
// 90% chance for pet and 100% chance for charmed creature
|
||||
pet->SendPetAIReaction(guid1);
|
||||
}
|
||||
}
|
||||
else // charmed player
|
||||
{
|
||||
if (pet->getVictim() && pet->getVictim() != TargetUnit)
|
||||
pet->AttackStop();
|
||||
|
||||
charmInfo->SetIsCommandAttack(true);
|
||||
charmInfo->SetIsAtStay(false);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
charmInfo->SetIsReturning(false);
|
||||
|
||||
pet->Attack(TargetUnit,true);
|
||||
pet->SendPetAIReaction(guid1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
|
||||
if (pet->GetCharmerGUID() == GetPlayer()->GetGUID())
|
||||
_player->StopCastingCharm();
|
||||
else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID())
|
||||
{
|
||||
assert(pet->GetTypeId() == TYPEID_UNIT);
|
||||
if (pet->isPet())
|
||||
{
|
||||
if (((Pet*)pet)->getPetType() == HUNTER_PET)
|
||||
GetPlayer()->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED);
|
||||
else
|
||||
//dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
|
||||
pet->setDeathState(CORPSE);
|
||||
}
|
||||
else if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
|
||||
{
|
||||
((Minion*)pet)->UnSummon();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
|
||||
}
|
||||
break;
|
||||
case ACT_REACTION: // 0x6
|
||||
switch(spellid)
|
||||
{
|
||||
case REACT_PASSIVE: //passive
|
||||
pet->AttackStop();
|
||||
|
||||
case REACT_DEFENSIVE: //recovery
|
||||
case REACT_AGGRESSIVE: //activete
|
||||
if (pet->GetTypeId() == TYPEID_UNIT)
|
||||
pet->ToCreature()->SetReactState(ReactStates(spellid));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ACT_DISABLED: // 0x81 spell (disabled), ignore
|
||||
case ACT_PASSIVE: // 0x01
|
||||
case ACT_ENABLED: // 0xC1 spell
|
||||
{
|
||||
Unit* unit_target = NULL;
|
||||
|
||||
if (guid2)
|
||||
unit_target = ObjectAccessor::GetUnit(*_player,guid2);
|
||||
|
||||
// do not cast unknown spells
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
|
||||
if (!spellInfo)
|
||||
{
|
||||
sLog.outError("WORLD: unknown PET spell id %i", spellid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spellInfo->StartRecoveryCategory > 0)
|
||||
if (pet->ToCreature()->GetGlobalCooldown() > 0)
|
||||
return;
|
||||
|
||||
for (uint32 i = 0; i < 3; ++i)
|
||||
{
|
||||
if (spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_SRC || spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_DST || spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_DYNOBJ_ENEMY)
|
||||
return;
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
|
||||
return;
|
||||
|
||||
// Clear the flags as if owner clicked 'attack'. AI will reset them
|
||||
// after AttackStart, even if spell failed
|
||||
if (pet->GetCharmInfo())
|
||||
{
|
||||
pet->GetCharmInfo()->SetIsAtStay(false);
|
||||
pet->GetCharmInfo()->SetIsCommandAttack(true);
|
||||
pet->GetCharmInfo()->SetIsReturning(false);
|
||||
pet->GetCharmInfo()->SetIsFollowing(false);
|
||||
}
|
||||
|
||||
Spell *spell = new Spell(pet, spellInfo, false);
|
||||
|
||||
SpellCastResult result = spell->CheckPetCast(unit_target);
|
||||
|
||||
//auto turn to target unless possessed
|
||||
if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle())
|
||||
{
|
||||
if (unit_target)
|
||||
{
|
||||
pet->SetInFront(unit_target);
|
||||
if (unit_target->GetTypeId() == TYPEID_PLAYER)
|
||||
pet->SendUpdateToPlayer((Player*)unit_target);
|
||||
}
|
||||
else if (Unit *unit_target2 = spell->m_targets.getUnitTarget())
|
||||
{
|
||||
pet->SetInFront(unit_target2);
|
||||
if (unit_target2->GetTypeId() == TYPEID_PLAYER)
|
||||
pet->SendUpdateToPlayer((Player*)unit_target2);
|
||||
}
|
||||
if (Unit* powner = pet->GetCharmerOrOwner())
|
||||
if (powner->GetTypeId() == TYPEID_PLAYER)
|
||||
pet->SendUpdateToPlayer(powner->ToPlayer());
|
||||
result = SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
if (result == SPELL_CAST_OK)
|
||||
{
|
||||
pet->ToCreature()->AddCreatureSpellCooldown(spellid);
|
||||
|
||||
unit_target = spell->m_targets.getUnitTarget();
|
||||
|
||||
//10% chance to play special pet attack talk, else growl
|
||||
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
||||
if (pet->ToCreature()->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10))
|
||||
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
|
||||
else
|
||||
{
|
||||
pet->SendPetAIReaction(guid1);
|
||||
}
|
||||
|
||||
if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle())
|
||||
{
|
||||
// This is true if pet has no target or has target but targets differs.
|
||||
if (pet->getVictim() != unit_target)
|
||||
{
|
||||
if (pet->getVictim())
|
||||
pet->AttackStop();
|
||||
pet->GetMotionMaster()->Clear();
|
||||
if (pet->ToCreature()->IsAIEnabled)
|
||||
pet->ToCreature()->AI()->AttackStart(unit_target);
|
||||
}
|
||||
}
|
||||
|
||||
spell->prepare(&(spell->m_targets));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pet->isPossessed() || pet->IsVehicle())
|
||||
Spell::SendCastResult(GetPlayer(),spellInfo,0,result);
|
||||
else
|
||||
pet->SendPetCastFail(spellid, result);
|
||||
|
||||
if (!pet->ToCreature()->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, pet);
|
||||
|
||||
spell->finish(false);
|
||||
delete spell;
|
||||
|
||||
// reset specific flags in case of spell fail. AI will reset other flags
|
||||
if (pet->GetCharmInfo())
|
||||
pet->GetCharmInfo()->SetIsCommandAttack(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetNameQuery(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDetail("HandlePetNameQuery. CMSG_PET_NAME_QUERY");
|
||||
|
||||
uint32 petnumber;
|
||||
uint64 petguid;
|
||||
|
||||
recv_data >> petnumber;
|
||||
recv_data >> petguid;
|
||||
|
||||
SendPetNameQuery(petguid,petnumber);
|
||||
}
|
||||
|
||||
void WorldSession::SendPetNameQuery(uint64 petguid, uint32 petnumber)
|
||||
{
|
||||
Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid);
|
||||
if (!pet)
|
||||
{
|
||||
WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+7+1));
|
||||
data << uint32(petnumber);
|
||||
data << "Unknown";
|
||||
data << uint32(0);
|
||||
data << uint8(0);
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name = pet->GetName();
|
||||
|
||||
WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1));
|
||||
data << uint32(petnumber);
|
||||
data << name.c_str();
|
||||
data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP));
|
||||
|
||||
if (pet->isPet() && ((Pet*)pet)->GetDeclinedNames())
|
||||
{
|
||||
data << uint8(1);
|
||||
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
data << ((Pet*)pet)->GetDeclinedNames()->name[i];
|
||||
}
|
||||
else
|
||||
data << uint8(0);
|
||||
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetSetAction(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDetail("HandlePetSetAction. CMSG_PET_SET_ACTION");
|
||||
|
||||
uint64 petguid;
|
||||
uint8 count;
|
||||
|
||||
recv_data >> petguid;
|
||||
|
||||
Unit* pet = ObjectAccessor::GetUnit(*_player, petguid);
|
||||
|
||||
if (!pet || pet != _player->GetFirstControlled())
|
||||
{
|
||||
sLog.outError("HandlePetSetAction: Unknown pet or pet owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
CharmInfo *charmInfo = pet->GetCharmInfo();
|
||||
if (!charmInfo)
|
||||
{
|
||||
sLog.outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
|
||||
return;
|
||||
}
|
||||
|
||||
count = (recv_data.size() == 24) ? 2 : 1;
|
||||
|
||||
uint32 position[2];
|
||||
uint32 data[2];
|
||||
bool move_command = false;
|
||||
|
||||
for (uint8 i = 0; i < count; ++i)
|
||||
{
|
||||
recv_data >> position[i];
|
||||
recv_data >> data[i];
|
||||
|
||||
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]);
|
||||
|
||||
//ignore invalid position
|
||||
if (position[i] >= MAX_UNIT_ACTION_BAR_INDEX)
|
||||
return;
|
||||
|
||||
// in the normal case, command and reaction buttons can only be moved, not removed
|
||||
// at moving count == 2, at removing count == 1
|
||||
// ignore attempt to remove command|reaction buttons (not possible at normal case)
|
||||
if (act_state == ACT_COMMAND || act_state == ACT_REACTION)
|
||||
{
|
||||
if (count == 1)
|
||||
return;
|
||||
|
||||
move_command = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness)
|
||||
if (move_command)
|
||||
{
|
||||
uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]);
|
||||
if (act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION)
|
||||
{
|
||||
uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]);
|
||||
UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]);
|
||||
if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() ||
|
||||
act_state_0 != actionEntry_1->GetType())
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]);
|
||||
if (act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION)
|
||||
{
|
||||
uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]);
|
||||
UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]);
|
||||
if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() ||
|
||||
act_state_1 != actionEntry_0->GetType())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < count; ++i)
|
||||
{
|
||||
uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]);
|
||||
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]);
|
||||
|
||||
sLog.outDetail("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position[i], spell_id, uint32(act_state));
|
||||
|
||||
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
|
||||
if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id)))
|
||||
{
|
||||
//sign for autocast
|
||||
if (act_state == ACT_ENABLED && spell_id)
|
||||
{
|
||||
if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet())
|
||||
((Pet*)pet)->ToggleAutocast(spell_id, true);
|
||||
else
|
||||
charmInfo->ToggleCreatureAutocast(spell_id, true);
|
||||
}
|
||||
//sign for no/turn off autocast
|
||||
else if (act_state == ACT_DISABLED && spell_id)
|
||||
{
|
||||
if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet())
|
||||
((Pet*)pet)->ToggleAutocast(spell_id, false);
|
||||
else
|
||||
charmInfo->ToggleCreatureAutocast(spell_id, false);
|
||||
|
||||
}
|
||||
|
||||
charmInfo->SetActionBar(position[i],spell_id,ActiveStates(act_state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetRename(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDetail("HandlePetRename. CMSG_PET_RENAME");
|
||||
|
||||
uint64 petguid;
|
||||
uint8 isdeclined;
|
||||
|
||||
std::string name;
|
||||
DeclinedName declinedname;
|
||||
|
||||
recv_data >> petguid;
|
||||
recv_data >> name;
|
||||
recv_data >> isdeclined;
|
||||
|
||||
Pet* pet = ObjectAccessor::GetPet(petguid);
|
||||
// check it!
|
||||
if (!pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET ||
|
||||
!pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ||
|
||||
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo())
|
||||
return;
|
||||
|
||||
PetNameInvalidReason res = ObjectMgr::CheckPetName(name);
|
||||
if (res != PET_NAME_SUCCESS)
|
||||
{
|
||||
SendPetNameInvalid(res, name, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (objmgr.IsReservedName(name))
|
||||
{
|
||||
SendPetNameInvalid(PET_NAME_RESERVED, name, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
pet->SetName(name);
|
||||
|
||||
Unit *owner = pet->GetOwner();
|
||||
if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
|
||||
owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME);
|
||||
|
||||
pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
|
||||
|
||||
if (isdeclined)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
{
|
||||
recv_data >> declinedname.name[i];
|
||||
}
|
||||
|
||||
std::wstring wname;
|
||||
Utf8toWStr(name, wname);
|
||||
if (!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname))
|
||||
{
|
||||
SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
if (isdeclined)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
CharacterDatabase.escape_string(declinedname.name[i]);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
|
||||
CharacterDatabase.PExecute("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')",
|
||||
pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str());
|
||||
}
|
||||
|
||||
CharacterDatabase.escape_string(name);
|
||||
CharacterDatabase.PExecute("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(), _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetAbandon(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid; //pet guid
|
||||
sLog.outDetail("HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid));
|
||||
|
||||
if (!_player->IsInWorld())
|
||||
return;
|
||||
|
||||
// pet/charmed
|
||||
Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
|
||||
if (pet)
|
||||
{
|
||||
if (pet->isPet())
|
||||
{
|
||||
if (pet->GetGUID() == _player->GetPetGUID())
|
||||
{
|
||||
uint32 feelty = pet->GetPower(POWER_HAPPINESS);
|
||||
pet->SetPower(POWER_HAPPINESS ,(feelty-50000) > 0 ?(feelty-50000) : 0);
|
||||
}
|
||||
|
||||
_player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED);
|
||||
}
|
||||
else if (pet->GetGUID() == _player->GetCharmGUID())
|
||||
_player->StopCastingCharm();
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDetail("CMSG_PET_SPELL_AUTOCAST");
|
||||
uint64 guid;
|
||||
uint32 spellid;
|
||||
uint8 state; //1 for on, 0 for off
|
||||
recvPacket >> guid >> spellid >> state;
|
||||
|
||||
if (!_player->GetGuardianPet() && !_player->GetCharm())
|
||||
return;
|
||||
|
||||
if (ObjectAccessor::FindPlayer(guid))
|
||||
return;
|
||||
|
||||
Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);
|
||||
|
||||
if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm()))
|
||||
{
|
||||
sLog.outError("HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
// do not add not learned spells/ passive spells
|
||||
if (!pet->HasSpell(spellid) || IsAutocastableSpell(spellid))
|
||||
return;
|
||||
|
||||
CharmInfo *charmInfo = pet->GetCharmInfo();
|
||||
if (!charmInfo)
|
||||
{
|
||||
sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet->isPet())
|
||||
((Pet*)pet)->ToggleAutocast(spellid, state);
|
||||
else
|
||||
pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
|
||||
|
||||
charmInfo->SetSpellAutocast(spellid,state);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");
|
||||
|
||||
uint64 guid;
|
||||
uint32 spellid;
|
||||
uint8 cast_count;
|
||||
uint8 unk_flags; // flags (if 0x02 - some additional data are received)
|
||||
|
||||
recvPacket >> guid >> cast_count >> spellid >> unk_flags;
|
||||
|
||||
sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags);
|
||||
|
||||
// This opcode is also sent from charmed and possessed units (players and creatures)
|
||||
if (!_player->GetGuardianPet() && !_player->GetCharm())
|
||||
return;
|
||||
|
||||
Unit* caster = ObjectAccessor::GetUnit(*_player, guid);
|
||||
|
||||
if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm()))
|
||||
{
|
||||
sLog.outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
|
||||
if (!spellInfo)
|
||||
{
|
||||
sLog.outError("WORLD: unknown PET spell id %i", spellid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD
|
||||
if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0)
|
||||
{
|
||||
caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY);
|
||||
return;
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!caster->HasSpell(spellid) || IsPassiveSpell(spellid))
|
||||
return;
|
||||
|
||||
SpellCastTargets targets;
|
||||
if (!targets.read(&recvPacket,caster))
|
||||
return;
|
||||
|
||||
caster->clearUnitState(UNIT_STAT_FOLLOW);
|
||||
|
||||
Spell *spell = new Spell(caster, spellInfo, spellid == 33395); // water elemental can cast freeze as triggered
|
||||
spell->m_cast_count = spellid == 33395 ? 0 : cast_count; // probably pending spell cast
|
||||
spell->m_targets = targets;
|
||||
|
||||
// TODO: need to check victim?
|
||||
SpellCastResult result;
|
||||
if (caster->m_movedPlayer)
|
||||
result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit());
|
||||
else
|
||||
result = spell->CheckPetCast(NULL);
|
||||
if (result == SPELL_CAST_OK)
|
||||
{
|
||||
if (caster->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
Creature* pet = caster->ToCreature();
|
||||
pet->AddCreatureSpellCooldown(spellid);
|
||||
if (pet->isPet())
|
||||
{
|
||||
Pet* p = (Pet*)pet;
|
||||
// 10% chance to play special pet attack talk, else growl
|
||||
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
||||
if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
|
||||
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
|
||||
else
|
||||
pet->SendPetAIReaction(guid);
|
||||
}
|
||||
}
|
||||
|
||||
spell->prepare(&(spell->m_targets));
|
||||
}
|
||||
else
|
||||
{
|
||||
caster->SendPetCastFail(spellid, result);
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (!caster->ToPlayer()->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, caster);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!caster->ToCreature()->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, caster);
|
||||
}
|
||||
|
||||
spell->finish(false);
|
||||
delete spell;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName)
|
||||
{
|
||||
WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1);
|
||||
data << uint32(error);
|
||||
data << name;
|
||||
if (declinedName)
|
||||
{
|
||||
data << uint8(1);
|
||||
for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
data << declinedName->name[i];
|
||||
}
|
||||
else
|
||||
data << uint8(0);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetLearnTalent(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT");
|
||||
|
||||
uint64 guid;
|
||||
uint32 talent_id, requested_rank;
|
||||
recv_data >> guid >> talent_id >> requested_rank;
|
||||
|
||||
_player->LearnPetTalent(guid, talent_id, requested_rank);
|
||||
_player->SendTalentsInfoData(true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("CMSG_LEARN_PREVIEW_TALENTS_PET");
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
uint32 talentsCount;
|
||||
recv_data >> talentsCount;
|
||||
|
||||
uint32 talentId, talentRank;
|
||||
|
||||
for (uint32 i = 0; i < talentsCount; ++i)
|
||||
{
|
||||
recv_data >> talentId >> talentRank;
|
||||
|
||||
_player->LearnPetTalent(guid, talentId, talentRank);
|
||||
}
|
||||
|
||||
_player->SendTalentsInfoData(true);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Player.h"
|
||||
|
||||
void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
uint64 guid;
|
||||
Player *pl;
|
||||
Player *plTarget;
|
||||
|
||||
if (!GetPlayer()->duel) // ignore accept from duel-sender
|
||||
return;
|
||||
|
||||
recvPacket >> guid;
|
||||
|
||||
pl = GetPlayer();
|
||||
plTarget = pl->duel->opponent;
|
||||
|
||||
if (pl == pl->duel->initiator || !plTarget || pl == plTarget || pl->duel->startTime != 0 || plTarget->duel->startTime != 0)
|
||||
return;
|
||||
|
||||
//sLog.outDebug("WORLD: received CMSG_DUEL_ACCEPTED");
|
||||
DEBUG_LOG("Player 1 is: %u (%s)", pl->GetGUIDLow(),pl->GetName());
|
||||
DEBUG_LOG("Player 2 is: %u (%s)", plTarget->GetGUIDLow(),plTarget->GetName());
|
||||
|
||||
time_t now = time(NULL);
|
||||
pl->duel->startTimer = now;
|
||||
plTarget->duel->startTimer = now;
|
||||
|
||||
pl->SendDuelCountdown(3000);
|
||||
plTarget->SendDuelCountdown(3000);
|
||||
}
|
||||
|
||||
void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
//sLog.outDebug("WORLD: received CMSG_DUEL_CANCELLED");
|
||||
|
||||
// no duel requested
|
||||
if (!GetPlayer()->duel)
|
||||
return;
|
||||
|
||||
// player surrendered in a duel using /forfeit
|
||||
if (GetPlayer()->duel->startTime != 0)
|
||||
{
|
||||
GetPlayer()->CombatStopWithPets(true);
|
||||
if (GetPlayer()->duel->opponent)
|
||||
GetPlayer()->duel->opponent->CombatStopWithPets(true);
|
||||
|
||||
GetPlayer()->CastSpell(GetPlayer(), 7267, true); // beg
|
||||
GetPlayer()->DuelComplete(DUEL_WON);
|
||||
return;
|
||||
}
|
||||
|
||||
// player either discarded the duel using the "discard button"
|
||||
// or used "/forfeit" before countdown reached 0
|
||||
uint64 guid;
|
||||
recvPacket >> guid;
|
||||
|
||||
GetPlayer()->DuelComplete(DUEL_INTERUPTED);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Language.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Guild.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "GossipDef.h"
|
||||
#include "SocialMgr.h"
|
||||
|
||||
/*enum PetitionType // dbc data
|
||||
{
|
||||
PETITION_TYPE_GUILD = 1,
|
||||
PETITION_TYPE_ARENA_TEAM = 3
|
||||
};*/
|
||||
|
||||
// Charters ID in item_template
|
||||
#define GUILD_CHARTER 5863
|
||||
#define GUILD_CHARTER_COST 1000 // 10 S
|
||||
#define ARENA_TEAM_CHARTER_2v2 23560
|
||||
#define ARENA_TEAM_CHARTER_2v2_COST 800000 // 80 G
|
||||
#define ARENA_TEAM_CHARTER_3v3 23561
|
||||
#define ARENA_TEAM_CHARTER_3v3_COST 1200000 // 120 G
|
||||
#define ARENA_TEAM_CHARTER_5v5 23562
|
||||
#define ARENA_TEAM_CHARTER_5v5_COST 2000000 // 200 G
|
||||
|
||||
void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_BUY");
|
||||
recv_data.hexlike();
|
||||
|
||||
uint64 guidNPC;
|
||||
uint32 clientIndex; // 1 for guild and arenaslot+1 for arenas in client
|
||||
std::string name;
|
||||
|
||||
recv_data >> guidNPC; // NPC GUID
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint64>(); // 0
|
||||
recv_data >> name; // name
|
||||
recv_data.read_skip<std::string>(); // some string
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint16>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
recv_data.read_skip<std::string>();
|
||||
|
||||
recv_data >> clientIndex; // index
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
|
||||
sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str());
|
||||
|
||||
// prevent cheating
|
||||
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC,UNIT_NPC_FLAG_PETITIONER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 charterid = 0;
|
||||
uint32 cost = 0;
|
||||
uint32 type = 0;
|
||||
if (pCreature->isTabardDesigner())
|
||||
{
|
||||
// if tabard designer, then trying to buy a guild charter.
|
||||
// do not let if already in guild.
|
||||
if (_player->GetGuildId())
|
||||
return;
|
||||
|
||||
charterid = GUILD_CHARTER;
|
||||
cost = GUILD_CHARTER_COST;
|
||||
type = 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: find correct opcode
|
||||
if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
|
||||
return;
|
||||
}
|
||||
|
||||
switch(clientIndex) // arenaSlot+1 as received from client (1 from 3 case)
|
||||
{
|
||||
case 1:
|
||||
charterid = ARENA_TEAM_CHARTER_2v2;
|
||||
cost = ARENA_TEAM_CHARTER_2v2_COST;
|
||||
type = 2; // 2v2
|
||||
break;
|
||||
case 2:
|
||||
charterid = ARENA_TEAM_CHARTER_3v3;
|
||||
cost = ARENA_TEAM_CHARTER_3v3_COST;
|
||||
type = 3; // 3v3
|
||||
break;
|
||||
case 3:
|
||||
charterid = ARENA_TEAM_CHARTER_5v5;
|
||||
cost = ARENA_TEAM_CHARTER_5v5_COST;
|
||||
type = 5; // 5v5
|
||||
break;
|
||||
default:
|
||||
sLog.outDebug("unknown selection at buy arena petition: %u", clientIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetArenaTeamId(clientIndex - 1)) // arenaSlot+1 as received from client
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (objmgr.GetGuildByName(name))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objmgr.GetArenaTeamByName(name))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ItemPrototype const *pProto = objmgr.GetItemPrototype(charterid);
|
||||
if (!pProto)
|
||||
{
|
||||
_player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetMoney() < cost)
|
||||
{ //player hasn't got enough money
|
||||
_player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, charterid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemPosCountVec dest;
|
||||
uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
_player->SendBuyError(msg, pCreature, charterid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_player->ModifyMoney(-(int32)cost);
|
||||
Item *charter = _player->StoreNewItem(dest, charterid, true);
|
||||
if (!charter)
|
||||
return;
|
||||
|
||||
charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow());
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item)
|
||||
charter->SetState(ITEM_CHANGED, _player);
|
||||
_player->SendNewItem(charter, 1, true, false);
|
||||
|
||||
// a petition is invalid, if both the owner and the type matches
|
||||
// we checked above, if this player is in an arenateam, so this must be
|
||||
// datacorruption
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type);
|
||||
|
||||
std::ostringstream ssInvalidPetitionGUIDs;
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , ";
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
// delete petitions with the same guid as this one
|
||||
ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'";
|
||||
|
||||
sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str());
|
||||
CharacterDatabase.escape_string(name);
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str());
|
||||
CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str());
|
||||
CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')",
|
||||
_player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type);
|
||||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
// ok
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES");
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint8 signs = 0;
|
||||
uint64 petitionguid;
|
||||
recv_data >> petitionguid; // petition guid
|
||||
|
||||
// solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?)
|
||||
uint32 petitionguid_low = GUID_LOPART(petitionguid);
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low);
|
||||
if (!result)
|
||||
{
|
||||
sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
Field *fields = result->Fetch();
|
||||
uint32 type = fields[0].GetUInt32();
|
||||
|
||||
// if guild petition and has guild => error, return;
|
||||
if (type == 9 && _player->GetGuildId())
|
||||
return;
|
||||
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low);
|
||||
|
||||
// result == NULL also correct in case no sign yet
|
||||
if (result)
|
||||
signs = result->GetRowCount();
|
||||
|
||||
sLog.outDebug("CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low);
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12));
|
||||
data << uint64(petitionguid); // petition guid
|
||||
data << uint64(_player->GetGUID()); // owner guid
|
||||
data << uint32(petitionguid_low); // guild guid (in mangos always same as GUID_LOPART(petitionguid)
|
||||
data << uint8(signs); // sign's count
|
||||
|
||||
for (uint8 i = 1; i <= signs; ++i)
|
||||
{
|
||||
Field *fields2 = result->Fetch();
|
||||
uint64 plguid = fields2[0].GetUInt64();
|
||||
|
||||
data << uint64(plguid); // Player GUID
|
||||
data << (uint32)0; // there 0 ...
|
||||
|
||||
result->NextRow();
|
||||
}
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_QUERY"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint32 guildguid;
|
||||
uint64 petitionguid;
|
||||
recv_data >> guildguid; // in Trinity always same as GUID_LOPART(petitionguid)
|
||||
recv_data >> petitionguid; // petition guid
|
||||
sLog.outDebug("CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid);
|
||||
|
||||
SendPetitionQueryOpcode(petitionguid);
|
||||
}
|
||||
|
||||
void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid)
|
||||
{
|
||||
uint64 ownerguid = 0;
|
||||
uint32 type;
|
||||
std::string name = "NO_NAME_FOR_GUID";
|
||||
uint8 signs = 0;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery(
|
||||
"SELECT ownerguid, name, "
|
||||
" (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, "
|
||||
" type "
|
||||
"FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
|
||||
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
name = fields[1].GetCppString();
|
||||
signs = fields[2].GetUInt8();
|
||||
type = fields[3].GetUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10));
|
||||
data << uint32(GUID_LOPART(petitionguid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid)
|
||||
data << uint64(ownerguid); // charter owner guid
|
||||
data << name; // name (guild/arena team)
|
||||
data << uint8(0); // some string
|
||||
if (type == 9)
|
||||
{
|
||||
data << uint32(9);
|
||||
data << uint32(9);
|
||||
data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(type-1);
|
||||
data << uint32(type-1);
|
||||
data << uint32(type); // bypass client - side limitation, a different value is needed here for each petition
|
||||
}
|
||||
data << uint32(0); // 5
|
||||
data << uint32(0); // 6
|
||||
data << uint32(0); // 7
|
||||
data << uint32(0); // 8
|
||||
data << uint16(0); // 9 2 bytes field
|
||||
data << uint32(0); // 10
|
||||
data << uint32(0); // 11
|
||||
data << uint32(0); // 13 count of next strings?
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
data << uint8(0); // some string
|
||||
|
||||
data << uint32(0); // 14
|
||||
|
||||
if (type == 9)
|
||||
data << uint32(0); // 15 0 - guild, 1 - arena team
|
||||
else
|
||||
data << uint32(1);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode MSG_PETITION_RENAME"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint64 petitionguid;
|
||||
uint32 type;
|
||||
std::string newname;
|
||||
|
||||
recv_data >> petitionguid; // guid
|
||||
recv_data >> newname; // new name
|
||||
|
||||
Item *item = _player->GetItemByGuid(petitionguid);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
type = fields[0].GetUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (objmgr.GetGuildByName(newname))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objmgr.GetArenaTeamByName(newname))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string db_newname = newname;
|
||||
CharacterDatabase.escape_string(db_newname);
|
||||
CharacterDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'",
|
||||
db_newname.c_str(), GUID_LOPART(petitionguid));
|
||||
|
||||
sLog.outDebug("Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str());
|
||||
WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1));
|
||||
data << uint64(petitionguid);
|
||||
data << newname;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_SIGN"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
Field *fields;
|
||||
uint64 petitionguid;
|
||||
uint8 unk;
|
||||
recv_data >> petitionguid; // petition guid
|
||||
recv_data >> unk;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery(
|
||||
"SELECT ownerguid, "
|
||||
" (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, "
|
||||
" type "
|
||||
"FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
fields = result->Fetch();
|
||||
uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
uint8 signs = fields[1].GetUInt8();
|
||||
uint32 type = fields[2].GetUInt32();
|
||||
|
||||
uint32 plguidlo = _player->GetGUIDLow();
|
||||
if (GUID_LOPART(ownerguid) == plguidlo)
|
||||
return;
|
||||
|
||||
// not let enemies sign guild charter
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != objmgr.GetPlayerTeamByGUID(ownerguid))
|
||||
{
|
||||
if (type != 9)
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
|
||||
else
|
||||
SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != 9)
|
||||
{
|
||||
if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 slot = ArenaTeam::GetSlotByType(type);
|
||||
if (slot >= MAX_ARENA_SLOT)
|
||||
return;
|
||||
|
||||
if (_player->GetArenaTeamId(slot))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetArenaTeamIdInvited())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_player->GetGuildId())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S);
|
||||
return;
|
||||
}
|
||||
if (_player->GetGuildIdInvited())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (++signs > type) // client signs maximum
|
||||
return;
|
||||
|
||||
//client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
|
||||
//not allow sign another player from already sign player account
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid));
|
||||
|
||||
if (result)
|
||||
{
|
||||
WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
|
||||
data << uint64(petitionguid);
|
||||
data << uint64(_player->GetGUID());
|
||||
data << (uint32)PETITION_SIGN_ALREADY_SIGNED;
|
||||
|
||||
// close at signer side
|
||||
SendPacket(&data);
|
||||
|
||||
// update for owner if online
|
||||
if (Player *owner = objmgr.GetPlayer(ownerguid))
|
||||
owner->GetSession()->SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GUID_LOPART(ownerguid),GUID_LOPART(petitionguid), plguidlo,GetAccountId());
|
||||
|
||||
sLog.outDebug("PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(),plguidlo,GetAccountId());
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
|
||||
data << uint64(petitionguid);
|
||||
data << uint64(_player->GetGUID());
|
||||
data << uint32(PETITION_SIGN_OK);
|
||||
|
||||
// close at signer side
|
||||
SendPacket(&data);
|
||||
|
||||
// update signs count on charter, required testing...
|
||||
//Item *item = _player->GetItemByGuid(petitionguid));
|
||||
//if (item)
|
||||
// item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs);
|
||||
|
||||
// update for owner if online
|
||||
if (Player *owner = objmgr.GetPlayer(ownerguid))
|
||||
owner->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode MSG_PETITION_DECLINE"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint64 petitionguid;
|
||||
uint64 ownerguid;
|
||||
recv_data >> petitionguid; // petition guid
|
||||
sLog.outDebug("Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
|
||||
Player *owner = objmgr.GetPlayer(ownerguid);
|
||||
if (owner) // petition owner online
|
||||
{
|
||||
WorldPacket data(MSG_PETITION_DECLINE, 8);
|
||||
data << uint64(_player->GetGUID());
|
||||
owner->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_OFFER_PETITION"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint8 signs = 0;
|
||||
uint64 petitionguid, plguid;
|
||||
uint32 type, junk;
|
||||
Player *player;
|
||||
recv_data >> junk; // this is not petition type!
|
||||
recv_data >> petitionguid; // petition guid
|
||||
recv_data >> plguid; // player guid
|
||||
|
||||
player = ObjectAccessor::FindPlayer(plguid);
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
type = fields[0].GetUInt32();
|
||||
|
||||
sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid));
|
||||
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam())
|
||||
{
|
||||
if (type != 9)
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
|
||||
else
|
||||
SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != 9)
|
||||
{
|
||||
if (player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
// player is too low level to join an arena team
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_TARGET_TOO_LOW_S);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 slot = ArenaTeam::GetSlotByType(type);
|
||||
if (slot >= MAX_ARENA_SLOT)
|
||||
return;
|
||||
|
||||
if (player->GetArenaTeamId(slot))
|
||||
{
|
||||
// player is already in an arena team
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->GetArenaTeamIdInvited())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->GetGuildId())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->GetGuildIdInvited())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
// result == NULL also correct charter without signs
|
||||
if (result)
|
||||
signs = result->GetRowCount();
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12));
|
||||
data << uint64(petitionguid); // petition guid
|
||||
data << uint64(_player->GetGUID()); // owner guid
|
||||
data << uint32(GUID_LOPART(petitionguid)); // guild guid (in mangos always same as GUID_LOPART(petition guid)
|
||||
data << uint8(signs); // sign's count
|
||||
|
||||
for (uint8 i = 1; i <= signs; ++i)
|
||||
{
|
||||
Field *fields2 = result->Fetch();
|
||||
plguid = fields2[0].GetUInt64();
|
||||
|
||||
data << uint64(plguid); // Player GUID
|
||||
data << (uint32)0; // there 0 ...
|
||||
|
||||
result->NextRow();
|
||||
}
|
||||
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_TURN_IN_PETITION"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
WorldPacket data;
|
||||
uint64 petitionguid;
|
||||
|
||||
uint32 ownerguidlo;
|
||||
uint32 type;
|
||||
std::string name;
|
||||
|
||||
recv_data >> petitionguid;
|
||||
|
||||
sLog.outDebug("Petition %u turned in by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
|
||||
|
||||
// data
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid, name, type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (result)
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
ownerguidlo = fields[0].GetUInt32();
|
||||
name = fields[1].GetCppString();
|
||||
type = fields[2].GetUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outError("petition table has broken data!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (_player->GetGuildId())
|
||||
{
|
||||
data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 slot = ArenaTeam::GetSlotByType(type);
|
||||
if (slot >= MAX_ARENA_SLOT)
|
||||
return;
|
||||
|
||||
if (_player->GetArenaTeamId(slot))
|
||||
{
|
||||
//data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
//data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
|
||||
//_player->GetSession()->SendPacket(&data);
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_player->GetGUIDLow() != ownerguidlo)
|
||||
return;
|
||||
|
||||
// signs
|
||||
uint8 signs;
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (result)
|
||||
signs = result->GetRowCount();
|
||||
else
|
||||
signs = 0;
|
||||
|
||||
uint32 count;
|
||||
//if (signs < sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS))
|
||||
if (type == 9)
|
||||
count = sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS);
|
||||
else
|
||||
count = type-1;
|
||||
if (signs < count)
|
||||
{
|
||||
data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; // need more signatures...
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (objmgr.GetGuildByName(name))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objmgr.GetArenaTeamByName(name))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// and at last charter item check
|
||||
Item *item = _player->GetItemByGuid(petitionguid);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
// OK!
|
||||
|
||||
// delete charter item
|
||||
_player->DestroyItem(item->GetBagSlot(),item->GetSlot(), true);
|
||||
|
||||
if (type == 9) // create guild
|
||||
{
|
||||
Guild* guild = new Guild;
|
||||
if (!guild->Create(_player, name))
|
||||
{
|
||||
delete guild;
|
||||
return;
|
||||
}
|
||||
|
||||
// register guild and add guildmaster
|
||||
objmgr.AddGuild(guild);
|
||||
|
||||
// add members
|
||||
for (uint8 i = 0; i < signs; ++i)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank());
|
||||
result->NextRow();
|
||||
}
|
||||
}
|
||||
else // or arena team
|
||||
{
|
||||
ArenaTeam* at = new ArenaTeam;
|
||||
if (!at->Create(_player->GetGUID(), type, name))
|
||||
{
|
||||
sLog.outError("PetitionsHandler: arena team create failed.");
|
||||
delete at;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 icon, iconcolor, border, bordercolor, backgroud;
|
||||
recv_data >> backgroud >> icon >> iconcolor >> border >> bordercolor;
|
||||
|
||||
at->SetEmblem(backgroud, icon, iconcolor, border, bordercolor);
|
||||
|
||||
// register team and add captain
|
||||
objmgr.AddArenaTeam(at);
|
||||
sLog.outDebug("PetitonsHandler: arena team added to objmrg");
|
||||
|
||||
// add members
|
||||
for (uint8 i = 0; i < signs; ++i)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint64 memberGUID = fields[0].GetUInt64();
|
||||
sLog.outDebug("PetitionsHandler: adding arena member %u", GUID_LOPART(memberGUID));
|
||||
at->AddMember(memberGUID);
|
||||
result->NextRow();
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
// created
|
||||
sLog.outDebug("TURN IN PETITION GUID %u", GUID_LOPART(petitionguid));
|
||||
|
||||
data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
data << (uint32)PETITION_TURN_OK;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received CMSG_PETITION_SHOWLIST"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
SendPetitionShowList(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendPetitionShowList(uint64 guid)
|
||||
{
|
||||
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint8 count = 0;
|
||||
if (pCreature->isTabardDesigner())
|
||||
count = 1;
|
||||
else
|
||||
count = 3;
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6);
|
||||
data << guid; // npc guid
|
||||
data << count; // count
|
||||
if (count == 1)
|
||||
{
|
||||
data << uint32(1); // index
|
||||
data << uint32(GUILD_CHARTER); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(GUILD_CHARTER_COST); // charter cost
|
||||
data << uint32(0); // unknown
|
||||
data << uint32(9); // required signs?
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2v2
|
||||
data << uint32(1); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost
|
||||
data << uint32(2); // unknown
|
||||
data << uint32(2); // required signs?
|
||||
// 3v3
|
||||
data << uint32(2); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost
|
||||
data << uint32(3); // unknown
|
||||
data << uint32(3); // required signs?
|
||||
// 5v5
|
||||
data << uint32(3); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost
|
||||
data << uint32(5); // unknown
|
||||
data << uint32(5); // required signs?
|
||||
}
|
||||
//for (uint8 i = 0; i < count; ++i)
|
||||
//{
|
||||
// data << uint32(i); // index
|
||||
// data << uint32(GUILD_CHARTER); // charter entry
|
||||
// data << uint32(16161); // charter display id
|
||||
// data << uint32(GUILD_CHARTER_COST+i); // charter cost
|
||||
// data << uint32(0); // unknown
|
||||
// data << uint32(9); // required signs?
|
||||
//}
|
||||
SendPacket(&data);
|
||||
sLog.outDebug("Sent SMSG_PETITION_SHOWLIST");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "SocialMgr.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "Util.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1(SocialMgr);
|
||||
|
||||
PlayerSocial::PlayerSocial()
|
||||
{
|
||||
m_playerGUID = 0;
|
||||
}
|
||||
|
||||
PlayerSocial::~PlayerSocial()
|
||||
{
|
||||
m_playerSocialMap.clear();
|
||||
}
|
||||
|
||||
uint32 PlayerSocial::GetNumberOfSocialsWithFlag(SocialFlag flag)
|
||||
{
|
||||
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 friend_guid, 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;
|
||||
}
|
||||
|
||||
uint32 flag = SOCIAL_FLAG_FRIEND;
|
||||
if (ignore)
|
||||
flag = SOCIAL_FLAG_IGNORED;
|
||||
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr != m_playerSocialMap.end())
|
||||
{
|
||||
CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
|
||||
m_playerSocialMap[friend_guid].Flags |= flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
CharacterDatabase.PExecute("INSERT INTO character_social (guid, friend, flags) VALUES ('%u', '%u', '%u')", GetPlayerGUID(), friend_guid, flag);
|
||||
FriendInfo fi;
|
||||
fi.Flags |= flag;
|
||||
m_playerSocialMap[friend_guid] = fi;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlayerSocial::RemoveFromSocialList(uint32 friend_guid, bool ignore)
|
||||
{
|
||||
PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr == m_playerSocialMap.end()) // not exist
|
||||
return;
|
||||
|
||||
uint32 flag = SOCIAL_FLAG_FRIEND;
|
||||
if (ignore)
|
||||
flag = SOCIAL_FLAG_IGNORED;
|
||||
|
||||
itr->second.Flags &= ~flag;
|
||||
if (itr->second.Flags == 0)
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' AND friend = '%u'", GetPlayerGUID(), friend_guid);
|
||||
m_playerSocialMap.erase(itr);
|
||||
}
|
||||
else
|
||||
CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags & ~%u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
|
||||
}
|
||||
|
||||
void PlayerSocial::SetFriendNote(uint32 friend_guid, std::string note)
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr == m_playerSocialMap.end()) // not exist
|
||||
return;
|
||||
|
||||
utf8truncate(note,48); // DB and client size limitation
|
||||
|
||||
CharacterDatabase.escape_string(note);
|
||||
CharacterDatabase.PExecute("UPDATE character_social SET note = '%s' WHERE guid = '%u' AND friend = '%u'", note.c_str(), GetPlayerGUID(), friend_guid);
|
||||
m_playerSocialMap[friend_guid].Note = note;
|
||||
}
|
||||
|
||||
void PlayerSocial::SendSocialList()
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(GetPlayerGUID());
|
||||
if (!plr)
|
||||
return;
|
||||
|
||||
uint32 size = m_playerSocialMap.size();
|
||||
|
||||
WorldPacket data(SMSG_CONTACT_LIST, (4+4+size*25)); // just can guess size
|
||||
data << uint32(7); // unk flag (0x1, 0x2, 0x4), 0x7 if it include ignore list
|
||||
data << uint32(size); // friends count
|
||||
|
||||
for (PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
|
||||
{
|
||||
sSocialMgr.GetFriendInfo(plr, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_CONTACT_LIST");
|
||||
}
|
||||
|
||||
bool PlayerSocial::HasFriend(uint32 friend_guid)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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::FindPlayer(friendGUID);
|
||||
if (!pFriend)
|
||||
return;
|
||||
|
||||
uint32 team = player->GetTeam();
|
||||
AccountTypes security = player->GetSession()->GetSecurity();
|
||||
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
|
||||
AccountTypes gmLevelInWhoList = AccountTypes (sWorld.getConfig(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 && pFriend->GetName() &&
|
||||
(security > SEC_PLAYER ||
|
||||
((pFriend->GetTeam() == team || 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, 5);
|
||||
*data << uint8(result);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
void SocialMgr::SendFriendStatus(Player *player, FriendsResult result, uint32 friend_guid, bool broadcast)
|
||||
{
|
||||
FriendInfo fi;
|
||||
|
||||
WorldPacket data;
|
||||
MakeFriendStatusPacket(result, friend_guid, &data);
|
||||
GetFriendInfo(player, friend_guid, 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;
|
||||
|
||||
uint32 team = player->GetTeam();
|
||||
AccountTypes security = player->GetSession()->GetSecurity();
|
||||
uint32 guid = player->GetGUIDLow();
|
||||
AccountTypes gmLevelInWhoList = AccountTypes(sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
|
||||
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_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 && pFriend->IsInWorld() &&
|
||||
(pFriend->GetSession()->GetSecurity() > SEC_PLAYER ||
|
||||
((pFriend->GetTeam() == team || allowTwoSideWhoList) && security <= gmLevelInWhoList)) &&
|
||||
player->IsVisibleGloballyFor(pFriend))
|
||||
{
|
||||
pFriend->GetSession()->SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayerSocial *SocialMgr::LoadFromDB(QueryResult_AutoPtr result, uint32 guid)
|
||||
{
|
||||
PlayerSocial *social = &m_socialMap[guid];
|
||||
social->SetPlayerGUID(guid);
|
||||
|
||||
if (!result)
|
||||
return social;
|
||||
|
||||
uint32 friend_guid = 0;
|
||||
uint32 flags = 0;
|
||||
std::string note = "";
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
friend_guid = fields[0].GetUInt32();
|
||||
flags = fields[1].GetUInt32();
|
||||
note = fields[2].GetCppString();
|
||||
|
||||
social->m_playerSocialMap[friend_guid] = 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __TRINITY_SOCIALMGR_H
|
||||
#define __TRINITY_SOCIALMGR_H
|
||||
|
||||
#include "Policies/Singleton.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Common.h"
|
||||
|
||||
class SocialMgr;
|
||||
class PlayerSocial;
|
||||
class Player;
|
||||
class WorldPacket;
|
||||
|
||||
enum FriendStatus
|
||||
{
|
||||
FRIEND_STATUS_OFFLINE = 0,
|
||||
FRIEND_STATUS_ONLINE = 1,
|
||||
FRIEND_STATUS_AFK = 2,
|
||||
FRIEND_STATUS_UNK3 = 3,
|
||||
FRIEND_STATUS_DND = 4
|
||||
};
|
||||
|
||||
enum SocialFlag
|
||||
{
|
||||
SOCIAL_FLAG_FRIEND = 0x01,
|
||||
SOCIAL_FLAG_IGNORED = 0x02,
|
||||
SOCIAL_FLAG_MUTED = 0x04 // guessed
|
||||
};
|
||||
|
||||
struct FriendInfo
|
||||
{
|
||||
FriendStatus Status;
|
||||
uint32 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(uint32 flags, const std::string& 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 25
|
||||
|
||||
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 friend_guid, std::string note);
|
||||
// Packet send's
|
||||
void SendSocialList();
|
||||
// Misc
|
||||
bool HasFriend(uint32 friend_guid);
|
||||
bool HasIgnore(uint32 ignore_guid);
|
||||
uint32 GetPlayerGUID() { return m_playerGUID; }
|
||||
void SetPlayerGUID(uint32 guid) { m_playerGUID = guid; }
|
||||
uint32 GetNumberOfSocialsWithFlag(SocialFlag flag);
|
||||
private:
|
||||
PlayerSocialMap m_playerSocialMap;
|
||||
uint32 m_playerGUID;
|
||||
};
|
||||
|
||||
class SocialMgr
|
||||
{
|
||||
public:
|
||||
SocialMgr();
|
||||
~SocialMgr();
|
||||
// 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(QueryResult_AutoPtr result, uint32 guid);
|
||||
private:
|
||||
SocialMap m_socialMap;
|
||||
};
|
||||
|
||||
#define sSocialMgr Trinity::Singleton<SocialMgr>::Instance()
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Language.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Common.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "World.h"
|
||||
|
||||
void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ))
|
||||
{
|
||||
SendNotification(GetTrinityString(LANG_TICKET_REQ), sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()))
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_CREATE, 4);
|
||||
data << uint32(1); // 1 - You already have GM ticket
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 map;
|
||||
float x, y, z;
|
||||
std::string ticketText, ticketText2;
|
||||
|
||||
SendQueryTimeResponse();
|
||||
|
||||
WorldPacket data(SMSG_GMTICKET_CREATE, 4);
|
||||
recv_data >> map;
|
||||
recv_data >> x;
|
||||
recv_data >> y;
|
||||
recv_data >> z;
|
||||
recv_data >> ticketText;
|
||||
recv_data >> ticketText2;
|
||||
|
||||
GM_Ticket *ticket = new GM_Ticket;
|
||||
ticket->name = GetPlayer()->GetName();
|
||||
ticket->guid = objmgr.GenerateGMTicketId();
|
||||
ticket->playerGuid = GetPlayer()->GetGUID();
|
||||
ticket->message = ticketText;
|
||||
ticket->createtime = time(NULL);
|
||||
ticket->map = map;
|
||||
ticket->pos_x = x;
|
||||
ticket->pos_y = y;
|
||||
ticket->pos_z = z;
|
||||
ticket->timestamp = time(NULL);
|
||||
ticket->closed = 0;
|
||||
ticket->assignedToGM = 0;
|
||||
ticket->comment = "";
|
||||
|
||||
objmgr.AddOrUpdateGMTicket(*ticket, true);
|
||||
|
||||
data << uint32(2);
|
||||
SendPacket(&data);
|
||||
|
||||
sWorld.SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->guid);
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4);
|
||||
|
||||
std::string message;
|
||||
recv_data >> message;
|
||||
|
||||
GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID());
|
||||
if (!ticket)
|
||||
{
|
||||
data << uint32(1);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
ticket->message = message;
|
||||
ticket->timestamp = time(NULL);
|
||||
|
||||
objmgr.AddOrUpdateGMTicket(*ticket);
|
||||
|
||||
data << uint32(2);
|
||||
SendPacket(&data);
|
||||
|
||||
sWorld.SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->guid);
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
GM_Ticket* ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID());
|
||||
|
||||
if (ticket)
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4);
|
||||
data << uint32(9);
|
||||
SendPacket(&data);
|
||||
|
||||
sWorld.SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->guid);
|
||||
objmgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false);
|
||||
SendGMTicketGetTicket(0x0A, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
SendQueryTimeResponse();
|
||||
|
||||
GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID());
|
||||
if (ticket)
|
||||
SendGMTicketGetTicket(0x06, ticket->message.c_str());
|
||||
else
|
||||
SendGMTicketGetTicket(0x0A, 0);
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4);
|
||||
data << uint32(1);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text)
|
||||
{
|
||||
int len = text ? strlen(text) : 0;
|
||||
WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4));
|
||||
data << uint32(status); // standard 0x0A, 0x06 if text present
|
||||
data << uint32(1); // unk flags, if 0, can't edit the ticket
|
||||
if (status == 6)
|
||||
{
|
||||
data << text; // ticket text
|
||||
data << uint8(0x7); // ticket category
|
||||
data << float(0); // tickets in queue?
|
||||
data << float(0); // if > "tickets in queue" then "We are currently experiencing a high volume of petitions."
|
||||
data << float(0); // 0 - "Your ticket will be serviced soon", 1 - "Wait time currently unavailable"
|
||||
data << uint8(0); // if == 2 and next field == 1 then "Your ticket has been escalated"
|
||||
data << uint8(0); // const
|
||||
}
|
||||
SendPacket(&data);
|
||||
}
|
||||
@@ -0,0 +1,656 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "Item.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "Language.h"
|
||||
|
||||
enum TradeStatus
|
||||
{
|
||||
TRADE_STATUS_BUSY = 0,
|
||||
TRADE_STATUS_BEGIN_TRADE = 1,
|
||||
TRADE_STATUS_OPEN_WINDOW = 2,
|
||||
TRADE_STATUS_TRADE_CANCELED = 3,
|
||||
TRADE_STATUS_TRADE_ACCEPT = 4,
|
||||
TRADE_STATUS_BUSY_2 = 5,
|
||||
TRADE_STATUS_NO_TARGET = 6,
|
||||
TRADE_STATUS_BACK_TO_TRADE = 7,
|
||||
TRADE_STATUS_TRADE_COMPLETE = 8,
|
||||
// 9?
|
||||
TRADE_STATUS_TARGET_TO_FAR = 10,
|
||||
TRADE_STATUS_WRONG_FACTION = 11,
|
||||
TRADE_STATUS_CLOSE_WINDOW = 12,
|
||||
// 13?
|
||||
TRADE_STATUS_IGNORE_YOU = 14,
|
||||
TRADE_STATUS_YOU_STUNNED = 15,
|
||||
TRADE_STATUS_TARGET_STUNNED = 16,
|
||||
TRADE_STATUS_YOU_DEAD = 17,
|
||||
TRADE_STATUS_TARGET_DEAD = 18,
|
||||
TRADE_STATUS_YOU_LOGOUT = 19,
|
||||
TRADE_STATUS_TARGET_LOGOUT = 20,
|
||||
TRADE_STATUS_TRIAL_ACCOUNT = 21, // Trial accounts can not perform that action
|
||||
TRADE_STATUS_ONLY_CONJURED = 22 // You can only trade conjured items... (cross realm BG related).
|
||||
};
|
||||
|
||||
void WorldSession::SendTradeStatus(uint32 status)
|
||||
{
|
||||
WorldPacket data;
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case TRADE_STATUS_BEGIN_TRADE:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+8);
|
||||
data << uint32(status);
|
||||
data << uint64(0);
|
||||
break;
|
||||
case TRADE_STATUS_OPEN_WINDOW:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+4);
|
||||
data << uint32(status);
|
||||
data << uint32(0); // added in 2.4.0
|
||||
break;
|
||||
case TRADE_STATUS_CLOSE_WINDOW:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4);
|
||||
data << uint32(status);
|
||||
data << uint32(0);
|
||||
data << uint8(0);
|
||||
data << uint32(0);
|
||||
break;
|
||||
case TRADE_STATUS_ONLY_CONJURED:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+1);
|
||||
data << uint32(status);
|
||||
data << uint8(0);
|
||||
break;
|
||||
default:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4);
|
||||
data << uint32(status);
|
||||
break;
|
||||
}
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
sLog.outDebug("WORLD: Ignore Trade %u",_player->GetGUIDLow());
|
||||
// recvPacket.print_storage();
|
||||
}
|
||||
|
||||
void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
sLog.outDebug("WORLD: Busy Trade %u",_player->GetGUIDLow());
|
||||
// recvPacket.print_storage();
|
||||
}
|
||||
|
||||
void WorldSession::SendUpdateTrade()
|
||||
{
|
||||
Item *item = NULL;
|
||||
|
||||
if (!_player || !_player->pTrader)
|
||||
return;
|
||||
|
||||
// reset trade status
|
||||
if (_player->acceptTrade)
|
||||
{
|
||||
_player->acceptTrade = false;
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
}
|
||||
|
||||
if (_player->pTrader->acceptTrade)
|
||||
{
|
||||
_player->pTrader->acceptTrade = false;
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size
|
||||
data << (uint8) 1; // can be different (only seen 0 and 1)
|
||||
data << (uint32) 0; // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?)
|
||||
data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = next field in most cases
|
||||
data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = prev field in most cases
|
||||
data << (uint32) _player->pTrader->tradeGold; // trader gold
|
||||
data << (uint32) 0; // spell casted on lowest slot item
|
||||
|
||||
for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
|
||||
{
|
||||
item = (_player->pTrader->tradeItems[i] != 0 ? _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]) : NULL);
|
||||
|
||||
data << (uint8) i; // trade slot number, if not specified, then end of packet
|
||||
|
||||
if (item)
|
||||
{
|
||||
data << (uint32) item->GetProto()->ItemId; // entry
|
||||
// display id
|
||||
data << (uint32) item->GetProto()->DisplayInfoID;
|
||||
// stack count
|
||||
data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT);
|
||||
data << (uint32) 0; // probably gift=1, created_by=0?
|
||||
// gift creator
|
||||
data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR);
|
||||
data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT);
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
data << (uint32) 0; // enchantment id (permanent/gems?)
|
||||
// creator
|
||||
data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR);
|
||||
data << (uint32) item->GetSpellCharges(); // charges
|
||||
data << (uint32) item->GetItemSuffixFactor(); // SuffixFactor
|
||||
// random properties id
|
||||
data << (int32) item->GetItemRandomPropertyId();
|
||||
data << (uint32) item->GetProto()->LockID; // lock id
|
||||
// max durability
|
||||
data << (uint32) item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
|
||||
// durability
|
||||
data << (uint32) item->GetUInt32Value(ITEM_FIELD_DURABILITY);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 j = 0; j < 18; j++)
|
||||
data << uint32(0);
|
||||
}
|
||||
}
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
// transfer the items to the players
|
||||
|
||||
void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
|
||||
{
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
ItemPosCountVec traderDst;
|
||||
ItemPosCountVec playerDst;
|
||||
bool traderCanTrade = (myItems[i] == NULL || _player->pTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK);
|
||||
bool playerCanTrade = (hisItems[i] == NULL || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK);
|
||||
if (traderCanTrade && playerCanTrade)
|
||||
{
|
||||
// Ok, if trade item exists and can be stored
|
||||
// If we trade in both directions we had to check, if the trade will work before we actually do it
|
||||
// A roll back is not possible after we stored it
|
||||
if (myItems[i])
|
||||
{
|
||||
// logging
|
||||
sLog.outDebug("partner storing: %u",myItems[i]->GetGUIDLow());
|
||||
if (_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
||||
{
|
||||
sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
|
||||
_player->GetName(),_player->GetSession()->GetAccountId(),
|
||||
myItems[i]->GetProto()->Name1,myItems[i]->GetEntry(),myItems[i]->GetCount(),
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
// store
|
||||
_player->pTrader->MoveItemToInventory(traderDst, myItems[i], true, true);
|
||||
}
|
||||
if (hisItems[i])
|
||||
{
|
||||
// logging
|
||||
sLog.outDebug("player storing: %u",hisItems[i]->GetGUIDLow());
|
||||
if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
||||
{
|
||||
sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
|
||||
hisItems[i]->GetProto()->Name1,hisItems[i]->GetEntry(),hisItems[i]->GetCount(),
|
||||
_player->GetName(),_player->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
// store
|
||||
_player->MoveItemToInventory(playerDst, hisItems[i], true, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// in case of fatal error log error message
|
||||
// return the already removed items to the original owner
|
||||
if (myItems[i])
|
||||
{
|
||||
if (!traderCanTrade)
|
||||
sLog.outError("trader can't store item: %u",myItems[i]->GetGUIDLow());
|
||||
if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK)
|
||||
_player->MoveItemToInventory(playerDst, myItems[i], true, true);
|
||||
else
|
||||
sLog.outError("player can't take item back: %u",myItems[i]->GetGUIDLow());
|
||||
}
|
||||
// return the already removed items to the original owner
|
||||
if (hisItems[i])
|
||||
{
|
||||
if (!playerCanTrade)
|
||||
sLog.outError("player can't store item: %u",hisItems[i]->GetGUIDLow());
|
||||
if (_player->pTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK)
|
||||
_player->pTrader->MoveItemToInventory(traderDst, hisItems[i], true, true);
|
||||
else
|
||||
sLog.outError("trader can't take item back: %u",hisItems[i]->GetGUIDLow());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
|
||||
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
Item *myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
Item *hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
bool myCanCompleteTrade=true,hisCanCompleteTrade=true;
|
||||
|
||||
if (!GetPlayer()->pTrader)
|
||||
return;
|
||||
|
||||
// not accept case incorrect money amount
|
||||
if (_player->tradeGold > _player->GetMoney())
|
||||
{
|
||||
SendNotification(LANG_NOT_ENOUGH_GOLD);
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->acceptTrade = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// not accept case incorrect money amount
|
||||
if (_player->pTrader->tradeGold > _player->pTrader->GetMoney())
|
||||
{
|
||||
_player->pTrader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD);
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->pTrader->acceptTrade = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// not accept if some items now can't be trade (cheating)
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
if (_player->tradeItems[i] != 0)
|
||||
{
|
||||
if (Item* item =_player->GetItemByGuid(_player->tradeItems[i]))
|
||||
{
|
||||
if (!item->CanBeTraded())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_player->pTrader->tradeItems[i] != 0)
|
||||
{
|
||||
if (Item* item =_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]))
|
||||
{
|
||||
if (!item->CanBeTraded())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_player->acceptTrade = true;
|
||||
if (_player->pTrader->acceptTrade)
|
||||
{
|
||||
// inform partner client
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT);
|
||||
|
||||
// store items in local list and set 'in-trade' flag
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
if (_player->tradeItems[i] != 0)
|
||||
{
|
||||
//Can return NULL
|
||||
myItems[i] = _player->GetItemByGuid(_player->tradeItems[i]);
|
||||
if (myItems[i])
|
||||
{
|
||||
myItems[i]->SetInTrade();
|
||||
sLog.outDebug("Player trade item bag: %u slot: %u", myItems[i]->GetBagSlot(), myItems[i]->GetSlot());
|
||||
}
|
||||
}
|
||||
if (_player->pTrader->tradeItems[i] != 0)
|
||||
{
|
||||
//Can return NULL
|
||||
hisItems[i]=_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]);
|
||||
if (hisItems[i])
|
||||
{
|
||||
hisItems[i]->SetInTrade();
|
||||
sLog.outDebug("Player trade item bag: %u slot: %u", hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test if item will fit in each inventory
|
||||
hisCanCompleteTrade = (_player->pTrader->CanStoreItems(myItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK);
|
||||
myCanCompleteTrade = (_player->CanStoreItems(hisItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK);
|
||||
|
||||
// clear 'in-trade' flag
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
if (myItems[i]) myItems[i]->SetInTrade(false);
|
||||
if (hisItems[i]) hisItems[i]->SetInTrade(false);
|
||||
}
|
||||
|
||||
// in case of missing space report error
|
||||
if (!myCanCompleteTrade)
|
||||
{
|
||||
SendNotification(LANG_NOT_FREE_TRADE_SLOTS);
|
||||
GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS);
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
return;
|
||||
}
|
||||
else if (!hisCanCompleteTrade)
|
||||
{
|
||||
SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS);
|
||||
GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS);
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
return;
|
||||
}
|
||||
|
||||
// execute trade: 1. remove
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
Item* iPtr = NULL;
|
||||
if (myItems[i])
|
||||
{
|
||||
myItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID());
|
||||
iPtr = _player->GetItemByGuid(_player->tradeItems[i]);
|
||||
_player->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true);
|
||||
}
|
||||
if (hisItems[i])
|
||||
{
|
||||
hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR,_player->pTrader->GetGUID());
|
||||
iPtr = _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]);
|
||||
_player->pTrader->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true);
|
||||
}
|
||||
}
|
||||
|
||||
// execute trade: 2. store
|
||||
moveItems(myItems, hisItems);
|
||||
|
||||
// logging money
|
||||
if (sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
||||
{
|
||||
if (_player->GetSession()->GetSecurity() > SEC_PLAYER && _player->tradeGold > 0)
|
||||
{
|
||||
sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
|
||||
_player->GetName(),_player->GetSession()->GetAccountId(),
|
||||
_player->tradeGold,
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
|
||||
}
|
||||
if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && _player->pTrader->tradeGold > 0)
|
||||
{
|
||||
sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
|
||||
_player->pTrader->tradeGold,
|
||||
_player->GetName(),_player->GetSession()->GetAccountId());
|
||||
}
|
||||
}
|
||||
|
||||
// update money
|
||||
_player->ModifyMoney(-int32(_player->tradeGold));
|
||||
_player->ModifyMoney(_player->pTrader->tradeGold);
|
||||
_player->pTrader->ModifyMoney(-int32(_player->pTrader->tradeGold));
|
||||
_player->pTrader->ModifyMoney(_player->tradeGold);
|
||||
|
||||
_player->ClearTrade();
|
||||
_player->pTrader->ClearTrade();
|
||||
|
||||
// desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
|
||||
CharacterDatabase.BeginTransaction();
|
||||
_player->SaveInventoryAndGoldToDB();
|
||||
_player->pTrader->SaveInventoryAndGoldToDB();
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE);
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE);
|
||||
|
||||
_player->pTrader->pTrader = NULL;
|
||||
_player->pTrader = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
if (!GetPlayer()->pTrader)
|
||||
return;
|
||||
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->acceptTrade = false;
|
||||
}
|
||||
|
||||
void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW);
|
||||
_player->pTrader->ClearTrade();
|
||||
|
||||
SendTradeStatus(TRADE_STATUS_OPEN_WINDOW);
|
||||
_player->ClearTrade();
|
||||
}
|
||||
|
||||
void WorldSession::SendCancelTrade()
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
}
|
||||
|
||||
void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
// sended also after LOGOUT COMPLETE
|
||||
if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
|
||||
_player->TradeCancel(true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (GetPlayer()->pTrader)
|
||||
return;
|
||||
|
||||
uint64 ID;
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_STUNNED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLogingOut())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_LOGOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer()->isInFlight())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ))
|
||||
{
|
||||
SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ));
|
||||
return;
|
||||
}
|
||||
|
||||
recvPacket >> ID;
|
||||
|
||||
Player* pOther = ObjectAccessor::FindPlayer(ID);
|
||||
|
||||
if (!pOther)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_NO_TARGET);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther == GetPlayer() || pOther->pTrader)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_BUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pOther->isAlive())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->isInFlight())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->hasUnitState(UNIT_STAT_STUNNED))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_STUNNED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->GetSession()->isLogingOut())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_IGNORE_YOU);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_WRONG_FACTION);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pOther->IsWithinDistInMap(_player,10.0f,false))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ))
|
||||
{
|
||||
SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ));
|
||||
return;
|
||||
}
|
||||
|
||||
// OK start trade
|
||||
_player->pTrader = pOther;
|
||||
pOther->pTrader =_player;
|
||||
|
||||
WorldPacket data(SMSG_TRADE_STATUS, 12);
|
||||
data << (uint32) TRADE_STATUS_BEGIN_TRADE;
|
||||
data << (uint64)_player->GetGUID();
|
||||
_player->pTrader->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
uint32 gold;
|
||||
|
||||
recvPacket >> gold;
|
||||
|
||||
// gold can be incorrect, but this is checked at trade finished.
|
||||
_player->tradeGold = gold;
|
||||
|
||||
_player->pTrader->GetSession()->SendUpdateTrade();
|
||||
}
|
||||
|
||||
void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
// send update
|
||||
uint8 tradeSlot;
|
||||
uint8 bag;
|
||||
uint8 slot;
|
||||
|
||||
recvPacket >> tradeSlot;
|
||||
recvPacket >> bag;
|
||||
recvPacket >> slot;
|
||||
|
||||
// invalid slot number
|
||||
if (tradeSlot >= TRADE_SLOT_COUNT)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
// check cheating, can't fail with correct client operations
|
||||
Item* item = _player->GetItemByPos(bag,slot);
|
||||
if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded()))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 iGUID = item->GetGUID();
|
||||
|
||||
// prevent place single item into many trade slots using cheating and client bugs
|
||||
for (int i = 0; i < TRADE_SLOT_COUNT; ++i)
|
||||
{
|
||||
if (_player->tradeItems[i] == iGUID)
|
||||
{
|
||||
// cheating attempt
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_player->tradeItems[tradeSlot] = iGUID;
|
||||
|
||||
_player->pTrader->GetSession()->SendUpdateTrade();
|
||||
}
|
||||
|
||||
void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
uint8 tradeSlot;
|
||||
recvPacket >> tradeSlot;
|
||||
|
||||
// invalid slot number
|
||||
if (tradeSlot >= TRADE_SLOT_COUNT)
|
||||
return;
|
||||
|
||||
_player->tradeItems[tradeSlot] = 0;
|
||||
|
||||
_player->pTrader->GetSession()->SendUpdateTrade();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Log.h"
|
||||
|
||||
void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_VOICE_SESSION_ENABLE");
|
||||
// uint8 isVoiceEnabled, uint8 isMicrophoneEnabled
|
||||
recv_data.read_skip<uint8>();
|
||||
recv_data.read_skip<uint8>();
|
||||
recv_data.hexlike();
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_CHANNEL_VOICE_ON");
|
||||
// Enable Voice button in channel context menu
|
||||
recv_data.hexlike();
|
||||
}
|
||||
|
||||
void WorldSession::HandleSetActiveVoiceChannel(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_SET_ACTIVE_VOICE_CHANNEL");
|
||||
recv_data.read_skip<uint32>();
|
||||
recv_data.read_skip<char*>();
|
||||
recv_data.hexlike();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Totem.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Log.h"
|
||||
#include "Group.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
Totem::Totem(SummonPropertiesEntry const *properties, Unit *owner) : Minion(properties, owner)
|
||||
{
|
||||
m_unitTypeMask |= UNIT_MASK_TOTEM;
|
||||
m_duration = 0;
|
||||
m_type = TOTEM_PASSIVE;
|
||||
}
|
||||
|
||||
void Totem::Update(uint32 time)
|
||||
{
|
||||
if (!m_owner->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)
|
||||
{
|
||||
Minion::InitStats(duration);
|
||||
|
||||
CreatureInfo const *cinfo = GetCreatureInfo();
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER && cinfo)
|
||||
{
|
||||
uint32 display_id = objmgr.ChooseDisplayId(m_owner->ToPlayer()->GetTeam(), cinfo);
|
||||
CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
|
||||
if (minfo)
|
||||
display_id = minfo->modelid;
|
||||
switch (m_owner->ToPlayer()->GetTeam())
|
||||
{
|
||||
case ALLIANCE:
|
||||
display_id = cinfo->Modelid1;
|
||||
break;
|
||||
case HORDE:
|
||||
if (cinfo->Modelid3)
|
||||
display_id = cinfo->Modelid3;
|
||||
else
|
||||
display_id = cinfo->Modelid1;
|
||||
|
||||
switch (((Player*)m_owner)->getRace())
|
||||
{
|
||||
case RACE_ORC:
|
||||
if (cinfo->Modelid2)
|
||||
display_id = cinfo->Modelid2;
|
||||
else
|
||||
display_id = cinfo->Modelid1;
|
||||
break;
|
||||
case RACE_TROLL:
|
||||
if (cinfo->Modelid4)
|
||||
display_id = cinfo->Modelid4;
|
||||
else
|
||||
display_id = cinfo->Modelid1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SetDisplayId(display_id);
|
||||
}
|
||||
|
||||
// Get spell casted by totem
|
||||
SpellEntry const * totemSpell = sSpellStore.LookupEntry(GetSpell());
|
||||
if (totemSpell)
|
||||
{
|
||||
// If spell have cast time -> so its active totem
|
||||
if (GetSpellCastTime(totemSpell))
|
||||
m_type = TOTEM_ACTIVE;
|
||||
}
|
||||
|
||||
if (GetEntry() == SENTRY_TOTEM_ENTRY)
|
||||
SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
m_duration = duration;
|
||||
|
||||
SetLevel(m_owner->getLevel());
|
||||
}
|
||||
|
||||
void Totem::InitSummon()
|
||||
{
|
||||
if (m_type == TOTEM_PASSIVE)
|
||||
CastSpell(this, GetSpell(), true);
|
||||
|
||||
// Some totems can have both instant effect and passive spell
|
||||
if (GetSpell(1))
|
||||
CastSpell(this, GetSpell(1), true);
|
||||
}
|
||||
|
||||
void Totem::UnSummon()
|
||||
{
|
||||
CombatStop();
|
||||
RemoveAurasDueToSpell(GetSpell());
|
||||
|
||||
// clear owner's totem slot
|
||||
for (int 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());
|
||||
|
||||
//remove aura all party members too
|
||||
Group *pGroup = NULL;
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
m_owner->ToPlayer()->SendAutoRepeatCancel(this);
|
||||
// Not only the player can summon the totem (scripted AI)
|
||||
pGroup = m_owner->ToPlayer()->GetGroup();
|
||||
if (pGroup)
|
||||
{
|
||||
for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player* Target = itr->getSource();
|
||||
if (Target && pGroup->SameSubGroup((Player*)m_owner, Target))
|
||||
Target->RemoveAurasDueToSpell(GetSpell());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
bool Totem::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
|
||||
{
|
||||
// TODO: possibly all negative auras immune?
|
||||
if (GetEntry() == 5925)
|
||||
return false;
|
||||
switch(spellInfo->EffectApplyAuraName[index])
|
||||
{
|
||||
case SPELL_AURA_PERIODIC_DAMAGE:
|
||||
case SPELL_AURA_PERIODIC_LEECH:
|
||||
case SPELL_AURA_MOD_FEAR:
|
||||
case SPELL_AURA_TRANSFORM:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Creature::IsImmunedToSpellEffect(spellInfo, index);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_TOTEM_H
|
||||
#define TRINITYCORE_TOTEM_H
|
||||
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum TotemType
|
||||
{
|
||||
TOTEM_PASSIVE = 0,
|
||||
TOTEM_ACTIVE = 1,
|
||||
TOTEM_STATUE = 2 // copied straight from MaNGOS, may need more implementation to work
|
||||
};
|
||||
|
||||
#define SENTRY_TOTEM_ENTRY 3968
|
||||
|
||||
class Totem : public Minion
|
||||
{
|
||||
public:
|
||||
explicit Totem(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
virtual ~Totem(){};
|
||||
void Update(uint32 time);
|
||||
void InitStats(uint32 duration);
|
||||
void InitSummon();
|
||||
void UnSummon();
|
||||
uint32 GetSpell(uint8 slot=0) const { return m_spells[slot]; }
|
||||
uint32 GetTotemDuration() const { return m_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(SpellEntry const* spellInfo, uint32 index) const;
|
||||
|
||||
protected:
|
||||
TotemType m_type;
|
||||
uint32 m_duration;
|
||||
};
|
||||
#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
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Unit.h"
|
||||
#include "Util.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "ZoneScript.h"
|
||||
|
||||
Vehicle::Vehicle(Unit *unit, VehicleEntry const *vehInfo) : me(unit), m_vehicleInfo(vehInfo), m_usableSeatNum(0)
|
||||
{
|
||||
for (uint32 i = 0; i < 8; ++i)
|
||||
{
|
||||
if (uint32 seatId = m_vehicleInfo->m_seatID[i])
|
||||
if (VehicleSeatEntry const *veSeat = sVehicleSeatStore.LookupEntry(seatId))
|
||||
{
|
||||
m_Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
|
||||
if (veSeat->IsUsable())
|
||||
++m_usableSeatNum;
|
||||
}
|
||||
}
|
||||
assert(!m_Seats.empty());
|
||||
}
|
||||
|
||||
Vehicle::~Vehicle()
|
||||
{
|
||||
for (SeatMap::const_iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
|
||||
assert(!itr->second.passenger);
|
||||
}
|
||||
|
||||
void Vehicle::Install()
|
||||
{
|
||||
if (Creature *cre = dynamic_cast<Creature*>(me))
|
||||
{
|
||||
if (m_vehicleInfo->m_powerType == POWER_STEAM)
|
||||
{
|
||||
me->setPowerType(POWER_ENERGY);
|
||||
me->SetMaxPower(POWER_ENERGY, 100);
|
||||
}
|
||||
else if (m_vehicleInfo->m_powerType == POWER_PYRITE)
|
||||
{
|
||||
me->setPowerType(POWER_ENERGY);
|
||||
me->SetMaxPower(POWER_ENERGY, 50);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_SPELL_VEHICLE; ++i)
|
||||
{
|
||||
if (!cre->m_spells[i])
|
||||
continue;
|
||||
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(cre->m_spells[i]);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (spellInfo->powerType == POWER_MANA)
|
||||
break;
|
||||
|
||||
if (spellInfo->powerType == POWER_ENERGY)
|
||||
{
|
||||
me->setPowerType(POWER_ENERGY);
|
||||
me->SetMaxPower(POWER_ENERGY, 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Vehicle::InstallAllAccessories()
|
||||
{
|
||||
VehicleAccessoryList const* mVehicleList = objmgr.GetVehicleAccessoryList(me->GetEntry());
|
||||
if (!mVehicleList)
|
||||
return;
|
||||
|
||||
for (VehicleAccessoryList::const_iterator itr = mVehicleList->begin(); itr != mVehicleList->end(); ++itr)
|
||||
InstallAccessory(itr->uiAccessory, itr->uiSeat, itr->bMinion);
|
||||
}
|
||||
|
||||
void Vehicle::Uninstall()
|
||||
{
|
||||
sLog.outDebug("Vehicle::Uninstall %u", me->GetEntry());
|
||||
for (SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
|
||||
if (Unit *passenger = itr->second.passenger)
|
||||
if (passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY))
|
||||
passenger->ToTempSummon()->UnSummon();
|
||||
RemoveAllPassengers();
|
||||
}
|
||||
|
||||
void Vehicle::Die()
|
||||
{
|
||||
sLog.outDebug("Vehicle::Die %u", me->GetEntry());
|
||||
for (SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
|
||||
if (Unit *passenger = itr->second.passenger)
|
||||
if (passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY))
|
||||
passenger->setDeathState(JUST_DIED);
|
||||
RemoveAllPassengers();
|
||||
}
|
||||
|
||||
void Vehicle::Reset()
|
||||
{
|
||||
sLog.outDebug("Vehicle::Reset");
|
||||
if (me->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (m_usableSeatNum)
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
InstallAllAccessories();
|
||||
if (m_usableSeatNum)
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::RemoveAllPassengers()
|
||||
{
|
||||
sLog.outDebug("Vehicle::RemoveAllPassengers");
|
||||
for (SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
|
||||
if (Unit *passenger = itr->second.passenger)
|
||||
{
|
||||
if (passenger->IsVehicle())
|
||||
passenger->GetVehicleKit()->RemoveAllPassengers();
|
||||
if (passenger->GetVehicle() != this)
|
||||
sLog.outCrash("Vehicle %u has invalid passenger %u.", me->GetEntry(), passenger->GetEntry());
|
||||
passenger->ExitVehicle();
|
||||
if (itr->second.passenger)
|
||||
{
|
||||
sLog.outCrash("Vehicle %u cannot remove passenger %u. %u is still on vehicle.", me->GetEntry(), passenger->GetEntry(), itr->second.passenger->GetEntry());
|
||||
//assert(!itr->second.passenger);
|
||||
itr->second.passenger = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Vehicle::HasEmptySeat(int8 seatId) const
|
||||
{
|
||||
SeatMap::const_iterator seat = m_Seats.find(seatId);
|
||||
if (seat == m_Seats.end()) return false;
|
||||
return !seat->second.passenger;
|
||||
}
|
||||
|
||||
Unit *Vehicle::GetPassenger(int8 seatId) const
|
||||
{
|
||||
SeatMap::const_iterator seat = m_Seats.find(seatId);
|
||||
if (seat == m_Seats.end()) return NULL;
|
||||
return seat->second.passenger;
|
||||
}
|
||||
|
||||
int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
|
||||
{
|
||||
SeatMap::const_iterator seat = m_Seats.find(seatId);
|
||||
if (seat == m_Seats.end()) return -1;
|
||||
while (seat->second.passenger || !seat->second.seatInfo->IsUsable())
|
||||
{
|
||||
if (next)
|
||||
{
|
||||
++seat;
|
||||
if (seat == m_Seats.end())
|
||||
seat = m_Seats.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (seat == m_Seats.begin())
|
||||
seat = m_Seats.end();
|
||||
--seat;
|
||||
}
|
||||
if (seat->first == seatId)
|
||||
return -1; // no available seat
|
||||
}
|
||||
return seat->first;
|
||||
}
|
||||
|
||||
void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion)
|
||||
{
|
||||
if (Unit *passenger = GetPassenger(seatId))
|
||||
{
|
||||
// already installed
|
||||
if (passenger->GetEntry() == entry)
|
||||
{
|
||||
assert(passenger->GetTypeId() == TYPEID_UNIT);
|
||||
if (me->GetTypeId() == TYPEID_UNIT && me->ToCreature()->IsInEvadeMode() && passenger->ToCreature()->IsAIEnabled)
|
||||
passenger->ToCreature()->AI()->EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
passenger->ExitVehicle(); // this should not happen
|
||||
}
|
||||
|
||||
//TODO: accessory should be minion
|
||||
if (Creature *accessory = me->SummonCreature(entry, *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000))
|
||||
{
|
||||
if (minion)
|
||||
accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
|
||||
accessory->EnterVehicle(this, seatId);
|
||||
// This is not good, we have to send update twice
|
||||
accessory->SendMovementFlagUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
bool Vehicle::AddPassenger(Unit *unit, int8 seatId)
|
||||
{
|
||||
if (unit->GetVehicle() != this)
|
||||
return false;
|
||||
|
||||
SeatMap::iterator seat;
|
||||
if (seatId < 0) // no specific seat requirement
|
||||
{
|
||||
for (seat = m_Seats.begin(); seat != m_Seats.end(); ++seat)
|
||||
if (!seat->second.passenger && seat->second.seatInfo->IsUsable())
|
||||
break;
|
||||
|
||||
if (seat == m_Seats.end()) // no available seat
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
seat = m_Seats.find(seatId);
|
||||
if (seat == m_Seats.end())
|
||||
return false;
|
||||
|
||||
if (seat->second.passenger)
|
||||
seat->second.passenger->ExitVehicle();
|
||||
|
||||
assert(!seat->second.passenger);
|
||||
}
|
||||
|
||||
sLog.outDebug("Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName(), me->GetEntry(), m_vehicleInfo->m_ID, me->GetGUIDLow(), (int32)seat->first);
|
||||
|
||||
seat->second.passenger = unit;
|
||||
if (seat->second.seatInfo->IsUsable())
|
||||
{
|
||||
assert(m_usableSeatNum);
|
||||
--m_usableSeatNum;
|
||||
if (!m_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 (seat->second.seatInfo->m_flags && !(seat->second.seatInfo->m_flags & 0x400))
|
||||
unit->addUnitState(UNIT_STAT_ONVEHICLE);
|
||||
|
||||
//SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
|
||||
|
||||
unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
VehicleSeatEntry const *veSeat = seat->second.seatInfo;
|
||||
unit->m_movementInfo.t_x = veSeat->m_attachmentOffsetX;
|
||||
unit->m_movementInfo.t_y = veSeat->m_attachmentOffsetY;
|
||||
unit->m_movementInfo.t_z = veSeat->m_attachmentOffsetZ;
|
||||
unit->m_movementInfo.t_o = 0;
|
||||
unit->m_movementInfo.t_time = 0; // 1 for player
|
||||
unit->m_movementInfo.t_seat = seat->first;
|
||||
|
||||
if (me->GetTypeId() == TYPEID_UNIT
|
||||
&& unit->GetTypeId() == TYPEID_PLAYER
|
||||
&& seat->first == 0 && seat->second.seatInfo->m_flags & 0x800) // not right
|
||||
if (!me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
|
||||
assert(false);
|
||||
|
||||
if (me->IsInWorld())
|
||||
{
|
||||
unit->SendMonsterMoveTransport(me);
|
||||
|
||||
if (me->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (me->ToCreature()->IsAIEnabled)
|
||||
me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true);
|
||||
|
||||
// update all passenger's positions
|
||||
RelocatePassengers(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||
}
|
||||
}
|
||||
|
||||
//if (unit->GetTypeId() == TYPEID_PLAYER)
|
||||
// unit->ToPlayer()->SendTeleportAckPacket();
|
||||
//unit->SendMovementFlagUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Vehicle::RemovePassenger(Unit *unit)
|
||||
{
|
||||
if (unit->GetVehicle() != this)
|
||||
return;
|
||||
|
||||
SeatMap::iterator seat;
|
||||
for (seat = m_Seats.begin(); seat != m_Seats.end(); ++seat)
|
||||
if (seat->second.passenger == unit)
|
||||
break;
|
||||
|
||||
assert(seat != m_Seats.end());
|
||||
|
||||
sLog.outDebug("Unit %s exit vehicle entry %u id %u dbguid %u seat %d", unit->GetName(), me->GetEntry(), m_vehicleInfo->m_ID, me->GetGUIDLow(), (int32)seat->first);
|
||||
|
||||
seat->second.passenger = NULL;
|
||||
if (seat->second.seatInfo->IsUsable())
|
||||
{
|
||||
if (!m_usableSeatNum)
|
||||
{
|
||||
if (me->GetTypeId() == TYPEID_PLAYER)
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
|
||||
else
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
|
||||
}
|
||||
++m_usableSeatNum;
|
||||
}
|
||||
|
||||
unit->clearUnitState(UNIT_STAT_ONVEHICLE);
|
||||
|
||||
//SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
|
||||
|
||||
if (me->GetTypeId() == TYPEID_UNIT
|
||||
&& unit->GetTypeId() == TYPEID_PLAYER
|
||||
&& seat->first == 0 && seat->second.seatInfo->m_flags & 0x800)
|
||||
me->RemoveCharmedBy(unit);
|
||||
|
||||
if (me->GetTypeId() == TYPEID_UNIT && me->ToCreature()->IsAIEnabled)
|
||||
me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, false);
|
||||
|
||||
// only for flyable vehicles
|
||||
if (unit->HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
|
||||
me->CastSpell(unit, 45472, true); // Parachute
|
||||
}
|
||||
|
||||
void Vehicle::RelocatePassengers(float x, float y, float z, float ang)
|
||||
{
|
||||
Map *map = me->GetMap();
|
||||
assert(map != NULL);
|
||||
|
||||
// not sure that absolute position calculation is correct, it must depend on vehicle orientation and pitch angle
|
||||
for (SeatMap::const_iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
|
||||
if (Unit *passenger = itr->second.passenger)
|
||||
{
|
||||
float px = x + passenger->m_movementInfo.t_x;
|
||||
float py = y + passenger->m_movementInfo.t_y;
|
||||
float pz = z + passenger->m_movementInfo.t_z;
|
||||
float po = ang + passenger->m_movementInfo.t_o;
|
||||
|
||||
passenger->SetPosition(px, py, pz, po);
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::Dismiss()
|
||||
{
|
||||
sLog.outDebug("Vehicle::Dismiss %u", me->GetEntry());
|
||||
Uninstall();
|
||||
me->SendObjectDeSpawnAnim(me->GetGUID());
|
||||
me->CombatStop();
|
||||
me->AddObjectToRemoveList();
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __TRINITY_VEHICLE_H
|
||||
#define __TRINITY_VEHICLE_H
|
||||
|
||||
#include "ObjectDefines.h"
|
||||
|
||||
struct VehicleEntry;
|
||||
struct VehicleSeatEntry;
|
||||
class Unit;
|
||||
|
||||
enum PowerType
|
||||
{
|
||||
POWER_STEAM = 61,
|
||||
POWER_PYRITE = 41,
|
||||
};
|
||||
|
||||
struct VehicleSeat
|
||||
{
|
||||
explicit VehicleSeat(VehicleSeatEntry const *_seatInfo) : seatInfo(_seatInfo), passenger(NULL) {}
|
||||
VehicleSeatEntry const *seatInfo;
|
||||
Unit* passenger;
|
||||
};
|
||||
|
||||
struct VehicleAccessory
|
||||
{
|
||||
explicit VehicleAccessory(uint32 _uiAccessory, int8 _uiSeat, bool _bMinion) : uiAccessory(_uiAccessory), uiSeat(_uiSeat), bMinion(_bMinion) {}
|
||||
uint32 uiAccessory;
|
||||
int8 uiSeat;
|
||||
uint32 bMinion;
|
||||
};
|
||||
|
||||
typedef std::vector<VehicleAccessory> VehicleAccessoryList;
|
||||
typedef std::map<uint32, VehicleAccessoryList> VehicleAccessoryMap;
|
||||
|
||||
typedef std::map<int8, VehicleSeat> SeatMap;
|
||||
|
||||
class Vehicle
|
||||
{
|
||||
public:
|
||||
explicit Vehicle(Unit *unit, VehicleEntry const *vehInfo);
|
||||
virtual ~Vehicle();
|
||||
|
||||
void Install();
|
||||
void Uninstall();
|
||||
void Reset();
|
||||
void Die();
|
||||
void InstallAllAccessories();
|
||||
|
||||
Unit *GetBase() const { return me; }
|
||||
VehicleEntry const *GetVehicleInfo() { return m_vehicleInfo; }
|
||||
|
||||
bool HasEmptySeat(int8 seatId) const;
|
||||
Unit *GetPassenger(int8 seatId) const;
|
||||
int8 GetNextEmptySeat(int8 seatId, bool next) const;
|
||||
bool AddPassenger(Unit *passenger, int8 seatId = -1);
|
||||
void RemovePassenger(Unit *passenger);
|
||||
void RelocatePassengers(float x, float y, float z, float ang);
|
||||
void RemoveAllPassengers();
|
||||
void Dismiss();
|
||||
bool IsVehicleInUse() { return m_Seats.begin() != m_Seats.end(); }
|
||||
|
||||
SeatMap m_Seats;
|
||||
|
||||
protected:
|
||||
Unit *me;
|
||||
VehicleEntry const *m_vehicleInfo;
|
||||
uint32 m_usableSeatNum;
|
||||
|
||||
void InstallAccessory(uint32 entry, int8 seatId, bool minion = true);
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user