rearranged core files

--HG--
branch : trunk
This commit is contained in:
Rat
2010-06-05 23:40:08 +02:00
parent 6a9357b13d
commit 75b80d9f5b
332 changed files with 0 additions and 0 deletions
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
+235
View File
@@ -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;
}
+75
View File
@@ -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
+356
View File
@@ -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
+243
View File
@@ -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);
}
+97
View File
@@ -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
+743
View File
@@ -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 &notifier) const { GetMap()->VisitAll(GetPositionX(), GetPositionY(), radius, notifier); }
template<class NOTIFIER> void VisitNearbyGridObject(const float &radius, NOTIFIER &notifier) const { GetMap()->VisitGrid(GetPositionX(), GetPositionY(), radius, notifier); }
template<class NOTIFIER> void VisitNearbyWorldObject(const float &radius, NOTIFIER &notifier) 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
+254
View File
@@ -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
+813
View File
@@ -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;
}
+161
View File
@@ -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();
}
+182
View File
@@ -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);
}
+64
View File
@@ -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