eqemu-server/zone/corpse.cpp
2013-06-02 13:47:52 -07:00

2084 lines
63 KiB
C++

/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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
*/
/*
New class for handeling corpses and everything associated with them.
Child of the Mob class.
-Quagmire
*/
#include "../common/debug.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <sstream>
#ifdef _WINDOWS
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
#include "masterentity.h"
#include "../common/packet_functions.h"
#include "../common/StringUtil.h"
#include "../common/crc32.h"
#include "StringIDs.h"
#include "worldserver.h"
#include "../common/rulesys.h"
#include "QuestParserCollection.h"
extern EntityList entity_list;
extern Zone* zone;
extern WorldServer worldserver;
extern npcDecayTimes_Struct npcCorpseDecayTimes[100];
void Corpse::SendEndLootErrorPacket(Client* client) {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_LootComplete, 0);
client->QueuePacket(outapp);
safe_delete(outapp);
}
void Corpse::SendLootReqErrorPacket(Client* client, uint8 response) {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct));
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer;
d->response = response;
d->unknown1 = 0x5a;
d->unknown2 = 0x40;
client->QueuePacket(outapp);
safe_delete(outapp);
}
Corpse* Corpse::LoadFromDBData(uint32 in_dbid, uint32 in_charid, char* in_charname, uchar* in_data, uint32 in_datasize, float in_x, float in_y, float in_z, float in_heading, char* timeofdeath, bool rezzed, bool wasAtGraveyard) {
if (in_datasize < sizeof(classic_db::DBPlayerCorpse_Struct)) {
LogFile->write(EQEMuLog::Error, "Corpse::LoadFromDBData: Corrupt data: in_datasize < sizeof(DBPlayerCorpse_Struct)");
return 0;
}
classic_db::DBPlayerCorpse_Struct* dbpc = (classic_db::DBPlayerCorpse_Struct*) in_data;
bool isSoF = true;
uint32 esize1 = (sizeof(DBPlayerCorpse_Struct) + (dbpc->itemcount * sizeof(player_lootitem::ServerLootItem_Struct)));
uint32 esize2 = (sizeof(classic_db::DBPlayerCorpse_Struct) + (dbpc->itemcount * sizeof(player_lootitem::ServerLootItem_Struct)));
if (in_datasize != esize1) {
LogFile->write(EQEMuLog::Error, "Corpse::LoadFromDBData: Corrupt data: in_datasize (%i) != expected size (%i) Continuing on...", in_datasize, esize1);
if (in_datasize != esize2) {
LogFile->write(EQEMuLog::Error, "Corpse::LoadFromDBData: Corrupt data: in_datasize (%i) != expected size (%i) Your corpse is done broke, sir.", in_datasize, esize2);
return 0;
}
else
{
isSoF = false;
}
}
if(isSoF)
{
DBPlayerCorpse_Struct* dbpcs = (DBPlayerCorpse_Struct*) in_data;
if (dbpcs->crc != CRC32::Generate(&((uchar*) dbpcs)[4], in_datasize - 4)) {
LogFile->write(EQEMuLog::Error, "Corpse::LoadFromDBData: Corrupt data: crc failure");
return 0;
}
ItemList itemlist;
ServerLootItem_Struct* tmp = 0;
for (unsigned int i=0; i < dbpcs->itemcount; i++) {
tmp = new ServerLootItem_Struct;
memcpy(tmp, &dbpcs->items[i], sizeof(player_lootitem::ServerLootItem_Struct));
itemlist.push_back(tmp);
}
// Little hack to account for the fact the race in the corpse struct is a uint8 and Froglok/Drakkin race number > 255
// and to maintain backwards compatability with existing corpses in the database.
uint16 RealRace;
switch(dbpcs->race) {
case 254:
RealRace = DRAKKIN;
break;
case 255:
RealRace = FROGLOK;
break;
default:
RealRace = dbpc->race;
}
Corpse* pc = new Corpse(in_dbid, in_charid, in_charname, &itemlist, dbpcs->copper, dbpcs->silver, dbpcs->gold, dbpcs->plat, in_x, in_y, in_z, in_heading, dbpcs->size, dbpcs->gender, RealRace, dbpcs->class_, dbpcs->deity, dbpcs->level, dbpcs->texture, dbpcs->helmtexture, dbpcs->exp, wasAtGraveyard);
if (dbpcs->locked)
pc->Lock();
// load tints
memcpy(pc->item_tint, dbpcs->item_tint, sizeof(pc->item_tint));
// appearance
pc->haircolor = dbpcs->haircolor;
pc->beardcolor = dbpcs->beardcolor;
pc->eyecolor1 = dbpcs->eyecolor1;
pc->eyecolor2 = dbpcs->eyecolor2;
pc->hairstyle = dbpcs->hairstyle;
pc->luclinface = dbpcs->face;
pc->beard = dbpcs->beard;
pc->drakkin_heritage = dbpcs->drakkin_heritage;
pc->drakkin_tattoo = dbpcs->drakkin_tattoo;
pc->drakkin_details = dbpcs->drakkin_details;
pc->Rezzed(rezzed);
pc->become_npc = false;
return pc;
}
else
{
if (dbpc->crc != CRC32::Generate(&((uchar*) dbpc)[4], in_datasize - 4)) {
LogFile->write(EQEMuLog::Error, "Corpse::LoadFromDBData: Corrupt data: crc failure");
return 0;
}
ItemList itemlist;
ServerLootItem_Struct* tmp = 0;
for (unsigned int i=0; i < dbpc->itemcount; i++) {
tmp = new ServerLootItem_Struct;
memcpy(tmp, &dbpc->items[i], sizeof(player_lootitem::ServerLootItem_Struct));
itemlist.push_back(tmp);
}
// Little hack to account for the fact the race in the corpse struct is a uint8 and Froglok/Drakkin race number > 255
// and to maintain backwards compatability with existing corpses in the database.
uint16 RealRace;
switch(dbpc->race) {
case 254:
RealRace = DRAKKIN;
break;
case 255:
RealRace = FROGLOK;
break;
default:
RealRace = dbpc->race;
}
Corpse* pc = new Corpse(in_dbid, in_charid, in_charname, &itemlist, dbpc->copper, dbpc->silver, dbpc->gold, dbpc->plat, in_x, in_y, in_z, in_heading, dbpc->size, dbpc->gender, RealRace, dbpc->class_, dbpc->deity, dbpc->level, dbpc->texture, dbpc->helmtexture,dbpc->exp, wasAtGraveyard);
if (dbpc->locked)
pc->Lock();
// load tints
memcpy(pc->item_tint, dbpc->item_tint, sizeof(pc->item_tint));
// appearance
pc->haircolor = dbpc->haircolor;
pc->beardcolor = dbpc->beardcolor;
pc->eyecolor1 = dbpc->eyecolor1;
pc->eyecolor2 = dbpc->eyecolor2;
pc->hairstyle = dbpc->hairstyle;
pc->luclinface = dbpc->face;
pc->beard = dbpc->beard;
pc->drakkin_heritage = 0;
pc->drakkin_tattoo = 0;
pc->drakkin_details = 0;
pc->Rezzed(rezzed);
pc->become_npc = false;
return pc;
}
}
// To be used on NPC death and ZoneStateLoad
// Mongrel: added see_invis and see_invis_undead
Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NPCType** in_npctypedata, uint32 in_decaytime)
// vesuvias - appearence fix
: Mob("Unnamed_Corpse","",0,0,in_npc->GetGender(),in_npc->GetRace(),in_npc->GetClass(),BT_Humanoid,//bodytype added
in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0,
in_npc->GetHeading(),in_npc->GetX(),in_npc->GetY(),in_npc->GetZ(),0,
in_npc->GetTexture(),in_npc->GetHelmTexture(),
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0),
corpse_decay_timer(in_decaytime),
corpse_res_timer(0),
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
corpse_graveyard_timer(0),
loot_cooldown_timer(10)
{
corpse_graveyard_timer.Disable();
memset(item_tint, 0, sizeof(item_tint));
pIsChanged = false;
p_PlayerCorpse = false;
pLocked = false;
BeingLootedBy = 0xFFFFFFFF;
if (in_itemlist) {
itemlist = *in_itemlist;
in_itemlist->clear();
}
SetCash(in_npc->GetCopper(), in_npc->GetSilver(), in_npc->GetGold(), in_npc->GetPlatinum());
npctype_id = in_npctypeid;
SetPKItem(0);
charid = 0;
dbid = 0;
p_depop = false;
strcpy(orgname, in_npc->GetName());
strcpy(name, in_npc->GetName());
// Added By Hogie
for(int count = 0; count < 100; count++) {
if ((level >= npcCorpseDecayTimes[count].minlvl) && (level <= npcCorpseDecayTimes[count].maxlvl)) {
corpse_decay_timer.SetTimer(npcCorpseDecayTimes[count].seconds*1000);
break;
}
}
if(IsEmpty())
{
corpse_decay_timer.SetTimer(RuleI(NPC,EmptyNPCCorpseDecayTimeMS)+1000);
}
if(in_npc->HasPrivateCorpse())
{
corpse_delay_timer.SetTimer(corpse_decay_timer.GetRemainingTime() + 1000);
}
// Added By Hogie -- End
for (int i=0; i<MAX_LOOTERS; i++)
looters[i] = 0;
this->rezzexp = 0;
}
// To be used on PC death
// Mongrel: added see_invis and see_invis_undead
Corpse::Corpse(Client* client, int32 in_rezexp)
// vesuvias - appearence fix
: Mob
(
"Unnamed_Corpse",
"",
0,
0,
client->GetGender(),
client->GetRace(),
client->GetClass(),
BT_Humanoid, // bodytype added
client->GetDeity(),
client->GetLevel(),
0,
client->GetSize(),
0,
client->GetHeading(), // heading
client->GetX(),
client->GetY(),
client->GetZ(),
0,
client->GetTexture(),
client->GetHelmTexture(),
0, // AC
0,
0,
0,
0,
0,
0,
0,
0, // CHA
client->GetPP().haircolor,
client->GetPP().beardcolor,
client->GetPP().eyecolor1,
client->GetPP().eyecolor2,
client->GetPP().hairstyle,
client->GetPP().face,
client->GetPP().beard,
client->GetPP().drakkin_heritage,
client->GetPP().drakkin_tattoo,
client->GetPP().drakkin_details,
0,
0xff, // aa title
0,
0,
0,
0,
0,
0,
0, // qglobal
0, // maxlevel
0 // scalerate
),
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
corpse_res_timer(RuleI(Character, CorpseResTimeMS)),
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)),
loot_cooldown_timer(10)
{
int i;
PlayerProfile_Struct *pp = &client->GetPP();
ItemInst *item;
if(!zone->HasGraveyard()) {
corpse_graveyard_timer.Disable();
}
memset(item_tint, 0, sizeof(item_tint));
for (i=0; i<MAX_LOOTERS; i++)
looters[i] = 0;
pIsChanged = true;
rezzexp = in_rezexp;
can_rez = true;
p_PlayerCorpse = true;
pLocked = false;
BeingLootedBy = 0xFFFFFFFF;
charid = client->CharacterID();
dbid = 0;
p_depop = false;
copper = 0;
silver = 0;
gold = 0;
platinum = 0;
strcpy(orgname, pp->name);
strcpy(name, pp->name);
//become_npc was not being initialized which led to some pretty funky things with newly created corpses
become_npc = false;
SetPKItem(0);
if(!RuleB(Character, LeaveNakedCorpses) || RuleB(Character, LeaveCorpses) && GetLevel() >= RuleI(Character, DeathItemLossLevel)) {
// cash
// Let's not move the cash when 'RespawnFromHover = true' && 'client->GetClientVersion() < EQClientSoF' since the client doesn't.
// (change to first client that supports 'death hover' mode, if not SoF.)
if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < EQClientSoF) {
SetCash(pp->copper, pp->silver, pp->gold, pp->platinum);
pp->copper = 0;
pp->silver = 0;
pp->gold = 0;
pp->platinum = 0;
}
// get their tints
memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint));
// solar: TODO soulbound items need not be added to corpse, but they need
// to go into the regular slots on the player, out of bags
// worn + inventory + cursor
std::list<uint32> removed_list;
bool cursor = false;
for(i = 0; i <= 30; i++)
{
if(i == 21 && client->GetClientVersion() >= EQClientSoF) {
item = client->GetInv().GetItem(9999);
if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) {
std::list<uint32> slot_list = MoveItemToCorpse(client, item, 9999);
removed_list.merge(slot_list);
}
}
item = client->GetInv().GetItem(i);
if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) {
std::list<uint32> slot_list = MoveItemToCorpse(client, item, i);
removed_list.merge(slot_list);
}
}
// cursor queue // (change to first client that supports 'death hover' mode, if not SoF.)
if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < EQClientSoF) {
// bumped starting assignment to 8001 because any in-memory 'slot 8000' item was moved above as 'slot 30'
// this was mainly for client profile state reflection..should match db player inventory entries now.
iter_queue it;
for(it=client->GetInv().cursor_begin(),i=8001; it!=client->GetInv().cursor_end(); it++,i++) {
item = *it;
if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
{
std::list<uint32> slot_list = MoveItemToCorpse(client, item, i);
removed_list.merge(slot_list);
cursor = true;
}
}
}
if(removed_list.size() != 0) {
std::stringstream ss("");
ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
ss << " AND (";
std::list<uint32>::const_iterator iter = removed_list.begin();
bool first = true;
while(iter != removed_list.end()) {
if(first) {
first = false;
} else {
ss << " OR ";
}
ss << "slotid=" << (*iter);
iter++;
}
ss << ")";
database.RunQuery(ss.str().c_str(), ss.str().length());
}
if(cursor) { // all cursor items should be on corpse (client < SoF or RespawnFromHover = false)
while(!client->GetInv().CursorEmpty())
client->DeleteItemInInventory(SLOT_CURSOR, 0, false, false);
}
else { // only visible cursor made it to corpse (client >= Sof and RespawnFromHover = true)
std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
database.SaveCursor(client->CharacterID(), start, finish);
}
client->CalcBonuses(); // will only affect offline profile viewing of dead characters..unneeded overhead
client->Save();
} //end "not leaving naked corpses"
Rezzed(false);
Save();
}
// solar: helper function for client corpse constructor
std::list<uint32> Corpse::MoveItemToCorpse(Client *client, ItemInst *item, int16 equipslot)
{
int bagindex;
int16 interior_slot;
ItemInst *interior_item;
std::list<uint32> returnlist;
AddItem(item->GetItem()->ID, item->GetCharges(), equipslot, item->GetAugmentItemID(0), item->GetAugmentItemID(1), item->GetAugmentItemID(2), item->GetAugmentItemID(3), item->GetAugmentItemID(4));
returnlist.push_back(equipslot);
// Qualified bag slot iterations. processing bag slots that don't exist is probably not a good idea.
if(item->IsType(ItemClassContainer) && ((equipslot >= 22 && equipslot <=30))) // Limit the bag check to inventory and cursor slots.
{
for(bagindex = 0; bagindex <= 9; bagindex++)
{
// For empty bags in cursor queue, slot was previously being resolved as SLOT_INVALID (-1)
interior_slot = Inventory::CalcSlotId(equipslot, bagindex);
interior_item = client->GetInv().GetItem(interior_slot);
if(interior_item)
{
AddItem(interior_item->GetItem()->ID, interior_item->GetCharges(), interior_slot, interior_item->GetAugmentItemID(0), interior_item->GetAugmentItemID(1), interior_item->GetAugmentItemID(2), interior_item->GetAugmentItemID(3), interior_item->GetAugmentItemID(4));
returnlist.push_back(Inventory::CalcSlotId(equipslot, bagindex));
client->DeleteItemInInventory(interior_slot, 0, true, false);
}
}
}
client->DeleteItemInInventory(equipslot, 0, true, false);
return returnlist;
}
// To be called from LoadFromDBData
// Mongrel: added see_invis and see_invis_undead
Corpse::Corpse(uint32 in_dbid, uint32 in_charid, char* in_charname, ItemList* in_itemlist, uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_plat, float in_x, float in_y, float in_z, float in_heading, float in_size, uint8 in_gender, uint16 in_race, uint8 in_class, uint8 in_deity, uint8 in_level, uint8 in_texture, uint8 in_helmtexture,uint32 in_rezexp, bool wasAtGraveyard)
: Mob("Unnamed_Corpse","",0,0,in_gender, in_race, in_class, BT_Humanoid, in_deity, in_level,0, in_size, 0, in_heading, in_x, in_y, in_z,0,in_texture,in_helmtexture,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0xff,
0,0,0,0,0,0,0,0,0),
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
corpse_res_timer(RuleI(Character, CorpseResTimeMS)),
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)),
loot_cooldown_timer(10)
{
//we really should be loading the decay timer here...
LoadPlayerCorpseDecayTime(in_dbid);
if(!zone->HasGraveyard() || wasAtGraveyard)
corpse_graveyard_timer.Disable();
memset(item_tint, 0, sizeof(item_tint));
pIsChanged = false;
p_PlayerCorpse = true;
pLocked = false;
BeingLootedBy = 0xFFFFFFFF;
dbid = in_dbid;
p_depop = false;
charid = in_charid;
itemlist = *in_itemlist;
in_itemlist->clear();
strcpy(orgname, in_charname);
strcpy(name, in_charname);
this->copper = in_copper;
this->silver = in_silver;
this->gold = in_gold;
this->platinum = in_plat;
rezzexp = in_rezexp;
for (int i=0; i<MAX_LOOTERS; i++)
looters[i] = 0;
SetPKItem(0);
}
Corpse::~Corpse() {
if (p_PlayerCorpse && !(p_depop && dbid == 0)) {
Save();
}
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
ServerLootItem_Struct* item = *cur;
safe_delete(item);
}
itemlist.clear();
}
/*
this needs to be called AFTER the entity_id is set
the client does this too, so it's unchangable
*/
void Corpse::CalcCorpseName() {
EntityList::RemoveNumbers(name);
char tmp[64];
if (p_PlayerCorpse)
snprintf(tmp, sizeof(tmp), "'s corpse%d", GetID());
else
snprintf(tmp, sizeof(tmp), "`s_corpse%d", GetID());
name[(sizeof(name) - 1) - strlen(tmp)] = 0;
strcat(name, tmp);
}
bool Corpse::Save() {
if (!p_PlayerCorpse)
return true;
if (!pIsChanged)
return true;
uint32 tmp = this->CountItems();
uint32 tmpsize = sizeof(DBPlayerCorpse_Struct) + (tmp * sizeof(player_lootitem::ServerLootItem_Struct));
DBPlayerCorpse_Struct* dbpc = (DBPlayerCorpse_Struct*) new uchar[tmpsize];
memset(dbpc, 0, tmpsize);
dbpc->itemcount = tmp;
dbpc->size = this->size;
dbpc->locked = pLocked;
dbpc->copper = this->copper;
dbpc->silver = this->silver;
dbpc->gold = this->gold;
dbpc->plat = this->platinum;
// Little hack to account for the fact the race in the corpse struct is a uint8 and Froglok/Drakkin race number > 255
// and to maintain backwards compatability with existing corpses in the database.
uint16 CorpseRace;
switch(race) {
case DRAKKIN:
CorpseRace = 254;
break;
case FROGLOK:
CorpseRace = 255;
break;
default:
CorpseRace = race;
}
dbpc->race = CorpseRace;
dbpc->class_ = class_;
dbpc->gender = gender;
dbpc->deity = deity;
dbpc->level = level;
dbpc->texture = this->texture;
dbpc->helmtexture = this->helmtexture;
dbpc->exp = rezzexp;
memcpy(dbpc->item_tint, item_tint, sizeof(dbpc->item_tint));
dbpc->haircolor = haircolor;
dbpc->beardcolor = beardcolor;
dbpc->eyecolor2 = eyecolor1;
dbpc->hairstyle = hairstyle;
dbpc->face = luclinface;
dbpc->beard = beard;
dbpc->drakkin_heritage = drakkin_heritage;
dbpc->drakkin_tattoo = drakkin_tattoo;
dbpc->drakkin_details = drakkin_details;
uint32 x = 0;
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
ServerLootItem_Struct* item = *cur;
memcpy((char*) &dbpc->items[x++], (char*) item, sizeof(player_lootitem::ServerLootItem_Struct));
}
dbpc->crc = CRC32::Generate(&((uchar*) dbpc)[4], tmpsize - 4);
if (dbid == 0)
{
dbid = database.CreatePlayerCorpse(charid, orgname, zone->GetZoneID(), zone->GetInstanceID(), (uchar*) dbpc, tmpsize, x_pos, y_pos, z_pos, heading);
if(RuleB(Zone, UsePlayerCorpseBackups) == true)
database.CreatePlayerCorpseBackup(dbid, charid, orgname, zone->GetZoneID(), zone->GetInstanceID(), (uchar*) dbpc, tmpsize, x_pos, y_pos, z_pos, heading);
}
else
dbid = database.UpdatePlayerCorpse(dbid, charid, orgname, zone->GetZoneID(), zone->GetInstanceID(), (uchar*) dbpc, tmpsize, x_pos, y_pos, z_pos, heading,Rezzed());
safe_delete_array(dbpc);
if (dbid == 0) {
std::cout << "Error: Failed to save player corpse '" << this->GetName() << "'" << std::endl;
return false;
}
return true;
}
void Corpse::Delete() {
if (IsPlayerCorpse() && dbid != 0)
database.DeletePlayerCorpse(dbid);
dbid = 0;
p_depop = true;
}
void Corpse::Bury() {
if (IsPlayerCorpse() && dbid != 0)
database.BuryPlayerCorpse(dbid);
dbid = 0;
p_depop = true;
}
void Corpse::Depop() {
if (IsNPCCorpse())
p_depop = true;
}
void Corpse::DepopCorpse() {
p_depop = true;
}
uint32 Corpse::CountItems() {
return itemlist.size();
}
void Corpse::AddItem(uint32 itemnum, uint16 charges, int16 slot, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5) {
if (!database.GetItem(itemnum))
return;
pIsChanged = true;
ServerLootItem_Struct* item = new ServerLootItem_Struct;
memset(item, 0, sizeof(ServerLootItem_Struct));
item->item_id = itemnum;
item->charges = charges;
item->equipSlot = slot;
item->aug1=aug1;
item->aug2=aug2;
item->aug3=aug3;
item->aug4=aug4;
item->aug5=aug5;
itemlist.push_back(item);
}
ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct** bag_item_data)
{
ServerLootItem_Struct *sitem = 0, *sitem2;
// find the item
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
if((*cur)->lootslot == lootslot)
{
sitem = *cur;
break;
}
}
if (sitem && bag_item_data && Inventory::SupportsContainers(sitem->equipSlot))
{
int16 bagstart = Inventory::CalcSlotId(sitem->equipSlot, 0);
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
sitem2 = *cur;
if(sitem2->equipSlot >= bagstart && sitem2->equipSlot < bagstart + 10)
{
bag_item_data[sitem2->equipSlot - bagstart] = sitem2;
}
}
}
return sitem;
}
uint32 Corpse::GetWornItem(int16 equipSlot) const {
ItemList::const_iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
ServerLootItem_Struct* item = *cur;
if (item->equipSlot == equipSlot)
{
return item->item_id;
}
}
return 0;
}
void Corpse::RemoveItem(uint16 lootslot)
{
if (lootslot == 0xFFFF)
return;
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
ServerLootItem_Struct* sitem = *cur;
if (sitem->lootslot == lootslot)
{
RemoveItem(sitem);
return;
}
}
}
void Corpse::RemoveItem(ServerLootItem_Struct* item_data)
{
uint8 material;
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
ServerLootItem_Struct* sitem = *cur;
if (sitem == item_data)
{
pIsChanged = true;
itemlist.erase(cur);
material = Inventory::CalcMaterialFromSlot(sitem->equipSlot);
if(material != 0xFF)
SendWearChange(material);
safe_delete(sitem);
return;
}
}
}
void Corpse::SetCash(uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_platinum) {
this->copper = in_copper;
this->silver = in_silver;
this->gold = in_gold;
this->platinum = in_platinum;
pIsChanged = true;
}
void Corpse::RemoveCash() {
this->copper = 0;
this->silver = 0;
this->gold = 0;
this->platinum = 0;
pIsChanged = true;
}
bool Corpse::IsEmpty() const {
if (copper != 0 || silver != 0 || gold != 0 || platinum != 0)
return false;
return(itemlist.size() == 0);
}
bool Corpse::Process() {
if (p_depop)
return false;
if(corpse_delay_timer.Check())
{
for (int i=0; i<MAX_LOOTERS; i++)
looters[i] = 0;
corpse_delay_timer.Disable();
return true;
}
if(corpse_graveyard_timer.Check()) {
if(zone->HasGraveyard()) {
Save();
p_depop = true;
database.GraveyardPlayerCorpse(dbid, zone->graveyard_zoneid(),
(zone->GetZoneID() == zone->graveyard_zoneid()) ? zone->GetInstanceID() : 0, zone->graveyard_x(),
zone->graveyard_y(), zone->graveyard_z(), zone->graveyard_heading());
corpse_graveyard_timer.Disable();
ServerPacket* pack = new ServerPacket(ServerOP_SpawnPlayerCorpse, sizeof(SpawnPlayerCorpse_Struct));
SpawnPlayerCorpse_Struct* spc = (SpawnPlayerCorpse_Struct*)pack->pBuffer;
spc->player_corpse_id = dbid;
spc->zone_id = zone->graveyard_zoneid();
worldserver.SendPacket(pack);
safe_delete(pack);
LogFile->write(EQEMuLog::Debug, "Moved %s player corpse to the designated graveyard in zone %s.", this->GetName(), database.GetZoneName(zone->graveyard_zoneid()));
dbid = 0;
}
corpse_graveyard_timer.Disable();
return false;
}
/*
if(corpse_res_timer.Check()) {
can_rez = false;
corpse_res_timer.Disable();
}
*/
if(corpse_decay_timer.Check()) {
if(!RuleB(Zone, EnableShadowrest))
Delete();
else {
if(database.BuryPlayerCorpse(dbid)) {
Save();
p_depop = true;
dbid = 0;
LogFile->write(EQEMuLog::Debug, "Tagged %s player corpse has burried.", this->GetName());
}
else
{
LogFile->write(EQEMuLog::Error, "Unable to bury %s player corpse.", this->GetName());
return true;
}
}
corpse_decay_timer.Disable();
return false;
}
return true;
}
void Corpse::SetDecayTimer(uint32 decaytime) {
if (decaytime == 0)
corpse_decay_timer.Trigger();
else
corpse_decay_timer.Start(decaytime);
}
bool Corpse::CanMobLoot(int charid) {
uint8 z=0;
for(int i=0; i<MAX_LOOTERS; i++) {
if(looters[i] != 0)
z++;
if (looters[i] == charid)
return true;
}
if(z == 0)
return true;
else
return false;
}
void Corpse::AllowMobLoot(Mob *them, uint8 slot)
{
if(slot >= MAX_LOOTERS)
return;
if(them == nullptr || !them->IsClient())
return;
looters[slot] = them->CastToClient()->CharacterID();
}
// @merth: this function needs some work
void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* app) {
// Added 12/08. Started compressing loot struct on live.
char tmp[10];
if(p_depop) {
SendLootReqErrorPacket(client, 0);
return;
}
if(IsPlayerCorpse() && dbid == 0) {
// SendLootReqErrorPacket(client, 0);
client->Message(13, "Warning: Corpse's dbid = 0! Corpse will not survive zone shutdown!");
std::cout << "Error: PlayerCorpse::MakeLootRequestPackets: dbid = 0!" << std::endl;
// return;
}
if(pLocked && client->Admin() < 100) {
SendLootReqErrorPacket(client, 0);
client->Message(13, "Error: Corpse locked by GM.");
return;
}
if(BeingLootedBy == 0) { BeingLootedBy = 0xFFFFFFFF; }
if(this->BeingLootedBy != 0xFFFFFFFF) {
// lets double check....
Entity* looter = entity_list.GetID(this->BeingLootedBy);
if(looter == 0) { this->BeingLootedBy = 0xFFFFFFFF; }
}
uint8 tCanLoot = 1;
bool lootcoin = false;
if(database.GetVariable("LootCoin", tmp, 9)) { lootcoin = (atoi(tmp) == 1); }
if(this->BeingLootedBy != 0xFFFFFFFF && this->BeingLootedBy != client->GetID()) {
SendLootReqErrorPacket(client, 0);
tCanLoot = 0;
}
else if(IsPlayerCorpse() && charid == client->CharacterID()) { tCanLoot = 2; }
else if((IsNPCCorpse() || become_npc) && CanMobLoot(client->CharacterID())) { tCanLoot = 2; }
else if(GetPKItem() == -1 && CanMobLoot(client->CharacterID())) { tCanLoot = 3; } //pvp loot all items, variable cash
else if(GetPKItem() == 1 && CanMobLoot(client->CharacterID())) { tCanLoot = 4; } //pvp loot 1 item, variable cash
else if(GetPKItem() > 1 && CanMobLoot(client->CharacterID())) { tCanLoot = 5; } //pvp loot 1 set item, variable cash
if(tCanLoot == 1) { if(client->Admin() < 100 || !client->GetGM()) { SendLootReqErrorPacket(client, 2); } }
if(tCanLoot >= 2 || (tCanLoot == 1 && client->Admin() >= 100 && client->GetGM())) {
this->BeingLootedBy = client->GetID();
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct));
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer;
d->response = 1;
d->unknown1 = 0x42;
d->unknown2 = 0xef;
if(tCanLoot == 2 || (tCanLoot >= 3 && lootcoin)) { // dont take the coin off if it's a gm peeking at the corpse
if(zone->lootvar != 0) {
int admin = client->Admin();
if(zone->lootvar == 7) { client->LogLoot(client, this, 0); }
else if((admin >= 10) && (admin < 20)) {
if((zone->lootvar < 8) && (zone->lootvar > 5)) { client->LogLoot(client, this, 0); }
}
else if(admin <= 20) {
if((zone->lootvar < 8) && (zone->lootvar > 4)) { client->LogLoot(client, this, 0); }
}
else if(admin <= 80) {
if((zone->lootvar < 8) && (zone->lootvar > 3)) { client->LogLoot(client, this, 0); }
}
else if(admin <= 100) {
if((zone->lootvar < 9) && (zone->lootvar > 2)) { client->LogLoot(client, this, 0); }
}
else if(admin <= 150) {
if(((zone->lootvar < 8) && (zone->lootvar > 1)) || (zone->lootvar == 9)) { client->LogLoot(client, this, 0); }
}
else if (admin <= 255) {
if((zone->lootvar < 8) && (zone->lootvar > 0)) { client->LogLoot(client, this, 0); }
}
}
if(!IsPlayerCorpse() && client->IsGrouped() && client->AutoSplitEnabled() && client->GetGroup()) {
d->copper = 0;
d->silver = 0;
d->gold = 0;
d->platinum = 0;
Group *cgroup = client->GetGroup();
cgroup->SplitMoney(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), client);
}
else {
d->copper = this->GetCopper();
d->silver = this->GetSilver();
d->gold = this->GetGold();
d->platinum = this->GetPlatinum();
client->AddMoneyToPP(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), false);
}
RemoveCash();
Save();
client->Save();
}
outapp->priority = 6;
client->QueuePacket(outapp);
safe_delete(outapp);
if(tCanLoot == 5) {
int pkitem = GetPKItem();
const Item_Struct* item = database.GetItem(pkitem);
ItemInst* inst = database.CreateItem(item, item->MaxCharges);
if(inst) {
client->SendItemPacket(22, inst, ItemPacketLoot);
safe_delete(inst);
}
else { client->Message(13, "Could not find item number %i to send!!", GetPKItem()); }
client->QueuePacket(app);
return;
}
int i = 0;
const Item_Struct* item = 0;
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
uint8 containercount = 0;
int corpselootlimit;
if(client->GetClientVersion() >= EQClientRoF) { corpselootlimit = 34; }
else if(client->GetClientVersion() >= EQClientSoF) { corpselootlimit = 32; }
else if(client->GetClientVersion() == EQClientTitanium) { corpselootlimit = 31; }
else { corpselootlimit = 30; }
for(; cur != end; cur++) {
ServerLootItem_Struct* item_data = *cur;
item_data->lootslot = 0xFFFF;
// Dont display the item if it's in a bag
// Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse.
if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || item_data->equipSlot == 9999 || tCanLoot>=3 ||
(item_data->equipSlot >= 8000 && item_data->equipSlot <= 8999)) {
if(i < corpselootlimit) {
item = database.GetItem(item_data->item_id);
if(client && item) {
ItemInst* inst = database.CreateItem(item, item_data->charges, item_data->aug1, item_data->aug2, item_data->aug3, item_data->aug4, item_data->aug5);
if(inst) {
client->SendItemPacket(i + 22, inst, ItemPacketLoot); // 22 is the corpse inventory start offset for Ti(EMu)
safe_delete(inst);
}
item_data->lootslot = i;
}
}
i++;
}
}
if(IsPlayerCorpse() && (charid == client->CharacterID() || client->GetGM())) {
if(i > corpselootlimit) {
client->Message(15, "*** This corpse contains more items than can be displayed! ***");
client->Message(0, "Remove items and re-loot corpse to access remaining inventory.");
client->Message(0, "(%s contains %i additional %s.)", GetName(), (i - corpselootlimit), (i - corpselootlimit) == 1 ? "item" : "items");
}
if(IsPlayerCorpse() && i == 0 && itemlist.size() > 0) { // somehow, player corpse contains items, but client doesn't see them...
client->Message(13, "This corpse contains items that are inaccessable!");
client->Message(15, "Contact a GM for item replacement, if necessary.");
client->Message(15, "BUGGED CORPSE [DBID: %i, Name: %s, Item Count: %i]", GetDBID(), GetName(), itemlist.size());
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; cur++) {
ServerLootItem_Struct* item_data = *cur;
item = database.GetItem(item_data->item_id);
LogFile->write(EQEMuLog::Debug, "Corpse Looting: %s was not sent to client loot window (corpse_dbid: %i, charname: %s(%s))", item->Name, GetDBID(), client->GetName(), client->GetGM() ? "GM" : "Owner");
client->Message(0, "Inaccessable Corpse Item: %s", item->Name);
}
}
}
}
// Disgrace: Client seems to require that we send the packet back...
client->QueuePacket(app);
// This is required for the 'Loot All' feature to work for SoD clients. I expect it is to tell the client that the
// server has now sent all the items on the corpse.
if(client->GetClientVersion() >= EQClientSoD) { SendLootReqErrorPacket(client, 6); }
}
void Corpse::LootItem(Client* client, const EQApplicationPacket* app)
{
//this gets sent out no matter what as a sort of 'ack', so send it here.
client->QueuePacket(app);
if(!loot_cooldown_timer.Check())
{
SendEndLootErrorPacket(client);
return;
}
// To prevent item loss for a player using 'Loot All' who doesn't have inventory space for all their items.
if(RuleB(Character, CheckCursorEmptyWhenLooting) && !client->GetInv().CursorEmpty())
{
client->Message(13, "You may not loot an item while you have an item on your cursor.");
SendEndLootErrorPacket(client);
return;
}
LootingItem_Struct* lootitem = (LootingItem_Struct*)app->pBuffer;
if (this->BeingLootedBy != client->GetID()) {
client->Message(13, "Error: Corpse::LootItem: BeingLootedBy != client");
SendEndLootErrorPacket(client);
return;
}
if (IsPlayerCorpse() && !CanMobLoot(client->CharacterID()) && !become_npc && (charid != client->CharacterID() && client->Admin() < 150)) {
client->Message(13, "Error: This is a player corpse and you dont own it.");
SendEndLootErrorPacket(client);
return;
}
if (pLocked && client->Admin() < 100) {
SendLootReqErrorPacket(client, 0);
client->Message(13, "Error: Corpse locked by GM.");
return;
}
if(IsPlayerCorpse() && (charid != client->CharacterID()) && CanMobLoot(client->CharacterID()) && GetPKItem()==0){
client->Message(13, "Error: You cannot loot any more items from this corpse.");
SendEndLootErrorPacket(client);
BeingLootedBy = 0xFFFFFFFF;
return;
}
const Item_Struct* item = 0;
ItemInst *inst = 0;
ServerLootItem_Struct* item_data = nullptr, *bag_item_data[10];
memset(bag_item_data, 0, sizeof(bag_item_data));
if(GetPKItem()>1)
item = database.GetItem(GetPKItem());
else if(GetPKItem()==-1 || GetPKItem()==1)
item_data = GetItem(lootitem->slot_id - 22); //dont allow them to loot entire bags of items as pvp reward
else
item_data = GetItem(lootitem->slot_id - 22, bag_item_data);
if (GetPKItem()<=1 && item_data != 0)
{
item = database.GetItem(item_data->item_id);
}
if (item != 0)
{
if(item_data)
inst = database.CreateItem(item, item_data?item_data->charges:0, item_data->aug1, item_data->aug2, item_data->aug3, item_data->aug4, item_data->aug5);
else
inst = database.CreateItem(item);
}
if (client && inst)
{
if (client->CheckLoreConflict(item))
{
client->Message_StringID(0,LOOT_LORE_ERROR);
SendEndLootErrorPacket(client);
BeingLootedBy = 0;
delete inst;
return;
}
if(inst->IsAugmented())
{
for(int i=0; i<MAX_AUGMENT_SLOTS; i++)
{
ItemInst *itm = inst->GetAugment(i);
if(itm)
{
if(client->CheckLoreConflict(itm->GetItem()))
{
client->Message_StringID(0,LOOT_LORE_ERROR);
SendEndLootErrorPacket(client);
BeingLootedBy = 0;
delete inst;
return;
}
}
}
}
char buf[88];
char corpse_name[64];
strcpy(corpse_name, orgname);
snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(corpse_name));
buf[87] = '\0';
parse->EventPlayer(EVENT_LOOT, client, buf, 0);
if ((RuleB(Character, EnableDiscoveredItems)))
{
if(client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID))
client->DiscoverItem(inst->GetItem()->ID);
}
if (zone->lootvar != 0)
{
int admin=client->Admin();
if (zone->lootvar==7){
client->LogLoot(client,this,item);
}
else if ((admin>=10) && (admin<20)){
if ((zone->lootvar<8) && (zone->lootvar>5))
client->LogLoot(client,this,item);
}
else if (admin<=20){
if ((zone->lootvar<8) && (zone->lootvar>4))
client->LogLoot(client,this,item);
}
else if (admin<=80){
if ((zone->lootvar<8) && (zone->lootvar>3))
client->LogLoot(client,this,item);
}
else if (admin<=100){
if ((zone->lootvar<9) && (zone->lootvar>2))
client->LogLoot(client,this,item);
}
else if (admin<=150){
if (((zone->lootvar<8) && (zone->lootvar>1)) || (zone->lootvar==9))
client->LogLoot(client,this,item);
}
else if (admin<=255){
if ((zone->lootvar<8) && (zone->lootvar>0))
client->LogLoot(client,this,item);
}
}
if(zone->adv_data)
{
ServerZoneAdventureDataReply_Struct *ad = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
if(ad->type == Adventure_Collect && !IsPlayerCorpse())
{
if(ad->data_id == inst->GetItem()->ID)
{
zone->DoAdventureCountIncrease();
}
}
}
// first add it to the looter - this will do the bag contents too
if(lootitem->auto_loot)
{
if(!client->AutoPutLootInInventory(*inst, true, true, bag_item_data))
client->PutLootInInventory(SLOT_CURSOR, *inst, bag_item_data);
}
else
{
client->PutLootInInventory(SLOT_CURSOR, *inst, bag_item_data);
}
// Update any tasks that have an activity to loot this item.
if(RuleB(TaskSystem, EnableTaskSystem))
client->UpdateTasksForItem(ActivityLoot, item->ID);
// now remove it from the corpse
if(item_data)
RemoveItem(item_data->lootslot);
// remove bag contents too
if (item->ItemClass == ItemClassContainer && (GetPKItem()!=-1 || GetPKItem()!=1))
{
for (int i=0; i < 10; i++)
{
if (bag_item_data[i])
{
RemoveItem(bag_item_data[i]);
}
}
}
if(GetPKItem()!=-1)
SetPKItem(0);
//now send messages to all interested parties
//creates a link for the item
char *link = 0, *link2 = 0; //just like a db query :-)
client->MakeItemLink(link2, inst);
MakeAnyLenString(&link, "%c" "%s" "%s" "%c",
0x12,
link2,
item->Name,
0x12);
safe_delete_array(link2);
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, link);
if(!IsPlayerCorpse()) {
Group *g = client->GetGroup();
if(g != nullptr) {
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
} else {
Raid *r = client->GetRaid();
if(r != nullptr) {
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
}
}
}
safe_delete_array(link);
}
else
{
SendEndLootErrorPacket(client);
safe_delete(inst);
return;
}
if (IsPlayerCorpse())
client->SendItemLink(inst);
else
client->SendItemLink(inst, true);
safe_delete(inst);
}
void Corpse::EndLoot(Client* client, const EQApplicationPacket* app) {
EQApplicationPacket* outapp = new EQApplicationPacket;
outapp->SetOpcode(OP_LootComplete);
outapp->size = 0;
client->QueuePacket(outapp);
safe_delete(outapp);
//client->Save(); //inventory operations auto-commit
this->BeingLootedBy = 0xFFFFFFFF;
if (this->IsEmpty())
Delete();
else
Save();
}
void Corpse::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
{
Mob::FillSpawnStruct(ns, ForWho);
ns->spawn.max_hp = 120;
if (IsPlayerCorpse())
ns->spawn.NPC = 3;
else
ns->spawn.NPC = 2;
}
void Corpse::QueryLoot(Client* to) {
int x = 0, y = 0; // x = visible items, y = total items
to->Message(0, "Coin: %ip, %ig, %is, %ic", platinum, gold, silver, copper);
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
int corpselootlimit;
if (to->GetClientVersion() >= EQClientSoF) { corpselootlimit = 32; }
else if (to->GetClientVersion() == EQClientTitanium) { corpselootlimit = 31; }
else { corpselootlimit = 30; }
for(; cur != end; cur++) {
ServerLootItem_Struct* sitem = *cur;
if (IsPlayerCorpse()) {
if (sitem->equipSlot >= 251 && sitem->equipSlot <= 340)
sitem->lootslot = 0xFFFF;
else
x < corpselootlimit ? sitem->lootslot = x : sitem->lootslot = 0xFFFF;
const Item_Struct* item = database.GetItem(sitem->item_id);
if (item)
to->Message((sitem->lootslot == 0xFFFF), "LootSlot: %i (EquipSlot: %i) Item: %s (%d), Count: %i", static_cast<int16>(sitem->lootslot), sitem->equipSlot, item->Name, item->ID, sitem->charges);
else
to->Message((sitem->lootslot == 0xFFFF), "Error: 0x%04x", sitem->item_id);
if (sitem->lootslot != 0xFFFF)
x++;
y++;
}
else {
sitem->lootslot=y;
const Item_Struct* item = database.GetItem(sitem->item_id);
if (item)
to->Message(0, "LootSlot: %i Item: %s (%d), Count: %i", sitem->lootslot, item->Name, item->ID, sitem->charges);
else
to->Message(0, "Error: 0x%04x", sitem->item_id);
y++;
}
}
if (IsPlayerCorpse()) {
to->Message(0, "%i visible %s (%i total) on %s (DBID: %i).", x, x==1?"item":"items", y, this->GetName(), this->GetDBID());
}
else {
to->Message(0, "%i %s on %s.", y, y==1?"item":"items", this->GetName());
}
}
bool Corpse::Summon(Client* client, bool spell, bool CheckDistance)
{
uint32 dist2 = 10000; // pow(100, 2);
if (!spell) {
if (this->GetCharID() == client->CharacterID()) {
if (IsLocked() && client->Admin() < 100) {
client->Message(13, "That corpse is locked by a GM.");
return false;
}
if (!CheckDistance || (DistNoRootNoZ(*client) <= dist2))
{
GMMove(client->GetX(), client->GetY(), client->GetZ());
pIsChanged = true;
}
else
{
client->Message(0, "Corpse is too far away.");
return false;
}
}
else
{
bool consented = false;
std::list<std::string>::iterator itr;
for(itr = client->consent_list.begin(); itr != client->consent_list.end(); itr++)
{
if(strcmp(this->GetOwnerName(), itr->c_str()) == 0)
{
if (!CheckDistance || (DistNoRootNoZ(*client) <= dist2))
{
GMMove(client->GetX(), client->GetY(), client->GetZ());
pIsChanged = true;
}
else
{
client->Message(0, "Corpse is too far away.");
return false;
}
consented = true;
}
}
if(!consented)
{
client->Message(0, "You do not have permission to move this corpse.");
return false;
}
}
}
else {
GMMove(client->GetX(), client->GetY(), client->GetZ());
pIsChanged = true;
}
Save();
return true;
}
void Corpse::CompleteRezz(){
rezzexp = 0;
pIsChanged = true;
this->Save();
}
void Corpse::Spawn() {
EQApplicationPacket* app = new EQApplicationPacket;
this->CreateSpawnPacket(app, this);
entity_list.QueueClients(this, app);
safe_delete(app);
}
bool ZoneDatabase::DeleteGraveyard(uint32 zone_id, uint32 graveyard_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256];
uint32 query_length = 0;
uint32 affected_rows = 0;
query_length = sprintf(query,"UPDATE zone SET graveyard_id=0 WHERE zoneidnumber=%u AND version=0", zone_id);
if (!RunQuery(query, query_length, errbuf, 0, &affected_rows)) {
safe_delete_array(query);
std::cerr << "Error1 in DeleteGraveyard query " << errbuf << std::endl;
return false;
}
if (affected_rows == 0) {
std::cerr << "Error2 in DeleteGraveyard query: affected_rows = 0" << std::endl;
return false;
}
query_length = sprintf(query,"DELETE FROM graveyard WHERE id=%u", graveyard_id);
if (!RunQuery(query, query_length, errbuf, 0, &affected_rows)) {
safe_delete_array(query);
std::cerr << "Error3 in DeleteGraveyard query " << errbuf << std::endl;
return false;
}
safe_delete_array(query);
if (affected_rows == 0) {
std::cerr << "Error4 in DeleteGraveyard query: affected_rows = 0" << std::endl;
return false;
}
return true;
}
uint32 ZoneDatabase::AddGraveyardIDToZone(uint32 zone_id, uint32 graveyard_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256];
char* end = query;
uint32 affected_rows = 0;
end += sprintf(end,"UPDATE zone SET graveyard_id=%u WHERE zoneidnumber=%u AND version=0", graveyard_id, zone_id);
if (!RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
std::cerr << "Error1 in AddGraveyardIDToZone query " << errbuf << std::endl;
return 0;
}
safe_delete_array(query);
if (affected_rows == 0) {
std::cerr << "Error2 in AddGraveyardIDToZone query: affected_rows = 0" << std::endl;
return 0;
}
return zone_id;
}
uint32 ZoneDatabase::NewGraveyardRecord(uint32 graveyard_zoneid, float graveyard_x, float graveyard_y, float graveyard_z, float graveyard_heading) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256];
char* end = query;
uint32 affected_rows = 0;
uint32 new_graveyard_id = 0;
end += sprintf(end,"INSERT INTO graveyard SET zone_id=%u, x=%1.1f, y=%1.1f, z=%1.1f, heading=%1.1f", graveyard_zoneid, graveyard_x, graveyard_y, graveyard_z, graveyard_heading);
if (!RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows, &new_graveyard_id)) {
safe_delete_array(query);
std::cerr << "Error1 in NewGraveyardRecord query " << errbuf << std::endl;
return 0;
}
safe_delete_array(query);
if (affected_rows == 0) {
std::cerr << "Error2 in NewGraveyardRecord query: affected_rows = 0" << std::endl;
return 0;
}
if(new_graveyard_id <= 0) {
std::cerr << "Error3 in NewGraveyardRecord query: new_graveyard_id <= 0" << std::endl;
return 0;
}
return new_graveyard_id;
}
uint32 ZoneDatabase::GraveyardPlayerCorpse(uint32 dbid, uint32 zoneid, uint16 instanceid, float x, float y, float z, float heading) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256];
char* end = query;
uint32 affected_rows = 0;
// We probably don't want a graveyard located in an instance.
end += sprintf(end,"Update player_corpses SET zoneid=%u, instanceid=0, x=%1.1f, y=%1.1f, z=%1.1f, heading=%1.1f, WasAtGraveyard=1 WHERE id=%d", zoneid, x, y, z, heading, dbid);
if (!RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
std::cerr << "Error1 in GraveyardPlayerCorpse query " << errbuf << std::endl;
return 0;
}
safe_delete_array(query);
if (affected_rows == 0) {
std::cerr << "Error2 in GraveyardPlayerCorpse query: affected_rows = 0" << std::endl;
return 0;
}
return dbid;
}
uint32 ZoneDatabase::UpdatePlayerCorpse(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, uchar* data, uint32 datasize, float x, float y, float z, float heading, bool rezzed) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256+(datasize*2)];
char* end = query;
uint32 affected_rows = 0;
end += sprintf(end, "Update player_corpses SET data=");
*end++ = '\'';
end += DoEscapeString(end, (char*)data, datasize);
*end++ = '\'';
end += sprintf(end,", charname='%s', zoneid=%u, instanceid=%u, charid=%d, x=%1.1f, y=%1.1f, z=%1.1f, heading=%1.1f WHERE id=%d", charname, zoneid, instanceid, charid, x, y, z, heading, dbid);
if (!RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
std::cerr << "Error1 in UpdatePlayerCorpse query " << errbuf << std::endl;
return 0;
}
safe_delete_array(query);
if (affected_rows == 0) {
std::cerr << "Error2 in UpdatePlayerCorpse query: affected_rows = 0" << std::endl;
return 0;
}
if(rezzed){
if (!RunQuery(query, MakeAnyLenString(&query, "update player_corpses set rezzed = 1 WHERE id=%d",dbid), errbuf)) {
std::cerr << "Error in UpdatePlayerCorpse/Rezzed query: " << errbuf << std::endl;
}
safe_delete_array(query);
}
return dbid;
}
void ZoneDatabase::MarkCorpseAsRezzed(uint32 dbid)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
if(!database.RunQuery(query,MakeAnyLenString(&query, "UPDATE player_corpses SET rezzed = 1 WHERE id = %i", dbid), errbuf))
{
LogFile->write(EQEMuLog::Error, "MarkCorpseAsRezzed failed: %s, %s", query, errbuf);
}
safe_delete_array(query);
}
uint32 ZoneDatabase::CreatePlayerCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, uchar* data, uint32 datasize, float x, float y, float z, float heading) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256+(datasize*2)];
char* end = query;
//MYSQL_RES *result;
//MYSQL_ROW row;
uint32 affected_rows = 0;
uint32 last_insert_id = 0;
end += sprintf(end, "Insert into player_corpses SET data=");
*end++ = '\'';
end += DoEscapeString(end, (char*)data, datasize);
*end++ = '\'';
end += sprintf(end,", charname='%s', zoneid=%u, instanceid=%u, charid=%d, x=%1.1f, y=%1.1f, z=%1.1f, heading=%1.1f, timeofdeath=Now(), IsBurried=0", charname, zoneid, instanceid, charid, x, y, z, heading);
if (!RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows, &last_insert_id)) {
safe_delete_array(query);
std::cerr << "Error1 in CreatePlayerCorpse query " << errbuf << std::endl;
return 0;
}
safe_delete_array(query);
if (affected_rows == 0) {
std::cerr << "Error2 in CreatePlayerCorpse query: affected_rows = 0" << std::endl;
return 0;
}
if (last_insert_id == 0) {
std::cerr << "Error3 in CreatePlayerCorpse query: last_insert_id = 0" << std::endl;
return 0;
}
return last_insert_id;
}
bool ZoneDatabase::CreatePlayerCorpseBackup(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, uchar* data, uint32 datasize, float x, float y, float z, float heading) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256+(datasize*2)];
char* end = query;
uint32 affected_rows = 0;
uint32 last_insert_id = 0;
bool result = false;
DBPlayerCorpse_Struct* dbpcs = (DBPlayerCorpse_Struct*) data;
if (dbid != 0) {
if(RuleB(Character, LeaveCorpses) == true && dbpcs->level >= RuleI(Character, DeathItemLossLevel)){
end += sprintf(end, "Insert into player_corpses_backup SET data=");
*end++ = '\'';
end += DoEscapeString(end, (char*)data, datasize);
*end++ = '\'';
end += sprintf(end,", charname='%s', zoneid=%u, instanceid=%u, charid=%d, x=%1.1f, y=%1.1f, z=%1.1f, heading=%1.1f, timeofdeath=Now(), IsBurried=0, id=%u", charname, zoneid, instanceid, charid, x, y, z, heading, dbid);
if (RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows)) {
if (affected_rows == 1)
result = true;
else
std::cerr << "Error in CreatePlayerCorpseBackup query: affected_rows != 1" << std::endl;
}
else
std::cerr << "Error in CreatePlayerCorpseBackup query " << errbuf << std::endl;
}
safe_delete_array(query);
}
else {
std::cerr << "Error in CreatePlayerCorpseBackup: dbid = 0" << std::endl;
}
return result;
}
uint32 ZoneDatabase::GetPlayerBurriedCorpseCount(uint32 char_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 CorpseCount = 0;
if (RunQuery(query, MakeAnyLenString(&query, "select count(*) from player_corpses where charid = '%u' and IsBurried = 1", char_id), errbuf, &result)) {
row = mysql_fetch_row(result);
CorpseCount = atoi(row[0]);
mysql_free_result(result);
}
else {
std::cerr << "Error in GetPlayerBurriedCorpseCount query '" << query << "' " << errbuf << std::endl;
}
safe_delete_array(query);
return CorpseCount;
}
uint32 ZoneDatabase::GetPlayerCorpseCount(uint32 char_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 CorpseCount = 0;
if (RunQuery(query, MakeAnyLenString(&query, "select count(*) from player_corpses where charid = '%u'", char_id), errbuf, &result)) {
row = mysql_fetch_row(result);
CorpseCount = atoi(row[0]);
mysql_free_result(result);
}
else {
std::cerr << "Error in GetPlayerCorpseCount query '" << query << "' " << errbuf << std::endl;
}
safe_delete_array(query);
return CorpseCount;
}
uint32 ZoneDatabase::GetPlayerCorpseID(uint32 char_id, uint8 corpse) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 id = 0;
if (RunQuery(query, MakeAnyLenString(&query, "select id from player_corpses where charid = '%u'", char_id), errbuf, &result)) {
for (int i=0; i<corpse;i++) {
row = mysql_fetch_row(result);
id = (uint32)atoi(row[0]);
}
mysql_free_result(result);
}
else {
std::cerr << "Error in GetPlayerCorpseID query '" << query << "' " << errbuf << std::endl;
}
safe_delete_array(query);
return id;
}
uint32 ZoneDatabase::GetPlayerCorpseItemAt(uint32 corpse_id, uint16 slotid) {
Corpse* tmp = LoadPlayerCorpse(corpse_id);
uint32 itemid = 0;
if (tmp) {
itemid = tmp->GetWornItem(slotid);
tmp->DepopCorpse();
}
return itemid;
}
Corpse* ZoneDatabase::SummonBurriedPlayerCorpse(uint32 char_id, uint32 dest_zoneid, uint16 dest_instanceid, float dest_x, float dest_y, float dest_z, float dest_heading) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
Corpse* NewCorpse = 0;
unsigned long* lengths;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, charname, data, timeofdeath, rezzed FROM player_corpses WHERE charid='%u' AND IsBurried=1 ORDER BY timeofdeath LIMIT 1", char_id), errbuf, &result)) {
row = mysql_fetch_row(result);
lengths = mysql_fetch_lengths(result);
if(row) {
NewCorpse = Corpse::LoadFromDBData(atoi(row[0]), char_id, row[1], (uchar*) row[2], lengths[2], dest_x, dest_y, dest_z, dest_heading, row[3],atoi(row[4])==1, false);
if(NewCorpse) {
entity_list.AddCorpse(NewCorpse);
NewCorpse->SetDecayTimer(RuleI(Character, CorpseDecayTimeMS));
NewCorpse->Spawn();
if(!UnburyPlayerCorpse(NewCorpse->GetDBID(), dest_zoneid, dest_instanceid, dest_x, dest_y, dest_z, dest_heading))
LogFile->write(EQEMuLog::Error, "Unable to unbury a summoned player corpse for character id %u.", char_id);
}
else
LogFile->write(EQEMuLog::Error, "Unable to construct a player corpse from a burried player corpse for character id %u.", char_id);
}
mysql_free_result(result);
}
else {
std::cerr << "Error in SummonBurriedPlayerCorpse query '" << query << "' " << errbuf << std::endl;
}
safe_delete_array(query);
return NewCorpse;
}
bool ZoneDatabase::SummonAllPlayerCorpses(uint32 char_id, uint32 dest_zoneid, uint16 dest_instanceid,
float dest_x, float dest_y, float dest_z, float dest_heading)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
Corpse* NewCorpse = 0;
int CorpseCount = 0;
unsigned long* lengths;
if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE player_corpses SET zoneid = %i, instanceid = %i, x = %f, y = %f, z = %f, "
"heading = %f, IsBurried = 0, WasAtGraveyard = 0 WHERE charid = %i",
dest_zoneid, dest_instanceid, dest_x, dest_y, dest_z, dest_heading, char_id), errbuf))
LogFile->write(EQEMuLog::Error, "Error moving corpses, Query = %s, Error = %s\n", query, errbuf);
safe_delete_array(query);
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, charname, data, timeofdeath, rezzed FROM player_corpses WHERE charid='%u'"
"ORDER BY timeofdeath", char_id), errbuf, &result))
{
while((row = mysql_fetch_row(result)))
{
lengths = mysql_fetch_lengths(result);
NewCorpse = Corpse::LoadFromDBData(atoi(row[0]), char_id, row[1], (uchar*) row[2], lengths[2], dest_x, dest_y,
dest_z, dest_heading, row[3],atoi(row[4])==1, false);
if(NewCorpse) {
entity_list.AddCorpse(NewCorpse);
NewCorpse->SetDecayTimer(RuleI(Character, CorpseDecayTimeMS));
NewCorpse->Spawn();
++CorpseCount;
}
else
LogFile->write(EQEMuLog::Error, "Unable to construct a player corpse for character id %u.", char_id);
}
mysql_free_result(result);
}
else
LogFile->write(EQEMuLog::Error, "Error in SummonAllPlayerCorpses Query = %s, Error = %s\n", query, errbuf);
safe_delete_array(query);
return (CorpseCount > 0);
}
bool ZoneDatabase::UnburyPlayerCorpse(uint32 dbid, uint32 new_zoneid, uint16 new_instanceid, float new_x, float new_y, float new_z, float new_heading) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = new char[256];
char* end = query;
uint32 affected_rows = 0;
bool Result = false;
end += sprintf(end, "UPDATE player_corpses SET IsBurried=0, zoneid=%u, instanceid=%u, x=%f, y=%f, z=%f, heading=%f, timeofdeath=Now(), WasAtGraveyard=0 WHERE id=%u", new_zoneid, new_instanceid, new_x, new_y, new_z, new_heading, dbid);
if (RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows)) {
if (affected_rows == 1)
Result = true;
else
std::cerr << "Error2 in UnburyPlayerCorpse query: affected_rows NOT EQUAL to 1, as expected." << std::endl;
}
else
std::cerr << "Error1 in UnburyPlayerCorpse query " << errbuf << std::endl;
safe_delete_array(query);
return Result;
}
Corpse* ZoneDatabase::LoadPlayerCorpse(uint32 player_corpse_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
Corpse* NewCorpse = 0;
unsigned long* lengths;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, charid, charname, x, y, z, heading, data, timeofdeath, rezzed, WasAtGraveyard FROM player_corpses WHERE id='%u'", player_corpse_id), errbuf, &result)) {
row = mysql_fetch_row(result);
lengths = mysql_fetch_lengths(result);
if(row && lengths)
{
NewCorpse = Corpse::LoadFromDBData(atoi(row[0]), atoi(row[1]), row[2], (uchar*) row[7], lengths[7], atof(row[3]), atoi(row[4]), atoi(row[5]), atoi(row[6]), row[8],atoi(row[9])==1, atoi(row[10]));
entity_list.AddCorpse(NewCorpse);
}
mysql_free_result(result);
}
else {
std::cerr << "Error in LoadPlayerCorpse query '" << query << "' " << errbuf << std::endl;
std::cerr << "Note that if your missing the 'rezzed' field you can add it with:\nALTER TABLE `player_corpses` ADD `rezzed` TINYINT UNSIGNED DEFAULT \"0\";\n";
}
safe_delete_array(query);
return NewCorpse;
}
bool ZoneDatabase::LoadPlayerCorpses(uint32 iZoneID, uint16 iInstanceID) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 query_length = 0;
unsigned long* lengths;
if(!RuleB(Zone, EnableShadowrest))
query_length = MakeAnyLenString(&query, "SELECT id, charid, charname, x, y, z, heading, data, timeofdeath, rezzed, WasAtGraveyard FROM player_corpses WHERE zoneid='%u' AND instanceid='%u'", iZoneID, iInstanceID);
else
query_length = MakeAnyLenString(&query, "SELECT id, charid, charname, x, y, z, heading, data, timeofdeath, rezzed, 0 FROM player_corpses WHERE zoneid='%u' AND instanceid='%u' AND IsBurried=0", iZoneID, iInstanceID);
if (RunQuery(query, query_length, errbuf, &result)) {
safe_delete_array(query);
while ((row = mysql_fetch_row(result))) {
lengths = mysql_fetch_lengths(result);
entity_list.AddCorpse(Corpse::LoadFromDBData(atoi(row[0]), atoi(row[1]), row[2], (uchar*) row[7], lengths[7], atof(row[3]), atoi(row[4]), atoi(row[5]), atoi(row[6]), row[8],atoi(row[9])==1, atoi(row[10])));
}
mysql_free_result(result);
}
else {
std::cerr << "Error in LoadPlayerCorpses query '" << query << "' " << errbuf << std::endl;
std::cerr << "Note that if your missing the 'rezzed' field you can add it with:\nALTER TABLE `player_corpses` ADD `rezzed` TINYINT UNSIGNED DEFAULT \"0\";\n";
safe_delete_array(query);
return false;
}
return true;
}
uint32 ZoneDatabase::GetFirstCorpseID(uint32 char_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 CorpseID = 0;
MakeAnyLenString(&query, "SELECT id FROM player_corpses WHERE charid='%u' AND IsBurried=0 ORDER BY timeofdeath LIMIT 1", char_id);
if (RunQuery(query, strlen(query), errbuf, &result)) {
if (mysql_num_rows(result)!= 0){
row = mysql_fetch_row(result);
CorpseID = atoi(row[0]);
mysql_free_result(result);
}
}
else {
std::cerr << "Error in GetFirstCorpseID query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return 0;
}
safe_delete_array(query);
return CorpseID;
}
bool ZoneDatabase::BuryPlayerCorpse(uint32 dbid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE player_corpses SET IsBurried = 1 WHERE id=%d", dbid), errbuf)) {
std::cerr << "Error in BuryPlayerCorpse query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
bool ZoneDatabase::BuryAllPlayerCorpses(uint32 charid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE player_corpses SET IsBurried = 1 WHERE charid=%d", charid), errbuf)) {
std::cerr << "Error in BuryPlayerCorpse query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
bool ZoneDatabase::DeletePlayerCorpse(uint32 dbid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "Delete from player_corpses where id=%d", dbid), errbuf)) {
std::cerr << "Error in DeletePlayerCorpse query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
// these functions operate with a material slot, which is from 0 to 8
uint32 Corpse::GetEquipment(uint8 material_slot) const {
int invslot;
if(material_slot > 8)
{
return 0;
}
invslot = Inventory::CalcSlotFromMaterial(material_slot);
if(invslot == -1)
return 0;
return GetWornItem(invslot);
}
uint32 Corpse::GetEquipmentColor(uint8 material_slot) const {
const Item_Struct *item;
if(material_slot > 8)
{
return 0;
}
item = database.GetItem(GetEquipment(material_slot));
if(item != 0)
{
return item_tint[material_slot].rgb.use_tint ?
item_tint[material_slot].color :
item->Color;
}
return 0;
}
void Corpse::AddLooter(Mob* who)
{
for (int i=0; i<MAX_LOOTERS; i++)
{
if (looters[i] == 0)
{
looters[i] = who->CastToClient()->CharacterID();
break;
}
}
}
void Corpse::LoadPlayerCorpseDecayTime(uint32 dbid){
if(!dbid)
return;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(timeofdeath)) FROM player_corpses WHERE id=%d and not timeofdeath=0", dbid), errbuf, &result)) {
safe_delete_array(query);
while ((row = mysql_fetch_row(result))) {
if(atoi(row[0]) > 0 && RuleI(Character, CorpseDecayTimeMS) > (atoi(row[0]) * 1000)) {
corpse_decay_timer.SetTimer(RuleI(Character, CorpseDecayTimeMS) - (atoi(row[0]) * 1000));
/*
if(RuleI(Character, CorpseResTimeMS) > (atoi(row[0]) * 1000)) {
corpse_res_timer.SetTimer(RuleI(Character, CorpseResTimeMS) - (atoi(row[0]) * 1000));
}
else {
corpse_res_timer.Disable();
can_rez = false;
}
*/
}
else {
corpse_decay_timer.SetTimer(2000);
//corpse_res_timer.SetTimer(300000);
}
if(atoi(row[0]) > 0 && RuleI(Zone, GraveyardTimeMS) > (atoi(row[0]) * 1000)) {
corpse_graveyard_timer.SetTimer(RuleI(Zone, GraveyardTimeMS) - (atoi(row[0]) * 1000));
}
else {
corpse_graveyard_timer.SetTimer(3000);
}
}
mysql_free_result(result);
}
else
safe_delete_array(query);
}
/*
void Corpse::CastRezz(uint16 spellid, Mob* Caster){
if(Rezzed()){
if(Caster && Caster->IsClient())
Caster->Message(13,"This character has already been resurrected.");
return;
}
APPLAYER* outapp = new APPLAYER(OP_RezzRequest, sizeof(Resurrect_Struct));
Resurrect_Struct* rezz = (Resurrect_Struct*) outapp->pBuffer;
memcpy(rezz->your_name,this->orgname,30);
memcpy(rezz->corpse_name,this->name,30);
memcpy(rezz->rezzer_name,Caster->GetName(),30);
memcpy(rezz->zone,zone->GetShortName(),15);
rezz->spellid = spellid;
rezz->x = this->x_pos;
rezz->y = this->y_pos;
rezz->z = (float)this->z_pos;
worldserver.RezzPlayer(outapp, rezzexp, OP_RezzRequest);
//DumpPacket(outapp);
safe_delete(outapp);
}
*/