Merge git://github.com/EQEmu/Server into Development

This commit is contained in:
KayenEQ
2015-02-07 20:19:58 -05:00
14 changed files with 222 additions and 130 deletions
+5
View File
@@ -141,6 +141,11 @@ Client::Client(EQStreamInterface* ieqs)
merc_timer(RuleI(Mercs, UpkeepIntervalMS)),
ItemTickTimer(10000),
ItemQuestTimer(500),
anim_change_timer(100),
anon_toggle_timer(250),
afk_toggle_timer(250),
helm_toggle_timer(250),
light_update_timer(250),
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f),
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
+5
View File
@@ -1465,6 +1465,11 @@ private:
Timer TrackingTimer;
Timer RespawnFromHoverTimer;
Timer merc_timer;
Timer anim_change_timer;
Timer anon_toggle_timer;
Timer afk_toggle_timer;
Timer helm_toggle_timer;
Timer light_update_timer;
glm::vec3 m_Proximity;
+27 -21
View File
@@ -1838,9 +1838,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (loaditems) { /* Dont load if a length error occurs */
BulkSendInventoryItems();
/* Send stuff on the cursor which isnt sent in bulk */
for (auto iter = m_inv.cursor_begin(); iter != m_inv.cursor_end(); ++iter) {
for (auto iter = m_inv.cursor_cbegin(); iter != m_inv.cursor_cend(); ++iter) {
/* First item cursor is sent in bulk inventory packet */
if (iter == m_inv.cursor_begin())
if (iter == m_inv.cursor_cbegin())
continue;
const ItemInst *inst = *iter;
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
@@ -5516,7 +5516,7 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
if (damage < 0)
damage = 31337;
if (admin >= minStatusToAvoidFalling && GetGM()){
if (admin >= minStatusToAvoidFalling && GetGM()) {
Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
return;
@@ -5526,11 +5526,11 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
return;
}
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184){
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184) {
// Hard coded tutorial and load zones for no fall damage
return;
}
else{
else {
SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter)));
/* EVENT_ENVIRONMENTAL_DAMAGE */
@@ -12640,6 +12640,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
else if (sa->type == AT_Anim) {
if (IsAIControlled())
return;
if(!anim_change_timer.Check())
return;
if (sa->parameter == ANIM_STAND) {
SetAppearance(eaStanding);
playeraction = 0;
@@ -12673,15 +12677,6 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
SetFeigned(false);
}
// This is from old code
// I have no clue what it's for
/*
else if (sa->parameter == 0x05) {
// Illusion
std::cout << "Illusion packet recv'd:" << std::endl;
DumpPacket(app);
}
*/
else {
std::cerr << "Client " << name << " unknown apperance " << (int)sa->parameter << std::endl;
return;
@@ -12690,6 +12685,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
entity_list.QueueClients(this, app, true);
}
else if (sa->type == AT_Anon) {
if(!anon_toggle_timer.Check()) {
return;
}
// For Anon/Roleplay
if (sa->parameter == 1) { // Anon
m_pp.anon = 1;
@@ -12711,13 +12710,18 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
return;
}
else if (sa->type == AT_AFK) {
this->AFK = (sa->parameter == 1);
entity_list.QueueClients(this, app, true);
if(afk_toggle_timer.Check()) {
AFK = (sa->parameter == 1);
entity_list.QueueClients(this, app, true);
}
}
else if (sa->type == AT_Split) {
m_pp.autosplit = (sa->parameter == 1);
}
else if (sa->type == AT_Sneak) {
if(sneaking == 0)
return;
if (sa->parameter != 0)
{
if (!HasSkill(SkillSneak))
@@ -12729,7 +12733,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
}
return;
}
this->sneaking = 0;
sneaking = 0;
entity_list.QueueClients(this, app, true);
}
else if (sa->type == AT_Size)
@@ -12741,7 +12745,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
}
else if (sa->type == AT_Light) // client emitting light (lightstone, shiny shield)
{
entity_list.QueueClients(this, app, false);
//don't do anything with this
}
else if (sa->type == AT_Levitate)
{
@@ -12750,8 +12754,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
}
else if (sa->type == AT_ShowHelm)
{
m_pp.showhelm = (sa->parameter == 1);
entity_list.QueueClients(this, app, true);
if(helm_toggle_timer.Check()) {
m_pp.showhelm = (sa->parameter == 1);
entity_list.QueueClients(this, app, true);
}
}
else {
std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec
+7
View File
@@ -260,6 +260,13 @@ bool Client::Process() {
}
}
if(light_update_timer.Check()) {
UpdateEquipLightValue();
if(UpdateActiveLightValue()) {
SendAppearancePacket(AT_Light, GetActiveLightValue());
}
}
bool may_use_attacks = false;
/*
Things which prevent us from attacking:
+43 -25
View File
@@ -2618,7 +2618,7 @@ void command_peekinv(Client *c, const Seperator *sep)
}
else {
int cursorDepth = 0;
for (auto it = targetClient->GetInv().cursor_begin(); (it != targetClient->GetInv().cursor_end()); ++it, ++cursorDepth) {
for (auto it = targetClient->GetInv().cursor_cbegin(); (it != targetClient->GetInv().cursor_cend()); ++it, ++cursorDepth) {
inst_main = *it;
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
linker.SetItemInst(inst_main);
@@ -4284,31 +4284,49 @@ void command_goto(Client *c, const Seperator *sep)
void command_iteminfo(Client *c, const Seperator *sep)
{
const ItemInst* inst = c->GetInv()[MainCursor];
if (!inst)
c->Message(13, "Error: You need an item on your cursor for this command");
else {
const Item_Struct* item = inst->GetItem();
c->Message(0, "ID: %i Name: %s", item->ID, item->Name);
c->Message(0, " Lore: %s ND: %i NS: %i Type: %i", (item->LoreFlag) ? "true":"false", item->NoDrop, item->NoRent, item->ItemClass);
c->Message(0, " IDF: %s Size: %i Weight: %i icon_id: %i Price: %i", item->IDFile, item->Size, item->Weight, item->Icon, item->Price);
if (c->Admin() >= 200)
c->Message(0, "MinStatus: %i", item->MinStatus);
if (item->ItemClass==ItemClassBook)
c->Message(0, " This item is a Book: %s", item->Filename);
else if (item->ItemClass==ItemClassContainer)
c->Message(0, " This item is a container with %i slots", item->BagSlots);
else {
c->Message(0, " equipableSlots: %u equipable Classes: %u", item->Slots, item->Classes);
c->Message(0, " Magic: %i SpellID: %i Proc Level: %i DBCharges: %i CurCharges: %i", item->Magic, item->Click.Effect, item->Click.Level, item->MaxCharges, inst->GetCharges());
c->Message(0, " EffectType: 0x%02x CastTime: %.2f", (uint8) item->Click.Type, (double) item->CastTime/1000);
c->Message(0, " Material: 0x%02x Color: 0x%08x Skill: %i", item->Material, item->Color, item->ItemType);
c->Message(0, " Required level: %i Required skill: %i Recommended level:%i", item->ReqLevel, item->RecSkill, item->RecLevel);
c->Message(0, " Skill mod: %i percent: %i", item->SkillModType, item->SkillModValue);
c->Message(0, " BaneRace: %i BaneBody: %i BaneDMG: %i", item->BaneDmgRace, item->BaneDmgBody, item->BaneDmgAmt);
}
auto inst = c->GetInv()[MainCursor];
if (!inst) { c->Message(13, "Error: You need an item on your cursor for this command"); }
auto item = inst->GetItem();
if (!item) {
Log.Out(Logs::General, Logs::Inventory, "(%s) Command #iteminfo processed an item with no data pointer");
c->Message(13, "Error: This item has no data reference");
}
Client::TextLink linker;
linker.SetLinkType(linker.linkItemInst);
linker.SetItemInst(inst);
auto item_link = linker.GenerateLink();
c->Message(0, "*** Item Info for [%s] ***", item_link.c_str());
c->Message(0, ">> ID: %u, ItemUseType: %u, ItemClassType: %u", item->ID, item->ItemType, item->ItemClass);
c->Message(0, ">> IDFile: '%s', IconID: %u", item->IDFile, item->Icon);
c->Message(0, ">> Size: %u, Weight: %u, Price: %u, LDoNPrice: %u", item->Size, item->Weight, item->Price, item->LDoNPrice);
c->Message(0, ">> Material: 0x%02X, Color: 0x%08X, Tint: 0x%08X, Light: 0x%02X", item->Material, item->Color, inst->GetColor(), item->Light);
c->Message(0, ">> IsLore: %s, LoreGroup: %u, Lore: '%s'", (item->LoreFlag ? "TRUE" : "FALSE"), item->LoreGroup, item->Lore);
c->Message(0, ">> NoDrop: %u, NoRent: %u, NoPet: %u, NoTransfer: %u, FVNoDrop: %u",
item->NoDrop, item->NoRent, (uint8)item->NoPet, (uint8)item->NoTransfer, item->FVNoDrop);
if (item->ItemClass == ItemClassBook) {
c->Message(0, "*** This item is a Book (filename:'%s') ***", item->Filename);
}
else if (item->ItemClass == ItemClassContainer) {
c->Message(0, "*** This item is a Container (%u slots) ***", item->BagSlots);
}
else {
c->Message(0, "*** This item is Common ***");
c->Message(0, ">> Classes: %u, Races: %u, Slots: %u", item->Classes, item->Races, item->Slots);
c->Message(0, ">> ReqSkill: %u, ReqLevel: %u, RecLevel: %u", item->RecSkill, item->ReqLevel, item->RecLevel);
c->Message(0, ">> SkillModType: %u, SkillModValue: %i", item->SkillModType, item->SkillModValue);
c->Message(0, ">> BaneRaceType: %u, BaneRaceDamage: %u, BaneBodyType: %u, BaneBodyDamage: %i",
item->BaneDmgRace, item->BaneDmgRaceAmt, item->BaneDmgBody, item->BaneDmgAmt);
c->Message(0, ">> Magic: %s, SpellID: %i, ProcLevel: %u, Charges: %u, MaxCharges: %u",
(item->Magic ? "TRUE" : "FALSE"), item->Click.Effect, item->Click.Level, inst->GetCharges(), item->MaxCharges);
c->Message(0, ">> EffectType: 0x%02X, CastTime: %.2f", (uint8)item->Click.Type, ((double)item->CastTime / 1000));
}
if (c->Admin() >= 200)
c->Message(0, ">> MinStatus: %u", item->MinStatus);
}
void command_uptime(Client *c, const Seperator *sep)
+2 -2
View File
@@ -361,8 +361,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
database.QueryDatabase(ss.str().c_str());
}
auto start = client->GetInv().cursor_begin();
auto finish = client->GetInv().cursor_end();
auto start = client->GetInv().cursor_cbegin();
auto finish = client->GetInv().cursor_cend();
database.SaveCursor(client->CharacterID(), start, finish);
client->CalcBonuses();
+1 -1
View File
@@ -73,7 +73,7 @@ public:
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
inline void SetLeader(Mob* newleader){ leader=newleader; };
inline Mob* GetLeader() { return leader; };
const char* GetLeaderName() { return leader->GetName(); };
const char* GetLeaderName() { return membername[0]; };
void SendHPPacketsTo(Mob* newmember);
void SendHPPacketsFrom(Mob* newmember);
bool UpdatePlayer(Mob* update);
+73 -33
View File
@@ -177,16 +177,16 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
}
bool Client::CheckLoreConflict(const Item_Struct* item) {
if (!item)
return false;
if (!(item->LoreFlag))
return false;
bool Client::CheckLoreConflict(const Item_Struct* item)
{
if (!item) { return false; }
if (!item->LoreFlag) { return false; }
if (item->LoreGroup == 0) { return false; }
if (item->LoreGroup == -1) // Standard lore items; look everywhere except the shared bank, return the result
if (item->LoreGroup == 0xFFFFFFFF) // Standard lore items; look everywhere except the shared bank, return the result
return (m_inv.HasItem(item->ID, 0, ~invWhereSharedBank) != INVALID_INDEX);
//If the item has a lore group, we check for other items with the same group and return the result
// If the item has a lore group, we check for other items with the same group and return the result
return (m_inv.HasItemByLoreGroup(item->LoreGroup, ~invWhereSharedBank) != INVALID_INDEX);
}
@@ -619,7 +619,7 @@ void Client::DropItem(int16 slot_id)
// Save client inventory change to database
if (slot_id == MainCursor) {
SendCursorBuffer();
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(CharacterID(), s, e);
} else {
database.SaveInventory(CharacterID(), nullptr, slot_id);
@@ -680,20 +680,37 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
return INVALID_ID;
}
void Client::SendCursorBuffer() {
void Client::SendCursorBuffer()
{
// Temporary work-around for the RoF+ Client Buffer
// Instead of dealing with client moving items in cursor buffer,
// we can just send the next item in the cursor buffer to the cursor.
if (GetClientVersion() >= ClientVersion::RoF)
{
if (!GetInv().CursorEmpty())
{
const ItemInst* inst = GetInv().GetCursorItem();
if (inst)
{
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
}
}
if (GetClientVersion() < ClientVersion::RoF) { return; }
if (GetInv().CursorEmpty()) { return; }
auto test_inst = GetInv().GetCursorItem();
if (test_inst == nullptr) { return; }
auto test_item = test_inst->GetItem();
if (test_item == nullptr) { return; }
bool lore_pass = true;
if (test_item->LoreGroup == 0xFFFFFFFF) {
lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
}
else if (test_item->LoreGroup != 0) {
lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
}
if (!lore_pass) {
Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor",
GetName(), test_item->Name, test_item->ID);
Message_StringID(MT_LootMessages, 290);
parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0);
DeleteItemInInventory(MainCursor);
SendCursorBuffer();
}
else {
SendItemPacket(MainCursor, test_inst, ItemPacketSummonItem);
}
}
@@ -772,7 +789,7 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
const ItemInst* inst = nullptr;
if (slot_id == MainCursor) {
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
if(update_db)
database.SaveCursor(character_id, s, e);
}
@@ -826,7 +843,7 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
SendItemPacket(MainCursor, &inst, ItemPacketSummonItem);
}
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
return database.SaveCursor(CharacterID(), s, e);
}
@@ -851,7 +868,7 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
}
if (slot_id == MainCursor) {
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
return database.SaveCursor(this->CharacterID(), s, e);
}
else {
@@ -870,7 +887,7 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI
SendLootItemInPacket(&inst, slot_id);
if (slot_id == MainCursor) {
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(this->CharacterID(), s, e);
}
else {
@@ -1009,7 +1026,7 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
from.SetCharges(from.GetCharges() - charges_to_move);
SendLootItemInPacket(tmp_inst, to_slot);
if (to_slot == MainCursor) {
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(this->CharacterID(), s, e);
}
else {
@@ -1320,10 +1337,33 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
return false;
}
// This could be expounded upon at some point to let the server know that
// the client has moved a buffered cursor item onto the active cursor -U
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
if (GetClientVersion() >= ClientVersion::RoF) { return true; } // Can't do RoF+
if (move_in->to_slot == MainCursor) {
auto test_inst = m_inv.GetItem(MainCursor);
if (test_inst == nullptr) { return true; }
auto test_item = test_inst->GetItem();
if (test_item == nullptr) { return true; }
if (!test_item->LoreFlag) { return true; }
bool lore_pass = true;
if (test_item->LoreGroup == 0xFFFFFFFF) {
lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
}
else if (test_item->LoreGroup != 0) {
lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
}
if (!lore_pass) {
Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor",
GetName(), test_item->Name, test_item->ID);
Message_StringID(MT_LootMessages, 290);
parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0);
DeleteItemInInventory(MainCursor, 0, true);
}
}
return true;
}
@@ -1567,7 +1607,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
{
SendCursorBuffer();
}
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(character_id, s, e);
}
else
@@ -1726,7 +1766,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
{
SendCursorBuffer();
}
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(character_id, s, e);
}
else {
@@ -1734,7 +1774,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
if (dst_slot_id == MainCursor) {
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(character_id, s, e);
}
else {
@@ -2170,7 +2210,7 @@ void Client::RemoveNoRent(bool client_update)
}
local.clear();
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(this->CharacterID(), s, e);
}
}
@@ -2298,7 +2338,7 @@ void Client::RemoveDuplicateLore(bool client_update)
}
local_2.clear();
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(this->CharacterID(), s, e);
}
}
@@ -2826,9 +2866,9 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool
}
int limbo = 0;
for (auto cursor_itr = m_inv.cursor_begin(); cursor_itr != m_inv.cursor_end(); ++cursor_itr, ++limbo) {
for (auto cursor_itr = m_inv.cursor_cbegin(); cursor_itr != m_inv.cursor_cend(); ++cursor_itr, ++limbo) {
// m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above
if (cursor_itr == m_inv.cursor_begin())
if (cursor_itr == m_inv.cursor_cbegin())
continue;
instmap[8000 + limbo] = *cursor_itr;
+3 -6
View File
@@ -1479,8 +1479,6 @@ static void BazaarAuditTrail(const char *seller, const char *buyer, const char *
database.QueryDatabase(query);
}
void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicationPacket* app){
if(!Trader) return;
@@ -1509,15 +1507,15 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
BuyItem->GetItem()->Name, BuyItem->IsStackable(), tbs->Quantity, BuyItem->GetCharges());
// If the item is not stackable, then we can only be buying one of them.
if(!BuyItem->IsStackable())
outtbs->Quantity = tbs->Quantity;
outtbs->Quantity = 1; // normally you can't send more than 1 here
else {
// Stackable items, arrows, diamonds, etc
int ItemCharges = BuyItem->GetCharges();
int32 ItemCharges = BuyItem->GetCharges();
// ItemCharges for stackables should not be <= 0
if(ItemCharges <= 0)
outtbs->Quantity = 1;
// If the purchaser requested more than is in the stack, just sell them how many are actually in the stack.
else if(ItemCharges < (int16)tbs->Quantity)
else if(static_cast<uint32>(ItemCharges) < tbs->Quantity)
outtbs->Quantity = ItemCharges;
else
outtbs->Quantity = tbs->Quantity;
@@ -1609,7 +1607,6 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
safe_delete(outapp);
safe_delete(outapp2);
}
void Client::SendBazaarWelcome()
+2 -4
View File
@@ -195,11 +195,9 @@ void ZoneDatabase::UpdateSpawn2Timeleft(uint32 id, uint16 instance_id, uint32 ti
//if we pass timeleft as 0 that means we clear from respawn time
//otherwise we update with a REPLACE INTO
if(timeleft == 0) {
std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu "
"AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id);
std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
return;
}