Make items with long reuse timers show the timer after zone

This adds a new table to store the timers in. This may seem
odd but the timers are associated with the player, not the
item, they're just included in the item header in the packet

Currently trading still needs to be handled
This commit is contained in:
Michael Cook (mackal) 2015-01-31 17:53:50 -05:00
parent b5d45effec
commit 5be1bd2ffb
19 changed files with 80 additions and 10 deletions

View File

@ -1441,6 +1441,7 @@ ItemInst::ItemInst(const Item_Struct* item, int16 charges) {
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
}
ItemInst::ItemInst(SharedDatabase *db, uint32 item_id, int16 charges) {
@ -1466,6 +1467,7 @@ ItemInst::ItemInst(SharedDatabase *db, uint32 item_id, int16 charges) {
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
}
ItemInst::ItemInst(ItemInstTypes use_type) {
@ -1486,6 +1488,7 @@ ItemInst::ItemInst(ItemInstTypes use_type) {
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
}
// Make a copy of an ItemInst object
@ -1539,6 +1542,7 @@ ItemInst::ItemInst(const ItemInst& copy)
m_ornamenticon = copy.m_ornamenticon;
m_ornamentidfile = copy.m_ornamentidfile;
m_ornament_hero_model = copy.m_ornament_hero_model;
m_recast_timestamp = copy.m_recast_timestamp;
}
// Clean up container contents

View File

@ -403,6 +403,8 @@ public:
void SetOrnamentationIDFile(uint32 ornament_idfile) { m_ornamentidfile = ornament_idfile; }
uint32 GetOrnamentHeroModel(int32 material_slot = -1) const;
void SetOrnamentHeroModel(uint32 ornament_hero_model) { m_ornament_hero_model = ornament_hero_model; }
uint32 GetRecastTimestamp() const { return m_recast_timestamp; }
void SetRecastTimestamp(uint32 in) { m_recast_timestamp = in; }
void Initialize(SharedDatabase *db = nullptr);
void ScaleItem();
@ -450,6 +452,7 @@ protected:
uint32 m_ornamenticon;
uint32 m_ornamentidfile;
uint32 m_ornament_hero_model;
uint32 m_recast_timestamp;
//
// Items inside of this item (augs or contents);

View File

@ -5000,7 +5000,7 @@ namespace RoF
hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0;
hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot;
hdr.unknown028 = 0;
hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0);
hdr.last_cast_time = inst->GetRecastTimestamp();
hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges);
hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0;
hdr.unknown044 = 0;

View File

@ -5069,7 +5069,7 @@ namespace RoF2
hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0;
hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot;
hdr.unknown028 = 0;
hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0);
hdr.last_cast_time = inst->GetRecastTimestamp();
hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges);
hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0;
hdr.unknown044 = 0;

View File

@ -3548,7 +3548,7 @@ namespace SoD
hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0;
hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot;
hdr.unknown028 = 0;
hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0);
hdr.last_cast_time = inst->GetRecastTimestamp();
hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges);
hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0;
hdr.unknown044 = 0;

View File

@ -2872,7 +2872,7 @@ namespace SoF
hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0;
hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot;
hdr.unknown028 = 0;
hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0);
hdr.last_cast_time = inst->GetRecastTimestamp();
hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges);
hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0;
hdr.unknown044 = 0;

View File

@ -2004,7 +2004,7 @@ namespace Titanium
inst->IsScaling() ? inst->GetExp() / 100 : 0,
//merchant_slot, //instance ID, bullshit for now
(merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot,
0, // item recast timer timestamp field (aka..last_cast_time field in SoF+ clients)
inst->GetRecastTimestamp(),
(stackable ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : charges),
inst->IsAttuned() ? 1 : 0,
0

View File

@ -3793,7 +3793,7 @@ namespace UF
hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0;
hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot;
hdr.unknown028 = 0;
hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0);
hdr.last_cast_time = inst->GetRecastTimestamp();
hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges);
hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0;
hdr.unknown044 = 0;

View File

@ -79,6 +79,7 @@ public:
inline const uint32 GetTimerTime() const { return timer_time; }
inline const uint32 GetStartTime() const { return start_time; }
inline const pTimerType GetType() const { return _type; }
inline const uint32 GetReadyTimestamp() const { return start_time + timer_time; }
inline bool Enabled() { return enabled; }

View File

