Updated Copyright year to 2013
[getmangos.git] / src / game / Corpse.cpp
blob71e2f8d17b7c949268fe18e1eba1a4d817e2876b
1 /*
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
19 #include "Corpse.h"
20 #include "Player.h"
21 #include "UpdateMask.h"
22 #include "ObjectAccessor.h"
23 #include "ObjectGuid.h"
24 #include "Database/DatabaseEnv.h"
25 #include "Opcodes.h"
26 #include "GossipDef.h"
27 #include "World.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;
39 m_type = type;
41 m_time = time(NULL);
43 lootForBody = false;
46 Corpse::~Corpse()
50 void Corpse::AddToWorld()
52 ///- Register the corpse for guid lookup
53 if (!IsInWorld())
54 sObjectAccessor.AddObject(this);
56 Object::AddToWorld();
59 void Corpse::RemoveFromWorld()
61 ///- Remove the corpse from the accessor
62 if (IsInWorld())
63 sObjectAccessor.RemoveObject(this);
65 Object::RemoveFromWorld();
68 bool Corpse::Create(uint32 guidlow)
70 Object::_Create(guidlow, 0, HIGHGUID_CORPSE);
71 return true;
74 bool Corpse::Create(uint32 guidlow, Player* owner)
76 MANGOS_ASSERT(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());
89 return false;
92 SetObjectScale(DEFAULT_OBJECT_SCALE);
93 SetGuidValue(CORPSE_FIELD_OWNER, owner->GetObjectGuid());
95 m_grid = MaNGOS::ComputeGridPair(GetPositionX(), GetPositionY());
97 return true;
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();
107 DeleteFromDB();
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());
131 if (!corpse)
133 sLog.outError("Bones %u not found in world.", GetGUIDLow());
134 return;
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)
154 //// 0 1 2 3 4 5 6
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);
173 return false;
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);
196 if (!info)
198 sLog.outError("Player %u has incorrect race/class pair.", GetGUIDLow());
199 return false;
201 SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, gender == GENDER_FEMALE ? info->displayId_f : info->displayId_m);
203 // Load equipment
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);
210 if (!proto)
212 SetUInt32Value(CORPSE_FIELD_ITEM + slot, 0);
213 continue;
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
238 // place
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());
248 return false;
251 m_grid = MaNGOS::ComputeGridPair(GetPositionX(), GetPositionY());
253 return true;
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);
265 else
266 return false;
269 bool Corpse::IsFriendlyTo(Unit const* unit) const
271 if (Player* owner = sObjectMgr.GetPlayer(GetOwnerGuid()))
272 return owner->IsFriendlyTo(unit);
273 else
274 return true;
277 bool Corpse::IsExpired(time_t t) const
279 if (m_type == CORPSE_BONES)
280 return m_time < t - 60 * MINUTE;
281 else
282 return m_time < t - 3 * DAY;