Loading...   


diff --git a/common/item.cpp b/common/item.cpp
index 35de0e7..a43b5d1 100644
--- a/common/item.cpp
+++ b/common/item.cpp
@@ -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
diff --git a/common/item.h b/common/item.h
index 0868e8c..fd30b5e 100644
--- a/common/item.h
+++ b/common/item.h
@@ -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);
diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp
index 9494c50..772e605 100644
--- a/common/patches/rof.cpp
+++ b/common/patches/rof.cpp
@@ -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;
diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp
index d4c6199..6947ded 100644
--- a/common/patches/rof2.cpp
+++ b/common/patches/rof2.cpp
@@ -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;
diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp
index 2e96719..98f7fac 100644
--- a/common/patches/sod.cpp
+++ b/common/patches/sod.cpp
@@ -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;
diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp
index 44a87d3..b8a84d9 100644
--- a/common/patches/sof.cpp
+++ b/common/patches/sof.cpp
@@ -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;
diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp
index aa5d3d7..3be2d7d 100644
--- a/common/patches/titanium.cpp
+++ b/common/patches/titanium.cpp
@@ -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
diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp
index 3f29753..f772509 100644
--- a/common/patches/uf.cpp
+++ b/common/patches/uf.cpp
@@ -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;
diff --git a/common/ptimer.h b/common/ptimer.h
index 829a015..d12b677 100644
--- a/common/ptimer.h
+++ b/common/ptimer.h
@@ -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; }
 
diff --git a/common/shareddb.cpp b/common/shareddb.cpp
index c6158a7..0a303a8 100644
--- a/common/shareddb.cpp
+++ b/common/shareddb.cpp
@@ -499,6 +499,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv)
 		return false;
 	}
 
+	auto timestamps = GetItemRecastTimestamp(char_id);
+
 	for (auto row = results.begin(); row != results.end(); ++row) {
 		int16 slot_id = atoi(row[0]);
 		uint32 item_id = atoi(row[1]);
@@ -583,6 +585,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])
@@ -726,6 +735,19 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, Inventory *inv)
 	return GetSharedBank(account_id, inv, false);
 }
 
+std::map<uint32, uint32> SharedDatabase::GetItemRecastTimestamp(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::GetItemsCount(int32 &item_count, uint32 &max_id)
 {
 	item_count = -1;
diff --git a/common/shareddb.h b/common/shareddb.h
index 073c385..fcc625b 100644
--- a/common/shareddb.h
+++ b/common/shareddb.h
@@ -11,6 +11,7 @@
 #include "fixed_memory_variable_hash_set.h"
 
 #include <list>
+#include <map>
 
 class EvolveInfo;
 class Inventory;
@@ -69,6 +70,7 @@ 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> GetItemRecastTimestamp(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);
 
 
diff --git a/zone/client.h b/zone/client.h
index fbdcfb6..97453d5 100644
--- a/zone/client.h
+++ b/zone/client.h
@@ -1253,6 +1253,7 @@ public:
 	virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
 	int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false);
 
+
 protected:
 	friend class Mob;
 	void CalcItemBonuses(StatBonuses* newbon);
diff --git a/zone/spells.cpp b/zone/spells.cpp
index bf4da66..1b1cb16 100644
--- a/zone/spells.cpp
+++ b/zone/spells.cpp
@@ -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);
 		}
diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp
index bb81a0f..56236f1 100644
--- a/zone/zonedb.cpp
+++ b/zone/zonedb.cpp
@@ -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
diff --git a/zone/zonedb.h b/zone/zonedb.h
index 5c3ed3d..5e1a552 100644
--- a/zone/zonedb.h
+++ b/zone/zonedb.h
@@ -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);

Raw Paste Data