@ -498,6 +498,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv)
return false;
}
auto timestamps = GetItemRecastTimestamps(char_id);
for (auto row = results.begin(); row != results.end(); ++row) {
int16 slot_id = atoi(row[0]);
uint32 item_id = atoi(row[1]);
@ -582,6 +584,13 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv)
else
inst->SetCharges(charges);
if (item->RecastDelay) {
if (timestamps.count(item->RecastType))
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
else
inst->SetRecastTimestamp(0);
}
if (item->ItemClass == ItemClassCommon) {
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
if (aug[i])
@ -725,6 +734,27 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, Inventory *inv)
return GetSharedBank(account_id, inv, false);
}
std::map<uint32, uint32> SharedDatabase::GetItemRecastTimestamps(uint32 char_id)
{
std::map<uint32, uint32> timers;
std::string query = StringFormat("SELECT recast_type,timestamp FROM character_item_recast WHERE id=%u", char_id);
auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0)
return timers;
for (auto row = results.begin(); row != results.end(); ++row)
timers[atoul(row[0])] = atoul(row[1]);
return timers; // RVO or move assigned
}
void SharedDatabase::ClearOldRecastTimestamps(uint32 char_id)
{
// This actually isn't strictly live-like. Live your recast timestamps are forever
std::string query =
StringFormat("DELETE FROM character_item_recast WHERE id = %u and timestamp < UNIX_TIMESTAMP()", char_id);
QueryDatabase(query);
}
void SharedDatabase::GetItemsCount(int32 &item_count, uint32 &max_id)
{
item_count = -1;

View File

@ -11,6 +11,7 @@
#include "fixed_memory_variable_hash_set.h"
#include <list>
#include <map>
class EvolveInfo;
class Inventory;
@ -69,6 +70,8 @@ class SharedDatabase : public Database
bool SetSharedPlatinum(uint32 account_id, int32 amount_to_add);
bool GetInventory(uint32 char_id, Inventory* inv);
bool GetInventory(uint32 account_id, char* name, Inventory* inv);
std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id);
void ClearOldRecastTimestamps(uint32 char_id);
bool SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin);

View File

@ -30,7 +30,7 @@
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9072
#define CURRENT_BINARY_DATABASE_VERSION 9073
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
#ifndef WIN32

View File

@ -326,6 +326,7 @@
9070|2015_01_28_quest_debug_log_category.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Quest Debug'|empty|
9071|2015_01_29_merc_stats_table_update.sql|SHOW COLUMNS FROM `merc_stats` LIKE 'statscale'|empty|
9072|2015_01_30_merc_attack_delay.sql|SHOW COLUMNS FROM `merc_stats` LIKE 'attack_delay'|empty|
9073|2015_01_31_character_item_recast.sql|SHOW TABLES LIKE 'character_item_recast'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1,7 @@
CREATE TABLE `character_item_recast` (
`id` int(11) UNSIGNED NOT NULL DEFAULT 0,
`recast_type` smallint(11) UNSIGNED NOT NULL DEFAULT 0,
`timestamp` int(11) UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY(`id`, `recast_type`),
KEY `id` (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = latin1;

View File

@ -1392,6 +1392,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (RuleB(Character, SharedBankPlat))
m_pp.platinum_shared = database.GetSharedPlatinum(this->AccountID());
database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */

View File

@ -965,6 +965,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
Save();
}
auto timestamps = database.GetItemRecastTimestamps(client->CharacterID());
outapp->priority = 6;
client->QueuePacket(outapp);
safe_delete(outapp);
@ -973,6 +974,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
const Item_Struct* item = database.GetItem(pkitem);
ItemInst* inst = database.CreateItem(item, item->MaxCharges);
if(inst) {
if (item->RecastDelay)
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
client->SendItemPacket(EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot);
safe_delete(inst);
}
@ -1004,6 +1007,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
if(client && item) {
ItemInst* inst = database.CreateItem(item, item_data->charges, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned);
if(inst) {
if (item->RecastDelay)
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
// MainGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = MainGeneral1 + MainCursor
client->SendItemPacket(i + EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot);
safe_delete(inst);
@ -1460,4 +1465,4 @@ void Corpse::LoadPlayerCorpseDecayTime(uint32 corpse_db_id){
else {
corpse_graveyard_timer.SetTimer(3000);
}
}
}

View File

@ -1242,6 +1242,8 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
{
//Can we start the timer here? I don't see why not.
CastToClient()->GetPTimers().Start((pTimerItemStart + recasttype), recastdelay);
database.UpdateItemRecastTimestamps(CastToClient()->CharacterID(), recasttype,
CastToClient()->GetPTimers().Get(pTimerItemStart + recasttype)->GetReadyTimestamp());
}
}
@ -2270,11 +2272,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
{
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
if(itm && itm->GetItem()->RecastDelay > 0){
CastToClient()->GetPTimers().Start((pTimerItemStart + itm->GetItem()->RecastType), itm->GetItem()->RecastDelay);
auto recast_type = itm->GetItem()->RecastType;
CastToClient()->GetPTimers().Start((pTimerItemStart + recast_type), itm->GetItem()->RecastDelay);
database.UpdateItemRecastTimestamps(
CastToClient()->CharacterID(), recast_type,
CastToClient()->GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp());
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
ird->recast_delay = itm->GetItem()->RecastDelay;
ird->recast_type = itm->GetItem()->RecastType;
ird->recast_type = recast_type;
CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}

View File

@ -2999,6 +2999,14 @@ void ZoneDatabase::RemoveTempFactions(Client *client) {
QueryDatabase(query);
}
void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp)
{
std::string query =
StringFormat("REPLACE INTO character_item_recast (id, recast_type, timestamp) VALUES (%u, %u, %u)", char_id,
recast_type, timestamp);
QueryDatabase(query);
}
void ZoneDatabase::LoadPetInfo(Client *client) {
// Load current pet and suspended pet

View File

@ -256,6 +256,7 @@ public:
void LoadPetInfo(Client *c);
void SavePetInfo(Client *c);
void RemoveTempFactions(Client *c);
void UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp);
/* Character Data Loaders */
bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list);