2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "UpdateMask.h"
22 #include "ObjectAccessor.h"
23 #include "ObjectGuid.h"
24 #include "Database/DatabaseEnv.h"
26 #include "GossipDef.h"
28 #include "ObjectMgr.h"
30 Corpse::Corpse(CorpseType type
) : WorldObject()
32 m_objectType
|= TYPEMASK_CORPSE
;
33 m_objectTypeId
= TYPEID_CORPSE
;
35 m_updateFlag
= UPDATEFLAG_HAS_POSITION
;
37 m_valuesCount
= CORPSE_END
;
50 void Corpse::AddToWorld()
52 ///- Register the corpse for guid lookup
54 sObjectAccessor
.AddObject(this);
59 void Corpse::RemoveFromWorld()
61 ///- Remove the corpse from the accessor
63 sObjectAccessor
.RemoveObject(this);
65 Object::RemoveFromWorld();
68 bool Corpse::Create(uint32 guidlow
)
70 Object::_Create(guidlow
, 0, HIGHGUID_CORPSE
);
74 bool Corpse::Create(uint32 guidlow
, Player
* owner
)
78 WorldObject::_Create(guidlow
, HIGHGUID_CORPSE
, owner
->GetPhaseMask());
79 Relocate(owner
->GetPositionX(), owner
->GetPositionY(), owner
->GetPositionZ(), owner
->GetOrientation());
81 // we need to assign owner's map for corpse
82 // in other way we will get a crash in Corpse::SaveToDB()
83 SetMap(owner
->GetMap());
85 if (!IsPositionValid())
87 sLog
.outError("Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
88 guidlow
, owner
->GetName(), owner
->GetPositionX(), owner
->GetPositionY());
92 SetObjectScale(DEFAULT_OBJECT_SCALE
);
93 SetGuidValue(CORPSE_FIELD_OWNER
, owner
->GetObjectGuid());
95 m_grid
= MaNGOS::ComputeGridPair(GetPositionX(), GetPositionY());
100 void Corpse::SaveToDB()
102 // bones should not be saved to DB (would be deleted on startup anyway)
103 MANGOS_ASSERT(GetType() != CORPSE_BONES
);
105 // prevent DB data inconsistence problems and duplicates
106 CharacterDatabase
.BeginTransaction();
109 std::ostringstream ss
;
110 ss
<< "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,map,time,corpse_type,instance,phaseMask) VALUES ("
111 << GetGUIDLow() << ", "
112 << GetOwnerGuid().GetCounter() << ", "
113 << GetPositionX() << ", "
114 << GetPositionY() << ", "
115 << GetPositionZ() << ", "
116 << GetOrientation() << ", "
117 << GetMapId() << ", "
118 << uint64(m_time
) << ", "
119 << uint32(GetType()) << ", "
120 << int(GetInstanceId()) << ", "
121 << uint16(GetPhaseMask()) << ")"; // prevent out of range error
122 CharacterDatabase
.Execute(ss
.str().c_str());
123 CharacterDatabase
.CommitTransaction();
126 void Corpse::DeleteBonesFromWorld()
128 MANGOS_ASSERT(GetType() == CORPSE_BONES
);
129 Corpse
* corpse
= GetMap()->GetCorpse(GetObjectGuid());
133 sLog
.outError("Bones %u not found in world.", GetGUIDLow());
137 AddObjectToRemoveList();
140 void Corpse::DeleteFromDB()
142 // bones should not be saved to DB (would be deleted on startup anyway)
143 MANGOS_ASSERT(GetType() != CORPSE_BONES
);
145 // all corpses (not bones)
146 static SqlStatementID id
;
148 SqlStatement stmt
= CharacterDatabase
.CreateStatement(id
, "DELETE FROM corpse WHERE player = ? AND corpse_type <> '0'");
149 stmt
.PExecute(GetOwnerGuid().GetCounter());
152 bool Corpse::LoadFromDB(uint32 lowguid
, Field
* fields
)
155 // QueryResult *result = CharacterDatabase.Query("SELECT corpse.guid, player, corpse.position_x, corpse.position_y, corpse.position_z, corpse.orientation, corpse.map,"
156 //// 7 8 9 10 11 12 13 14 15 16 17 18
157 // "time, corpse_type, instance, phaseMask, gender, race, class, playerBytes, playerBytes2, equipmentCache, guildId, playerFlags FROM corpse"
158 uint32 playerLowGuid
= fields
[1].GetUInt32();
159 float positionX
= fields
[2].GetFloat();
160 float positionY
= fields
[3].GetFloat();
161 float positionZ
= fields
[4].GetFloat();
162 float orientation
= fields
[5].GetFloat();
163 uint32 mapid
= fields
[6].GetUInt32();
165 Object::_Create(lowguid
, 0, HIGHGUID_CORPSE
);
167 m_time
= time_t(fields
[7].GetUInt64());
168 m_type
= CorpseType(fields
[8].GetUInt32());
170 if (m_type
>= MAX_CORPSE_TYPE
)
172 sLog
.outError("%s Owner %s have wrong corpse type (%i), not load.", GetGuidStr().c_str(), GetOwnerGuid().GetString().c_str(), m_type
);
176 uint32 instanceid
= fields
[9].GetUInt32();
177 uint32 phaseMask
= fields
[10].GetUInt32();
178 uint8 gender
= fields
[11].GetUInt8();
179 uint8 race
= fields
[12].GetUInt8();
180 uint8 _class
= fields
[13].GetUInt8();
181 uint32 playerBytes
= fields
[14].GetUInt32();
182 uint32 playerBytes2
= fields
[15].GetUInt32();
183 uint32 guildId
= fields
[17].GetUInt32();
184 uint32 playerFlags
= fields
[18].GetUInt32();
186 ObjectGuid guid
= ObjectGuid(HIGHGUID_CORPSE
, lowguid
);
187 ObjectGuid playerGuid
= ObjectGuid(HIGHGUID_PLAYER
, playerLowGuid
);
189 // overwrite possible wrong/corrupted guid
190 SetGuidValue(OBJECT_FIELD_GUID
, guid
);
191 SetGuidValue(CORPSE_FIELD_OWNER
, playerGuid
);
193 SetObjectScale(DEFAULT_OBJECT_SCALE
);
195 PlayerInfo
const* info
= sObjectMgr
.GetPlayerInfo(race
, _class
);
198 sLog
.outError("Player %u has incorrect race/class pair.", GetGUIDLow());
201 SetUInt32Value(CORPSE_FIELD_DISPLAY_ID
, gender
== GENDER_FEMALE
? info
->displayId_f
: info
->displayId_m
);
204 Tokens data
= StrSplit(fields
[16].GetCppString(), " ");
205 for (uint8 slot
= 0; slot
< EQUIPMENT_SLOT_END
; ++slot
)
207 uint32 visualbase
= slot
* 2;
208 uint32 item_id
= GetUInt32ValueFromArray(data
, visualbase
);
209 const ItemPrototype
* proto
= ObjectMgr::GetItemPrototype(item_id
);
212 SetUInt32Value(CORPSE_FIELD_ITEM
+ slot
, 0);
216 SetUInt32Value(CORPSE_FIELD_ITEM
+ slot
, proto
->DisplayInfoID
| (proto
->InventoryType
<< 24));
219 uint8 skin
= (uint8
)(playerBytes
);
220 uint8 face
= (uint8
)(playerBytes
>> 8);
221 uint8 hairstyle
= (uint8
)(playerBytes
>> 16);
222 uint8 haircolor
= (uint8
)(playerBytes
>> 24);
223 uint8 facialhair
= (uint8
)(playerBytes2
);
224 SetUInt32Value(CORPSE_FIELD_BYTES_1
, ((0x00) | (race
<< 8) | (gender
<< 16) | (skin
<< 24)));
225 SetUInt32Value(CORPSE_FIELD_BYTES_2
, ((face
) | (hairstyle
<< 8) | (haircolor
<< 16) | (facialhair
<< 24)));
227 //SetUInt32Value(CORPSE_FIELD_GUILD, guildId);
229 uint32 flags
= CORPSE_FLAG_UNK2
;
230 if (playerFlags
& PLAYER_FLAGS_HIDE_HELM
)
231 flags
|= CORPSE_FLAG_HIDE_HELM
;
232 if (playerFlags
& PLAYER_FLAGS_HIDE_CLOAK
)
233 flags
|= CORPSE_FLAG_HIDE_CLOAK
;
234 SetUInt32Value(CORPSE_FIELD_FLAGS
, flags
);
236 // no need to mark corpse as lootable, because corpses are not saved in battle grounds
239 SetLocationInstanceId(instanceid
);
240 SetLocationMapId(mapid
);
241 SetPhaseMask(phaseMask
, false);
242 Relocate(positionX
, positionY
, positionZ
, orientation
);
244 if (!IsPositionValid())
246 sLog
.outError("%s Owner %s not created. Suggested coordinates isn't valid (X: %f Y: %f)",
247 GetGuidStr().c_str(), GetOwnerGuid().GetString().c_str(), GetPositionX(), GetPositionY());
251 m_grid
= MaNGOS::ComputeGridPair(GetPositionX(), GetPositionY());
256 bool Corpse::isVisibleForInState(Player
const* u
, WorldObject
const* viewPoint
, bool inVisibleList
) const
258 return IsInWorld() && u
->IsInWorld() && IsWithinDistInMap(viewPoint
, GetMap()->GetVisibilityDistance() + (inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
), false);
261 bool Corpse::IsHostileTo(Unit
const* unit
) const
263 if (Player
* owner
= sObjectMgr
.GetPlayer(GetOwnerGuid()))
264 return owner
->IsHostileTo(unit
);
269 bool Corpse::IsFriendlyTo(Unit
const* unit
) const
271 if (Player
* owner
= sObjectMgr
.GetPlayer(GetOwnerGuid()))
272 return owner
->IsFriendlyTo(unit
);
277 bool Corpse::IsExpired(time_t t
) const
279 if (m_type
== CORPSE_BONES
)
280 return m_time
< t
- 60 * MINUTE
;
282 return m_time
< t
- 3 * DAY
;