| cybernine186 | 
			11-19-2008 01:08 AM | 
		 
		 
		 
		
			Loot a corpse to fast causes zone crash or item dupe   
		
		
		I have an issue when players loot there corpses to fast it can cause one of two things to happen. 
Zone crashes or they can duplicate an item in a particular slot in the corpses inventory.
 
I was thinking maybe putting some sort of timer on the item loot of a corpse to keep people from looting corpses to fast.
 
Maybe putting a timer in the function void Corpse::LootItem in PlayerCorpse.cpp to maybe 1/2 a second or maybe a full 1 second.
 
What do you guys think? 
 
Or is there already a fix for this and I haven't updated my source yet?
 
Here is my PlayerCorpse.cpp file
 
	Code: 
	
 /*  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> 
using namespace std; 
#ifdef WIN32 
#define snprintf        _snprintf 
#define vsnprintf        _vsnprintf 
#define strncasecmp        _strnicmp 
#define strcasecmp  _stricmp 
#endif 
 
#include "masterentity.h" 
#include "../common/packet_functions.h" 
#include "../common/crc32.h" 
#include "StringIDs.h" 
#include "worldserver.h" 
#include "../common/rulesys.h" 
 
 
#ifdef EMBPERL 
#include "embparser.h" 
#endif 
 
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, int8 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(int32 in_dbid, int32 in_charid, char* in_charname, uchar* in_data, int32 in_datasize, float in_x, float in_y, float in_z, float in_heading, char* timeofdeath, bool rezzed, bool wasAtGraveyard) { 
        if (in_datasize < sizeof(DBPlayerCorpse_Struct)) { 
                cout << "Corpse::LoadFromDBData: Corrupt data: in_datasize < sizeof(DBPlayerCorpse_Struct)" << endl; 
                return 0; 
        } 
        DBPlayerCorpse_Struct* dbpc = (DBPlayerCorpse_Struct*) in_data; 
        if (in_datasize != (sizeof(DBPlayerCorpse_Struct) + (dbpc->itemcount * sizeof(ServerLootItem_Struct)))) { 
                cout << "Corpse::LoadFromDBData: Corrupt data: in_datasize != expected size" << endl; 
                return 0; 
        } 
        if (dbpc->crc != CRC32::Generate(&((uchar*) dbpc)[4], in_datasize - 4)) { 
                cout << "Corpse::LoadFromDBData: Corrupt data: crc failure" << endl; 
                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(ServerLootItem_Struct)); 
                itemlist.push_back(tmp); 
        } 
        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, dbpc->race, 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->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, int32 in_npctypeid, const NPCType** in_npctypedata, int32 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, 
         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0,0,0,0,0,0,0), 
        corpse_decay_timer(in_decaytime), 
        corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), 
        corpse_graveyard_timer(0) 
{ 
        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()); 
         
        if(IsEmpty()) 
        { 
                corpse_decay_timer.SetTimer(RuleI(NPC,EmptyNPCCorpseDecayTimeMS)+1000); 
        } 
 
        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; 
                } 
        } 
        // 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, sint32 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, 
        0xff,        // aa title 
        0, 
        0, 
        0, 
        0, 
        0, 
        0, 
        0        // qglobal 
), 
        corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)), 
        corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), 
        corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)) 
{ 
        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; 
        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 
                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 
                for(i = 0; i <= 30; i++) 
                { 
                        item = client->GetInv().GetItem(i); 
                        if(((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) && !item->GetItem()->NoTransfer) 
                        { 
                                //client->Message(15, "Item to Corpse: %s NoTransfer: %s", item->GetItem()->Name, (item->GetItem()->NoTransfer == 0) ? "false" : "true"); 
                                MoveItemToCorpse(client, item, i); 
                        } 
                } 
                // cursor queue 
                iter_queue it; 
                for(it=client->GetInv().cursor_begin(),i=8000; it!=client->GetInv().cursor_end(); it++,i++) { 
                        item = *it; 
                        if(((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))  && !item->GetItem()->NoTransfer) 
                        { 
                                //client->Message(15, "Item to Corpse: %s NoTransfer: %s", item->GetItem()->Name, (item->GetItem()->NoTransfer == 0) ? "false" : "true"); 
                                MoveItemToCorpse(client, item, i); 
                        } 
                } 
                 
                client->Save(); 
        } //end "not leaving naked corpses" 
         
        Rezzed(false); 
        Save(); 
} 
 
// solar: helper function for client corpse constructor 
void Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot) 
{ 
        int bagindex; 
        sint16 interior_slot; 
        ItemInst *interior_item; 
        int notransID[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
        int notransinc = 0; 
 
        AddItem(item->GetItem()->ID, item->GetCharges(),  equipslot, item->GetAugmentItemID(0), item->GetAugmentItemID(1), item->GetAugmentItemID(2), item->GetAugmentItemID(3), item->GetAugmentItemID(4)); 
        if(item->IsType(ItemClassContainer)) 
        { 
                for(bagindex = 0; bagindex <= 10; bagindex++) 
                { 
                        interior_slot = Inventory::CalcSlotId(equipslot, bagindex); 
                        interior_item = client->GetInv().GetItem(interior_slot); 
                        if(interior_item && !interior_item->GetItem()->NoTransfer) 
                        { 
                                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)); 
                                client->DeleteItemInInventory(interior_slot, interior_item->GetCharges(), false); 
                        }else if(interior_item){ 
                                notransID[notransinc] = interior_item->GetItem()->ID; 
                                notransinc++; 
                                //client->PutLootInInventory(SLOT_CURSOR,*interior_item,0); 
                                client->DeleteItemInInventory(interior_slot, interior_item->GetCharges(), false); 
                        } 
                } 
        } 
         
        client->DeleteItemInInventory(equipslot, item->GetCharges(), false); 
 
        if(notransinc > 0) { 
                for(int x = 0; x <= notransinc; x++) { 
                        if(notransID[x] != 0){ 
                                client->SummonItem(notransID[x], 0, 0, 0, 0, 0, 0); 
                        } 
                } 
        } 
} 
 
// To be called from LoadFromDBData 
// Mongrel: added see_invis and see_invis_undead 
Corpse::Corpse(int32 in_dbid, int32 in_charid, char* in_charname, ItemList* in_itemlist, int32 in_copper, int32 in_silver, int32 in_gold, int32 in_plat, float in_x, float in_y, float in_z, float in_heading, float in_size, int8 in_gender, int16 in_race, int8 in_class, int8 in_deity, int8 in_level, int8 in_texture, int8 in_helmtexture,int32 in_rezexp, bool wasAtGraveyard) 
// vesuvias - appearence fix 
 : 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, 
         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 
         0,0,0,0,0,0,0), 
        corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)), 
        corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), 
        corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)) 
{ 
        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(); 
 
        //we really should be loading the decay timer here... 
         
        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]; 
        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; 
         
        int32 tmp = this->CountItems(); 
        int32 tmpsize = sizeof(DBPlayerCorpse_Struct) + (tmp * sizeof(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; 
        dbpc->race = race; 
        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; 
         
        int32 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(ServerLootItem_Struct)); 
        } 
 
        dbpc->crc = CRC32::Generate(&((uchar*) dbpc)[4], tmpsize - 4); 
 
        if (dbid == 0) 
                dbid = database.CreatePlayerCorpse(charid, orgname, zone->GetZoneID(), (uchar*) dbpc, tmpsize, x_pos, y_pos, z_pos, heading); 
        else 
                dbid = database.UpdatePlayerCorpse(dbid, charid, orgname, zone->GetZoneID(), (uchar*) dbpc, tmpsize, x_pos, y_pos, z_pos, heading,Rezzed()); 
        safe_delete(dbpc); 
        if (dbid == 0) { 
                cout << "Error: Failed to save player corpse '" << this->GetName() << "'" << endl; 
                return false; 
        } 
        return true; 
} 
 
void Corpse::Delete() { 
        if (IsPlayerCorpse() && dbid != 0) 
                database.DeletePlayerCorpse(dbid); 
        dbid = 0; 
 
        p_depop = true; 
} 
 
void Corpse::Depop(bool StartSpawnTimer) { 
        if (IsNPCCorpse()) 
                p_depop = true; 
} 
 
int32 Corpse::CountItems() { 
        return itemlist.size(); 
} 
 
void Corpse::AddItem(uint32 itemnum, int8 charges, sint16 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(int16 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++) { 
                sitem = *cur; 
                if(sitem->lootslot == lootslot) 
                        break; 
        } 
 
        if (sitem && bag_item_data && Inventory::SupportsContainers(sitem->equipSlot)) 
        { 
                sint16 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(sint16 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(int16 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); 
        //                pIsChanged = true;//Lieka Edit: Prevent Corpse Dupe 
                        this->Save(); //Lieka Edit: Prevent Corpse Dupe 
                        return; 
                } 
        } 
} 
 
void Corpse::RemoveItem(ServerLootItem_Struct* item_data) 
{ 
        int8 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); 
        //                this->Save();//Lieka Edit: Prevent Corpse Dupe 
                        return; 
                } 
        } 
} 
 
void Corpse::SetCash(int16 in_copper, int16 in_silver, int16 in_gold, int16 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->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_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(int32 decaytime) { 
        if (decaytime == 0) 
                corpse_decay_timer.Trigger(); 
        else 
                corpse_decay_timer.Start(decaytime); 
} 
 
bool Corpse::CanMobLoot(int charid) { 
        int8 z=0; 
        for(int i=0; i<MAX_LOOTERS; i++) { 
                if(looters[i] != 0) 
                        z++; 
 
                if (looters[i] == charid) 
                        return true; 
        } 
        if(z == 0 && !IsPlayerCorpse()) 
                return true; 
        else 
                return false; 
} 
 
void Corpse::AllowMobLoot(Mob *them, int8 slot) 
{ 
        if(slot >= MAX_LOOTERS) 
                return; 
        if(them == NULL || !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!"); 
                cout << "Error: PlayerCorpse::MakeLootRequestPackets: dbid = 0!" << 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; 
        } 
        int8 tCanLoot = 1; 
        bool lootcoin=true; 
        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() == 0 && CanMobLoot(client->CharacterID())) 
                tCanLoot = 6; //pvp coin loot 
        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) || tCanLoot == 6) { // 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);         
                                } 
                        } 
                        #ifdef GUILDWARS 
                                if (this->GetPlatinum()>10000) 
                                        this->RemoveCash(); 
                        #endif 
                        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(); 
                for(; cur != end; cur++) { 
                        ServerLootItem_Struct* item_data = *cur; 
                        item_data->lootslot = 0xFFFF; 
 
                        // Dont display the item if it's in a bag 
                        if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || tCanLoot>=3) 
                        { 
                                if (i >= 30) 
                                { 
                                                Message(13, "Warning: Too many items to display. Loot some then re-loot the corpse to see the rest"); 
                                } 
                                else 
                                { 
                                        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); 
                                                        safe_delete(inst); 
                                                } 
                                                item_data->lootslot = i; 
                                        } 
                                } 
                                i++; 
                        } 
                } 
 
        } 
         
        // Disgrace: Client seems to require that we send the packet back... 
        client->QueuePacket(app); 
} 
 
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); 
         
        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 = NULL, *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->ItemClass == 1) || (item->NoDrop == 0) || (item_data->equipSlot == 13) || (item_data->equipSlot == 14)) && ((charid != client->CharacterID()) && (IsPlayerCorpse()))) // Lieka:  Do not allow looting of no drop, bags, primary equipped or secondary equipped items from pvp corpses. 
        { 
                client->Message(13, "Looting of No Drop, Container, Primary Equipped, or Secondary Equipped Items from a PvP corpse is not permitted."); 
                return ; 
        } 
        //Begin Lieka Edit:  Prevent looting of bagged items 
        if (((item_data->equipSlot >= 251) && (item_data->equipSlot <= 330)) && ((charid != client->CharacterID()) && (IsPlayerCorpse()))) // Lieka:  Items in bags still show up on the loot menu.  Prevent them from being looted. 9-6-07 
        { 
                client->Message(13, "Looting of bagged items from a PvP corpse is not permitted. (This item was in your opponent's bag)"); 
                return ; 
        } 
        //Lieka End Edit 
        if (item != 0) 
        { 
                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); 
                 
                if(item_data && inst->IsStackable()) { 
                        //Restore charges from the original item. 
                        inst->SetCharges(item_data->charges); 
                } else { 
                        //default changes 
                        if(item->MaxCharges == -1) { 
                                inst->SetCharges(1); 
                        } else { 
                                inst->SetCharges(item_data->charges); 
                                //inst->SetCharges(item->MaxCharges);   //Null:  This line caused the item charges bug, leaving it incase removing it causes another bug. 
                        } 
                } 
        } 
 
        if (client && inst) 
        { 
                if (client->CheckLoreConflict(item)) 
                { 
                        client->Message_StringID(0,LOOT_LORE_ERROR); 
                        SendEndLootErrorPacket(client); 
                        BeingLootedBy = 0; 
                        delete inst; 
                        return; 
                } 
 
#ifdef EMBPERL 
                char buf[24]; 
                snprintf(buf, 23, "%d %d", inst->GetItem()->ID, inst->GetCharges()); 
                buf[23] = '\0'; 
                ((PerlembParser*)parse)->Event(EVENT_LOOT, 0, buf, (NPC*)NULL, client); 
#endif 
 
                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(client->CastToClient()->GetAdventureID()>0){ 
                        AdventureInfo AF=database.GetAdventureInfo(client->CastToClient()->GetAdventureID()); 
                        if((AF.type == ADVENTURE_COLLECT) && (zone->GetZoneID()== AF.zonedungeonid) 
                                && item_data->item_id == AF.Objetive) 
                                client->CastToClient()->SendAdventureUpdate(); 
                } 
                // 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); 
                } 
 
                // now remove it from the corpse 
                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 
                string link; 
                //TODO: generat a link... too lazy to find the format.. I have the hash algo though 
                //http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=70&postdays=0&postorder=asc 
                link = item->Name; 
                client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, link.c_str()); 
                if(!IsPlayerCorpse()) { 
                        Group *g = client->GetGroup(); 
                        if(g != NULL) { 
                                g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link.c_str()); 
                        } 
                } 
        } 
        else 
        { 
                SendEndLootErrorPacket(client); 
                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; 
        to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper); 
 
        ItemList::iterator cur,end; 
        cur = itemlist.begin(); 
        end = itemlist.end(); 
        for(; cur != end; cur++) { 
                ServerLootItem_Struct* sitem = *cur; 
                const Item_Struct* item = database.GetItem(sitem->item_id); 
                if (item) 
                        to->Message(0, "  %d: %s", item->ID, item->Name); 
                else 
                        to->Message(0, "  Error: 0x%04x", sitem->item_id); 
                x++; 
        } 
        to->Message(0, "%i items on %s.", x, this->GetName()); 
} 
 
void Corpse::Summon(Client* client,bool spell) { 
        int32 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."); 
                        } 
                        else if (DistNoRootNoZ(*client) <= dist2) { 
                                GMMove(client->GetX(), client->GetY(), client->GetZ()); 
                                pIsChanged = true; 
                        } 
                        else 
                                client->Message(0, "Corpse is too far away."); 
                } 
                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 (DistNoRootNoZ(*client) <= dist2) { 
                                                GMMove(client->GetX(), client->GetY(), client->GetZ()); 
                                                pIsChanged = true; 
                                        } 
                                        else 
                                                client->Message(0, "Corpse is too far away."); 
                                        } 
                                } 
                        if(!consented) 
                                client->Message(0, "You do not have permission to move this corpse."); 
                } 
        } else { //Sean:  Still broke :( 
                GMMove(client->GetX(), client->GetY(), client->GetZ()); 
                pIsChanged = true; 
        } 
        Save(); 
} 
 
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(int32 zone_id, int32 graveyard_id) { 
        char errbuf[MYSQL_ERRMSG_SIZE]; 
    char* query = new char[256]; 
        int32 query_length = 0; 
        int32 affected_rows = 0; 
         
        query_length = sprintf(query,"UPDATE zone SET graveyard_id=0 WHERE zoneidnumber=%u", zone_id); 
         
        if (!RunQuery(query, query_length, errbuf, 0, &affected_rows)) { 
                safe_delete_array(query); 
        cerr << "Error1 in DeleteGraveyard query " << errbuf << endl; 
                return false; 
    } 
         
        if (affected_rows == 0) { 
        cerr << "Error2 in DeleteGraveyard query: affected_rows = 0" << 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); 
        cerr << "Error3 in DeleteGraveyard query " << errbuf << endl; 
                return false; 
    } 
        safe_delete_array(query); 
         
        if (affected_rows == 0) { 
        cerr << "Error4 in DeleteGraveyard query: affected_rows = 0" << endl; 
                return false; 
        } 
 
        return true; 
} 
int32 ZoneDatabase::AddGraveyardIDToZone(int32 zone_id, int32 graveyard_id) { 
        char errbuf[MYSQL_ERRMSG_SIZE]; 
    char* query = new char[256]; 
        char* end = query; 
        int32 affected_rows = 0; 
         
        end += sprintf(end,"UPDATE zone SET graveyard_id=%u WHERE zoneidnumber=%u", graveyard_id, zone_id); 
         
        if (!RunQuery(query, (int32) (end - query), errbuf, 0, &affected_rows)) { 
                safe_delete_array(query); 
        cerr << "Error1 in AddGraveyardIDToZone query " << errbuf << endl; 
                return 0; 
    } 
        safe_delete_array(query); 
         
        if (affected_rows == 0) { 
        cerr << "Error2 in AddGraveyardIDToZone query: affected_rows = 0" << endl; 
                return 0; 
        } 
 
        return zone_id; 
} 
int32 ZoneDatabase::NewGraveyardRecord(int32 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; 
        int32 affected_rows = 0; 
        int32 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, (int32) (end - query), errbuf, 0, &affected_rows, &new_graveyard_id)) { 
                safe_delete_array(query); 
        cerr << "Error1 in NewGraveyardRecord query " << errbuf << endl; 
                return 0; 
    } 
        safe_delete_array(query); 
         
        if (affected_rows == 0) { 
        cerr << "Error2 in NewGraveyardRecord query: affected_rows = 0" << endl; 
                return 0; 
        } 
 
        if(new_graveyard_id <= 0) { 
                cerr << "Error3 in NewGraveyardRecord query: new_graveyard_id <= 0" << endl; 
                return 0; 
        } 
 
        return new_graveyard_id; 
} 
int32 ZoneDatabase::GraveyardPlayerCorpse(int32 dbid, int32 zoneid, float x, float y, float z, float heading) { 
        char errbuf[MYSQL_ERRMSG_SIZE]; 
    char* query = new char[256]; 
        char* end = query; 
        int32 affected_rows = 0; 
         
        end += sprintf(end,"Update player_corpses SET zoneid=%u, 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, (int32) (end - query), errbuf, 0, &affected_rows)) { 
                safe_delete_array(query); 
        cerr << "Error1 in GraveyardPlayerCorpse query " << errbuf << endl; 
                return 0; 
    } 
        safe_delete_array(query); 
         
        if (affected_rows == 0) { 
        cerr << "Error2 in GraveyardPlayerCorpse query: affected_rows = 0" << endl; 
                return 0; 
        } 
        return dbid; 
} 
int32 ZoneDatabase::UpdatePlayerCorpse(int32 dbid, int32 charid, const char* charname, int32 zoneid, uchar* data, int32 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; 
        int32 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, charid=%d, x=%1.1f, y=%1.1f, z=%1.1f, heading=%1.1f WHERE id=%d", charname, zoneid, charid, x, y, z, heading, dbid); 
         
        if (!RunQuery(query, (int32) (end - query), errbuf, 0, &affected_rows)) { 
                safe_delete_array(query); 
        cerr << "Error1 in UpdatePlayerCorpse query " << errbuf << endl; 
                return 0; 
    } 
        safe_delete_array(query); 
         
        if (affected_rows == 0) { 
        cerr << "Error2 in UpdatePlayerCorpse query: affected_rows = 0" << endl; 
                return 0; 
        } 
        if(rezzed){ 
                if (!RunQuery(query, MakeAnyLenString(&query, "update player_corpses set rezzed = 1 WHERE id=%d",dbid), errbuf)) { 
                        safe_delete_array(query); 
                        cerr << "Error in UpdatePlayerCorpse/Rezzed query: " << errbuf << endl; 
                } 
        } 
        return dbid; 
} 
 
int32 ZoneDatabase::CreatePlayerCorpse(int32 charid, const char* charname, int32 zoneid, uchar* data, int32 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; 
        int32 affected_rows = 0; 
        int32 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, charid=%d, x=%1.1f, y=%1.1f, z=%1.1f, heading=%1.1f, timeofdeath=Now(), IsBurried=0", charname, zoneid, charid, x, y, z, heading); 
         
    if (!RunQuery(query, (int32) (end - query), errbuf, 0, &affected_rows, &last_insert_id)) { 
                safe_delete_array(query); 
        cerr << "Error1 in CreatePlayerCorpse query " << errbuf << endl; 
                return 0; 
    } 
        safe_delete_array(query); 
         
        if (affected_rows == 0) { 
        cerr << "Error2 in CreatePlayerCorpse query: affected_rows = 0" << endl; 
                return 0; 
        } 
 
        if (last_insert_id == 0) { 
        cerr << "Error3 in CreatePlayerCorpse query: last_insert_id = 0" << endl; 
                return 0; 
        } 
         
        return last_insert_id; 
} 
 
int32 ZoneDatabase::GetPlayerBurriedCorpseCount(int32 char_id) { 
        char errbuf[MYSQL_ERRMSG_SIZE]; 
    char *query = 0; 
    MYSQL_RES *result; 
    MYSQL_ROW row; 
        int32 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 { 
                cerr << "Error in GetPlayerBurriedCorpseCount query '" << query << "' " << errbuf << endl; 
        } 
         
        safe_delete_array(query); 
 
        return CorpseCount; 
} 
 
Corpse* ZoneDatabase::SummonBurriedPlayerCorpse(int32 char_id, int32 dest_zoneid, 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); 
                                if(!UnburyPlayerCorpse(NewCorpse->GetDBID(), dest_zoneid, 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 { 
                cerr << "Error in SummonBurriedPlayerCorpse query '" << query << "' " << errbuf << endl; 
        } 
         
        safe_delete_array(query); 
 
        return NewCorpse; 
} 
 
bool ZoneDatabase::UnburyPlayerCorpse(int32 dbid, int32 new_zoneid, 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; 
        int32 affected_rows = 0; 
        bool Result = false; 
         
        end += sprintf(end, "UPDATE player_corpses SET IsBurried=0, zoneid=%u, x=%f, y=%f, z=%f, heading=%f, WasAtGraveyard=0 WHERE id=%u", new_zoneid, new_x, new_y, new_z, new_heading, dbid); 
         
        if (RunQuery(query, (int32) (end - query), errbuf, 0, &affected_rows)) { 
        if (affected_rows == 1) 
                        Result = true; 
                else 
                        cerr << "Error2 in UnburyPlayerCorpse query: affected_rows NOT EQUAL to 1, as expected." << endl; 
    } 
        else 
                cerr << "Error1 in UnburyPlayerCorpse query " << errbuf << endl; 
 
        safe_delete_array(query); 
 
        return Result; 
} 
 
Corpse* ZoneDatabase::LoadPlayerCorpse(int32 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); 
                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 { 
                cerr << "Error in LoadPlayerCorpse query '" << query << "' " << errbuf << endl; 
                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(int32 iZoneID) { 
        char errbuf[MYSQL_ERRMSG_SIZE]; 
    char *query = 0; 
    MYSQL_RES *result; 
    MYSQL_ROW row; 
        int32 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'", iZoneID); 
        else 
                query_length = MakeAnyLenString(&query, "SELECT id, charid, charname, x, y, z, heading, data, timeofdeath, rezzed FROM player_corpses WHERE zoneid='%u' AND IsBurried=0", iZoneID); 
 
        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 { 
                cerr << "Error in LoadPlayerCorpses query '" << query << "' " << errbuf << endl; 
                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; 
} 
 
bool ZoneDatabase::BuryPlayerCorpse(int32 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)) { 
                cerr << "Error in BuryPlayerCorpse query '" << query << "' " << errbuf << endl; 
                safe_delete_array(query); 
                return false; 
        } 
         
        safe_delete_array(query); 
        return true; 
} 
 
bool ZoneDatabase::DeletePlayerCorpse(int32 dbid) { 
        char errbuf[MYSQL_ERRMSG_SIZE]; 
    char *query = 0; 
         
        if (!RunQuery(query, MakeAnyLenString(&query, "Delete from player_corpses where id=%d", dbid), errbuf)) { 
                cerr << "Error in DeletePlayerCorpse query '" << query << "' " << errbuf << 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 
int32 Corpse::GetEquipment(int8 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(int8 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::CastRezz(int16 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); 
} 
*/ 
  
	 |