mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-28 13:01:31 +00:00
Merge branch 'master' into profiler
This commit is contained in:
commit
d39e886459
@ -1,5 +1,28 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 02/09/2015 ==
|
||||
Trevius: (RoF+) Setting Alt flag on characters in the Guild Management Window is now saved and functional for filtering.
|
||||
Trevius: (RoF+) Guild Invites between RoF+ and previous Clients is now functional.
|
||||
|
||||
== 02/08/2015 ==
|
||||
Kayen: Implemented npc specialability (44) COUNTER_AVOID_DAMAGE which when applied to the ATTACKING NPC will make their attacks more difficult to be avoided by riposte/dodge/parry/block.
|
||||
Parama0: Negative modifer value that affects ALL avoid damage types dodge/parry/riposte/block) chance on defender. Ie (44,50 = 50 pct reduction to ALL)
|
||||
Parama1: Negative modifer value that affects RIPOSTE chance on defender. Ie (44,1,0,50 = 50 pct reduction to riposte chance)
|
||||
Parama2: Negative modifer value that affects PARRY chance on defender. Ie (44,1,0,0,50 = 50 pct reduction to parry chance)
|
||||
Parama3: Negative modifer value that affects BLOCK chance on defender. Ie (44,1,0,0,0,50 = 50 pct reduction to block chance)
|
||||
Parama4: Negative modifer value that affects DODGE chance on defender. e (44,1,0,0,0,0,50 = 50 pct reduction to dodge chance)
|
||||
Example of usage: Player has Improved Dodge V (+50 pct dodge chance), you want to negate this bonus you would set 44,1,0,0,0,0,50 on your NPC.
|
||||
|
||||
== 02/07/2015 ==
|
||||
Akkadius: Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few
|
||||
See: https://www.youtube.com/watch?v=9kSFbyTBuAk
|
||||
|
||||
== 02/06/2015 ==
|
||||
Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const)
|
||||
Uleat: Replaced 'iter_inst' and 'iter_contents' typedefs with their stl definitions
|
||||
Uleat: Removed 'limbo' from the 'HasItem' series of checks - including lore checks. The client excludes this range and it causes issues when performing item searches - dupe lore checks were added to account for this.
|
||||
Uleat: Updated command #iteminfo to show light source information and a few other things
|
||||
|
||||
== 02/05/2015 ==
|
||||
Trevius: Fixed Environmental Damage for RoF2.
|
||||
|
||||
|
||||
@ -76,6 +76,24 @@ int GetSpellColumns(SharedDatabase *db) {
|
||||
return results.RowCount();
|
||||
}
|
||||
|
||||
bool IsStringField(int i) {
|
||||
switch(i)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ImportSpells(SharedDatabase *db) {
|
||||
Log.Out(Logs::General, Logs::Status, "Importing Spells...");
|
||||
FILE *f = fopen("import/spells_us.txt", "r");
|
||||
@ -113,7 +131,12 @@ void ImportSpells(SharedDatabase *db) {
|
||||
sql += "'";
|
||||
}
|
||||
|
||||
sql += split[i];
|
||||
if(split[i].compare("") == 0 && !IsStringField(i)) {
|
||||
sql += "0";
|
||||
}
|
||||
else {
|
||||
sql += split[i];
|
||||
}
|
||||
sql += "'";
|
||||
}
|
||||
|
||||
@ -128,7 +151,12 @@ void ImportSpells(SharedDatabase *db) {
|
||||
sql += "'";
|
||||
}
|
||||
|
||||
sql += split[i];
|
||||
if(split[i].compare("") == 0 && !IsStringField(i)) {
|
||||
sql += "0";
|
||||
} else {
|
||||
sql += split[i];
|
||||
}
|
||||
|
||||
sql += "'";
|
||||
}
|
||||
|
||||
|
||||
@ -506,6 +506,7 @@ int16 Inventory::HasItem(uint32 item_id, uint8 quantity, uint8 where)
|
||||
return slot_id;
|
||||
}
|
||||
|
||||
// Behavioral change - Limbo is no longer checked due to improper handling of return value
|
||||
if (where & invWhereCursor) {
|
||||
// Check cursor queue
|
||||
slot_id = _HasItem(m_cursor, item_id, quantity);
|
||||
@ -552,6 +553,7 @@ int16 Inventory::HasItemByUse(uint8 use, uint8 quantity, uint8 where)
|
||||
return slot_id;
|
||||
}
|
||||
|
||||
// Behavioral change - Limbo is no longer checked due to improper handling of return value
|
||||
if (where & invWhereCursor) {
|
||||
// Check cursor queue
|
||||
slot_id = _HasItemByUse(m_cursor, use, quantity);
|
||||
@ -597,6 +599,7 @@ int16 Inventory::HasItemByLoreGroup(uint32 loregroup, uint8 where)
|
||||
return slot_id;
|
||||
}
|
||||
|
||||
// Behavioral change - Limbo is no longer checked due to improper handling of return value
|
||||
if (where & invWhereCursor) {
|
||||
// Check cursor queue
|
||||
slot_id = _HasItemByLoreGroup(m_cursor, loregroup);
|
||||
@ -1060,7 +1063,7 @@ int Inventory::GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &col
|
||||
}
|
||||
|
||||
if (t_inst && !t_inst->IsType(ItemClassContainer)) {
|
||||
for (auto b_iter = t_inst->_begin(); b_iter != t_inst->_end(); ++b_iter) {
|
||||
for (auto b_iter = t_inst->_cbegin(); b_iter != t_inst->_cend(); ++b_iter) {
|
||||
if (b_iter->second == inst) {
|
||||
return Inventory::CalcSlotId(iter->first, b_iter->first);
|
||||
}
|
||||
@ -1071,13 +1074,10 @@ int Inventory::GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &col
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection) {
|
||||
iter_inst it;
|
||||
iter_contents itb;
|
||||
ItemInst* inst = nullptr;
|
||||
|
||||
for (it = collection.begin(); it != collection.end(); ++it) {
|
||||
inst = it->second;
|
||||
void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection)
|
||||
{
|
||||
for (auto it = collection.cbegin(); it != collection.cend(); ++it) {
|
||||
auto inst = it->second;
|
||||
if (!inst || !inst->GetItem())
|
||||
continue;
|
||||
|
||||
@ -1088,14 +1088,13 @@ void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection)
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) {
|
||||
iter_contents itb;
|
||||
|
||||
void Inventory::dumpBagContents(ItemInst *inst, std::map<int16, ItemInst*>::const_iterator *it)
|
||||
{
|
||||
if (!inst || !inst->IsType(ItemClassContainer))
|
||||
return;
|
||||
|
||||
// Go through bag, if bag
|
||||
for (itb = inst->_begin(); itb != inst->_end(); ++itb) {
|
||||
for (auto itb = inst->_cbegin(); itb != inst->_cend(); ++itb) {
|
||||
ItemInst* baginst = itb->second;
|
||||
if (!baginst || !baginst->GetItem())
|
||||
continue;
|
||||
@ -1110,7 +1109,7 @@ void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) {
|
||||
// Internal Method: Retrieves item within an inventory bucket
|
||||
ItemInst* Inventory::_GetItem(const std::map<int16, ItemInst*>& bucket, int16 slot_id) const
|
||||
{
|
||||
iter_inst it = bucket.find(slot_id);
|
||||
auto it = bucket.find(slot_id);
|
||||
if (it != bucket.end()) {
|
||||
return it->second;
|
||||
}
|
||||
@ -1123,6 +1122,8 @@ ItemInst* Inventory::_GetItem(const std::map<int16, ItemInst*>& bucket, int16 sl
|
||||
// Assumes item has already been allocated
|
||||
int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst)
|
||||
{
|
||||
// What happens here when we _PutItem(MainCursor)? Bad things..really bad things...
|
||||
//
|
||||
// If putting a nullptr into slot, we need to remove slot without memory delete
|
||||
if (inst == nullptr) {
|
||||
//Why do we not delete the poped item here????
|
||||
@ -1204,7 +1205,7 @@ int16 Inventory::_HasItem(std::map<int16, ItemInst*>& bucket, uint32 item_id, ui
|
||||
|
||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||
|
||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
||||
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||
auto bag_inst = bag_iter->second;
|
||||
if (bag_inst == nullptr) { continue; }
|
||||
|
||||
@ -1235,7 +1236,7 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
|
||||
|
||||
uint8 quantity_found = 0;
|
||||
|
||||
for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) {
|
||||
for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) {
|
||||
auto inst = *iter;
|
||||
if (inst == nullptr) { continue; }
|
||||
|
||||
@ -1252,7 +1253,7 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
|
||||
|
||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||
|
||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
||||
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||
auto bag_inst = bag_iter->second;
|
||||
if (bag_inst == nullptr) { continue; }
|
||||
|
||||
@ -1267,6 +1268,9 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
}
|
||||
}
|
||||
|
||||
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||
break;
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
@ -1289,7 +1293,7 @@ int16 Inventory::_HasItemByUse(std::map<int16, ItemInst*>& bucket, uint8 use, ui
|
||||
|
||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||
|
||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
||||
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||
auto bag_inst = bag_iter->second;
|
||||
if (bag_inst == nullptr) { continue; }
|
||||
|
||||
@ -1309,7 +1313,7 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity)
|
||||
{
|
||||
uint8 quantity_found = 0;
|
||||
|
||||
for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) {
|
||||
for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) {
|
||||
auto inst = *iter;
|
||||
if (inst == nullptr) { continue; }
|
||||
|
||||
@ -1321,7 +1325,7 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity)
|
||||
|
||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||
|
||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
||||
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||
auto bag_inst = bag_iter->second;
|
||||
if (bag_inst == nullptr) { continue; }
|
||||
|
||||
@ -1331,6 +1335,9 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity)
|
||||
return Inventory::CalcSlotId(MainCursor, bag_iter->first);
|
||||
}
|
||||
}
|
||||
|
||||
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||
break;
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
@ -1355,7 +1362,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
|
||||
|
||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||
|
||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
||||
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||
auto bag_inst = bag_iter->second;
|
||||
if (bag_inst == nullptr) { continue; }
|
||||
|
||||
@ -1378,7 +1385,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
|
||||
// Internal Method: Checks an inventory queue type bucket for a particular item
|
||||
int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
||||
{
|
||||
for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) {
|
||||
for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) {
|
||||
auto inst = *iter;
|
||||
if (inst == nullptr) { continue; }
|
||||
|
||||
@ -1395,7 +1402,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
||||
|
||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||
|
||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
||||
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||
auto bag_inst = bag_iter->second;
|
||||
if (bag_inst == nullptr) { continue; }
|
||||
|
||||
@ -1410,6 +1417,9 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
}
|
||||
}
|
||||
|
||||
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||
break;
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
@ -1505,8 +1515,7 @@ ItemInst::ItemInst(const ItemInst& copy)
|
||||
m_attuned=copy.m_attuned;
|
||||
m_merchantcount=copy.m_merchantcount;
|
||||
// Copy container contents
|
||||
iter_contents it;
|
||||
for (it=copy.m_contents.begin(); it!=copy.m_contents.end(); ++it) {
|
||||
for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) {
|
||||
ItemInst* inst_old = it->second;
|
||||
ItemInst* inst_new = nullptr;
|
||||
|
||||
@ -1676,7 +1685,7 @@ bool ItemInst::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
|
||||
// Retrieve item inside container
|
||||
ItemInst* ItemInst::GetItem(uint8 index) const
|
||||
{
|
||||
iter_contents it = m_contents.find(index);
|
||||
auto it = m_contents.find(index);
|
||||
if (it != m_contents.end()) {
|
||||
return it->second;
|
||||
}
|
||||
@ -1739,7 +1748,7 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent)
|
||||
// TODO: This needs work...
|
||||
|
||||
// Destroy container contents
|
||||
iter_contents cur, end, del;
|
||||
std::map<uint8, ItemInst*>::const_iterator cur, end, del;
|
||||
cur = m_contents.begin();
|
||||
end = m_contents.end();
|
||||
for (; cur != end;) {
|
||||
|
||||
@ -33,9 +33,6 @@ class EvolveInfo; // Stores information about an evolving item family
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
// Helper typedefs
|
||||
typedef std::map<int16, ItemInst*>::const_iterator iter_inst;
|
||||
typedef std::map<uint8, ItemInst*>::const_iterator iter_contents;
|
||||
|
||||
namespace ItemField
|
||||
{
|
||||
@ -86,8 +83,8 @@ public:
|
||||
// Public Methods
|
||||
/////////////////////////
|
||||
|
||||
inline std::list<ItemInst*>::const_iterator begin() { return m_list.begin(); }
|
||||
inline std::list<ItemInst*>::const_iterator end() { return m_list.end(); }
|
||||
inline std::list<ItemInst*>::const_iterator cbegin() { return m_list.cbegin(); }
|
||||
inline std::list<ItemInst*>::const_iterator cend() { return m_list.cend(); }
|
||||
|
||||
inline int size() { return static_cast<int>(m_list.size()); } // TODO: change to size_t
|
||||
inline bool empty() { return m_list.empty(); }
|
||||
@ -140,8 +137,8 @@ public:
|
||||
ItemInst* GetItem(int16 slot_id) const;
|
||||
ItemInst* GetItem(int16 slot_id, uint8 bagidx) const;
|
||||
|
||||
inline std::list<ItemInst*>::const_iterator cursor_begin() { return m_cursor.begin(); }
|
||||
inline std::list<ItemInst*>::const_iterator cursor_end() { return m_cursor.end(); }
|
||||
inline std::list<ItemInst*>::const_iterator cursor_cbegin() { return m_cursor.cbegin(); }
|
||||
inline std::list<ItemInst*>::const_iterator cursor_cend() { return m_cursor.cend(); }
|
||||
|
||||
inline int CursorSize() { return m_cursor.size(); }
|
||||
inline bool CursorEmpty() { return m_cursor.empty(); }
|
||||
@ -227,7 +224,7 @@ protected:
|
||||
|
||||
int GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &collection, ItemInst *inst);
|
||||
void dumpItemCollection(const std::map<int16, ItemInst*> &collection);
|
||||
void dumpBagContents(ItemInst *inst, iter_inst *it);
|
||||
void dumpBagContents(ItemInst *inst, std::map<int16, ItemInst*>::const_iterator *it);
|
||||
|
||||
// Retrieves item within an inventory bucket
|
||||
ItemInst* _GetItem(const std::map<int16, ItemInst*>& bucket, int16 slot_id) const;
|
||||
@ -425,8 +422,8 @@ protected:
|
||||
//////////////////////////
|
||||
// Protected Members
|
||||
//////////////////////////
|
||||
iter_contents _begin() { return m_contents.begin(); }
|
||||
iter_contents _end() { return m_contents.end(); }
|
||||
std::map<uint8, ItemInst*>::const_iterator _cbegin() { return m_contents.cbegin(); }
|
||||
std::map<uint8, ItemInst*>::const_iterator _cend() { return m_contents.cend(); }
|
||||
|
||||
friend class Inventory;
|
||||
|
||||
|
||||
@ -5053,7 +5053,7 @@ namespace RoF2
|
||||
|
||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
||||
|
||||
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%012d", item->ID);
|
||||
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
|
||||
|
||||
hdr.stacksize = stackable ? charges : 1;
|
||||
hdr.unknown004 = 0;
|
||||
|
||||
@ -4353,7 +4353,7 @@ struct RoF2SlotStruct
|
||||
|
||||
struct ItemSerializationHeader
|
||||
{
|
||||
/*000*/ char unknown000[13]; // New for HoT. Looks like a string.
|
||||
/*000*/ char unknown000[17]; // New for HoT. Looks like a string.
|
||||
/*017*/ uint32 stacksize;
|
||||
/*021*/ uint32 unknown004;
|
||||
/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ?
|
||||
|
||||
@ -300,7 +300,7 @@ RULE_INT ( Spells, MaxCastTimeReduction, 50) //Max percent your spell cast time
|
||||
RULE_INT ( Spells, RootBreakFromSpells, 55) //Chance for root to break when cast on.
|
||||
RULE_INT ( Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effects chance of death save firing.
|
||||
RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount.
|
||||
RULE_BOOL ( Spells, AdditiveBonusValues, false) //Allow certain bonuses to be calculated by adding together the value from each item, instead of taking the highest value. (ie Add together all Cleave Effects)
|
||||
RULE_INT ( Spells, AdditiveBonusWornType, 0) //Calc worn bonuses to add together (instead of taking highest) if set to THIS worn type. (2=Will covert live items automatically)
|
||||
RULE_BOOL ( Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this?
|
||||
RULE_BOOL ( Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live
|
||||
RULE_INT ( Spells, RootBreakCheckChance, 70) //Determines chance for a root break check to occur each buff tick.
|
||||
|
||||
@ -1183,7 +1183,7 @@ void SharedDatabase::GetFactionListInfo(uint32 &list_count, uint32 &max_lists) {
|
||||
auto row = results.begin();
|
||||
|
||||
list_count = static_cast<uint32>(atoul(row[0]));
|
||||
max_lists = static_cast<uint32>(atoul(row[1]));
|
||||
max_lists = static_cast<uint32>(atoul(row[1] ? row[1] : "0"));
|
||||
}
|
||||
|
||||
const NPCFactionList* SharedDatabase::GetNPCFactionEntry(uint32 id) {
|
||||
@ -1263,9 +1263,6 @@ bool SharedDatabase::LoadNPCFactionLists() {
|
||||
uint32 list_count = 0;
|
||||
uint32 max_lists = 0;
|
||||
GetFactionListInfo(list_count, max_lists);
|
||||
if(list_count == 0) {
|
||||
EQ_EXCEPT("SharedDatabase", "Database returned no result");
|
||||
}
|
||||
uint32 size = static_cast<uint32>(EQEmu::FixedMemoryHashSet<NPCFactionList>::estimated_size(
|
||||
list_count, max_lists));
|
||||
|
||||
@ -1883,7 +1880,7 @@ void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot
|
||||
auto row = results.begin();
|
||||
|
||||
loot_table_count = static_cast<uint32>(atoul(row[0]));
|
||||
max_loot_table = static_cast<uint32>(atoul(row[1]));
|
||||
max_loot_table = static_cast<uint32>(atoul(row[1] ? row[1] : "0"));
|
||||
loot_table_entries = static_cast<uint32>(atoul(row[2]));
|
||||
}
|
||||
|
||||
@ -1905,7 +1902,7 @@ void SharedDatabase::GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_d
|
||||
auto row =results.begin();
|
||||
|
||||
loot_drop_count = static_cast<uint32>(atoul(row[0]));
|
||||
max_loot_drop = static_cast<uint32>(atoul(row[1]));
|
||||
max_loot_drop = static_cast<uint32>(atoul(row[1] ? row[1] : "0"));
|
||||
loot_drop_entries = static_cast<uint32>(atoul(row[2]));
|
||||
}
|
||||
|
||||
|
||||
@ -32,9 +32,6 @@ void LoadFactions(SharedDatabase *database) {
|
||||
uint32 lists = 0;
|
||||
uint32 max_list = 0;
|
||||
database->GetFactionListInfo(lists, max_list);
|
||||
if(lists == 0) {
|
||||
EQ_EXCEPT("Shared Memory", "Unable to get any factions from the database.");
|
||||
}
|
||||
|
||||
uint32 size = static_cast<uint32>(EQEmu::FixedMemoryHashSet<NPCFactionList>::estimated_size(lists, max_list));
|
||||
EQEmu::MemoryMappedFile mmf("shared/faction", size);
|
||||
|
||||
@ -129,7 +129,7 @@ OP_GuildInviteAccept=0x78a5
|
||||
OP_GuildDemote=0x3100
|
||||
OP_GuildPromote=0x2945
|
||||
OP_GuildPublicNote=0x3c2c
|
||||
OP_GuildManageBanker=0x096d # Was 0x0737
|
||||
OP_GuildManageBanker=0x389c # Was 0x096d
|
||||
OP_GuildBank=0x2ab0 # Was 0x10c3
|
||||
OP_SetGuildRank=0x3599
|
||||
OP_GuildUpdateURLAndChannel=0x7851
|
||||
|
||||
@ -128,7 +128,7 @@ OP_GuildInviteAccept=0x7053
|
||||
OP_GuildDemote=0x2d4e
|
||||
OP_GuildPromote=0x6a98
|
||||
OP_GuildPublicNote=0x5053
|
||||
OP_GuildManageBanker=0x748f
|
||||
OP_GuildManageBanker=0x3f35
|
||||
OP_GuildBank=0x5134
|
||||
OP_SetGuildRank=0x0b9c
|
||||
OP_GuildUpdateURLAndChannel=0x2958
|
||||
@ -353,21 +353,22 @@ OP_Marquee=0x502e
|
||||
OP_ItemRecastDelay=0x15a9
|
||||
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
|
||||
|
||||
OP_DzQuit=0x205f
|
||||
OP_DzListTimers=0x0398
|
||||
OP_DzAddPlayer=0x59ca
|
||||
OP_DzRemovePlayer=0x4701
|
||||
OP_DzSwapPlayer=0x1abc
|
||||
OP_DzMakeLeader=0x405b
|
||||
OP_DzPlayerList=0x543d
|
||||
OP_DzJoinExpeditionConfirm=0x14c6
|
||||
OP_DzJoinExpeditionReply=0x7f4b
|
||||
OP_DzExpeditionInfo=0x4f7e
|
||||
OP_DzExpeditionList=0x9119
|
||||
OP_DzMemberStatus=0xb2e3
|
||||
OP_DzLeaderStatus=0x32f0
|
||||
# Expeditions
|
||||
OP_DzAddPlayer=0x4701
|
||||
OP_DzRemovePlayer=0x1abc
|
||||
OP_DzSwapPlayer=0x405b
|
||||
OP_DzMakeLeader=0x543d
|
||||
OP_DzPlayerList=0x14c6
|
||||
OP_DzJoinExpeditionConfirm=0x7f4b
|
||||
OP_DzJoinExpeditionReply=0x1950
|
||||
OP_DzListTimers=0x7b68
|
||||
OP_DzExpeditionInfo=0x9119
|
||||
OP_DzExpeditionList=0x205f
|
||||
OP_DzQuit=0xb2e3
|
||||
OP_DzMemberStatus=0x32f0
|
||||
OP_DzLeaderStatus=0x3de9
|
||||
OP_DzMemberList=0x5ae4
|
||||
OP_DzExpeditionEndsWarning=0x383c
|
||||
OP_DzMemberList=0x3de9
|
||||
OP_DzCompass=0x3e0e
|
||||
OP_DzChooseZone=0x0b7d
|
||||
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:AdditiveBonusWornType', '0', 'Calcs worn bonuses to add together (instead of taking highest) if item set to THIS worn type. Will stack with regular worn bonuses. (2=Will cause all live items to use this behavior)');
|
||||
|
||||
-- This is no longer used - Set the above value equal to 2 to achieve the same effect.
|
||||
DELETE FROM `rule_values` WHERE rule_name LIKE "Spells:AdditiveBonusValues";
|
||||
106
zone/attack.cpp
106
zone/attack.cpp
@ -362,13 +362,40 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
|
||||
//garunteed hit
|
||||
bool ghit = false;
|
||||
if((attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
||||
if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
||||
ghit = true;
|
||||
|
||||
bool InFront = false;
|
||||
|
||||
if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY()))
|
||||
InFront = true;
|
||||
|
||||
/*
|
||||
This special ability adds a negative modifer to the defenders riposte/block/parry/chance
|
||||
therefore reducing the defenders chance to successfully avoid the melee attack. At present
|
||||
time this is the only way to fine tune counter these mods on players. This may
|
||||
ultimately end up being more useful as fields in npc_types.
|
||||
*/
|
||||
|
||||
int counter_all = 0;
|
||||
int counter_riposte = 0;
|
||||
int counter_block = 0;
|
||||
int counter_parry = 0;
|
||||
int counter_dodge = 0;
|
||||
|
||||
if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)){
|
||||
|
||||
counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0);
|
||||
counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE,1);
|
||||
counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2);
|
||||
counter_parry = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 3);
|
||||
counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// make enrage same as riposte
|
||||
/////////////////////////////////////////////////////////
|
||||
if (IsEnraged() && other->InFrontMob(this, other->GetX(), other->GetY())) {
|
||||
if (IsEnraged() && InFront) {
|
||||
damage = -3;
|
||||
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
||||
}
|
||||
@ -377,9 +404,10 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
// riposte
|
||||
/////////////////////////////////////////////////////////
|
||||
float riposte_chance = 0.0f;
|
||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront)
|
||||
{
|
||||
riposte_chance = (100.0f + (float)defender->aabonuses.RiposteChance + (float)defender->spellbonuses.RiposteChance + (float)defender->itembonuses.RiposteChance) / 100.0f;
|
||||
riposte_chance = (100.0f + static_cast<float>(aabonuses.RiposteChance + spellbonuses.RiposteChance +
|
||||
itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f;
|
||||
skill = GetSkill(SkillRiposte);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
|
||||
@ -398,28 +426,19 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
bool bBlockFromRear = false;
|
||||
bool bShieldBlockFromRear = false;
|
||||
|
||||
if (this->IsClient()) {
|
||||
int aaChance = 0;
|
||||
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
||||
// from a direction other than the rear is granted.
|
||||
|
||||
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
||||
// from a direction other than the rear is granted.
|
||||
int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind;
|
||||
|
||||
//Live AA - HightenedAwareness
|
||||
int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind;
|
||||
|
||||
if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) {
|
||||
bBlockFromRear = true;
|
||||
|
||||
if (spellbonuses.BlockBehind || itembonuses.BlockBehind)
|
||||
bShieldBlockFromRear = true; //This bonus should allow a chance to Shield Block from behind.
|
||||
}
|
||||
}
|
||||
if (BlockBehindChance && zone->random.Roll(BlockBehindChance))
|
||||
bBlockFromRear = true;
|
||||
|
||||
float block_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassBlock() && (other->InFrontMob(this, other->GetX(), other->GetY()) || bBlockFromRear)) {
|
||||
block_chance = (100.0f + (float)spellbonuses.IncreaseBlockChance + (float)itembonuses.IncreaseBlockChance) / 100.0f;
|
||||
if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) {
|
||||
block_chance = (100.0f + static_cast<float>(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance +
|
||||
itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f;
|
||||
skill = CastToClient()->GetSkill(SkillBlock);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10);
|
||||
@ -435,32 +454,20 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
RollTable[1] = RollTable[0];
|
||||
}
|
||||
|
||||
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock)
|
||||
&& (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
||||
|
||||
float bonusShieldBlock = 0.0f;
|
||||
bonusShieldBlock = static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock);
|
||||
RollTable[1] += bonusShieldBlock;
|
||||
}
|
||||
|
||||
if(IsClient() && damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock)
|
||||
&& (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
||||
if(CastToClient()->m_inv.GetItem(MainPrimary)) {
|
||||
float bonusStaffBlock = 0.0f;
|
||||
if (CastToClient()->m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HBlunt){
|
||||
bonusStaffBlock = static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock);
|
||||
RollTable[1] += bonusStaffBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Try Shield Block OR TwoHandBluntBlockCheck
|
||||
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear))
|
||||
RollTable[1] += static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all);
|
||||
|
||||
else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear))
|
||||
RollTable[1] += static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// parry
|
||||
//////////////////////////////////////////////////////
|
||||
float parry_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassParry() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
||||
{
|
||||
parry_chance = (100.0f + (float)defender->spellbonuses.ParryChance + (float)defender->itembonuses.ParryChance) / 100.0f;
|
||||
if (damage > 0 && CanThisClassParry() && InFront){
|
||||
parry_chance = (100.0f + static_cast<float>(aabonuses.ParryChance + itembonuses.ParryChance +
|
||||
itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f;
|
||||
skill = CastToClient()->GetSkill(SkillParry);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
||||
@ -481,9 +488,11 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
// dodge
|
||||
////////////////////////////////////////////////////////
|
||||
float dodge_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassDodge() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
||||
{
|
||||
dodge_chance = (100.0f + (float)defender->spellbonuses.DodgeChance + (float)defender->itembonuses.DodgeChance) / 100.0f;
|
||||
if (damage > 0 && CanThisClassDodge() && InFront){
|
||||
|
||||
dodge_chance = (100.0f + static_cast<float>(aabonuses.DodgeChance + spellbonuses.DodgeChance +
|
||||
itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f;
|
||||
|
||||
skill = CastToClient()->GetSkill(SkillDodge);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
||||
@ -3521,6 +3530,10 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Melee Damage reduced to %d", damage);
|
||||
damage = ReduceAllDamage(damage);
|
||||
TryTriggerThreshHold(damage, SE_TriggerMeleeThreshold, attacker);
|
||||
|
||||
if (skill_used)
|
||||
CheckNumHitsRemaining(NumHit::IncomingHitSuccess);
|
||||
|
||||
} else {
|
||||
int32 origdmg = damage;
|
||||
damage = AffectMagicalDamage(damage, spell_id, iBuffTic, attacker);
|
||||
@ -3536,9 +3549,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker);
|
||||
}
|
||||
|
||||
if (skill_used)
|
||||
CheckNumHitsRemaining(NumHit::IncomingHitSuccess);
|
||||
|
||||
if(IsClient() && CastToClient()->sneaking){
|
||||
CastToClient()->sneaking = false;
|
||||
SendAppearancePacket(AT_Sneak, 0);
|
||||
|
||||
118
zone/bonuses.cpp
118
zone/bonuses.cpp
@ -139,7 +139,8 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
|
||||
// Clear item faction mods
|
||||
ClearItemFactionBonuses();
|
||||
ShieldEquiped(false);
|
||||
SetShieldEquiped(false);
|
||||
SetTwoHandBluntEquiped(false);
|
||||
|
||||
unsigned int i;
|
||||
//should not include 21 (SLOT_AMMO)
|
||||
@ -149,9 +150,12 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
continue;
|
||||
AddItemBonuses(inst, newbon);
|
||||
|
||||
//Check if item is secondary slot is a 'shield'. Required for multiple spelll effects.
|
||||
if (i == MainSecondary && (m_inv.GetItem(MainSecondary)->GetItem()->ItemType == ItemTypeShield))
|
||||
ShieldEquiped(true);
|
||||
//These are given special flags due to how often they are checked for various spell effects.
|
||||
const Item_Struct *item = inst->GetItem();
|
||||
if (i == MainSecondary && (item && item->ItemType == ItemTypeShield))
|
||||
SetShieldEquiped(true);
|
||||
else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt))
|
||||
SetTwoHandBluntEquiped(true);
|
||||
}
|
||||
|
||||
//Power Source Slot
|
||||
@ -169,6 +173,17 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
continue;
|
||||
AddItemBonuses(inst, newbon, false, true);
|
||||
}
|
||||
|
||||
//Optional ability to have worn effects calculate as an addititive bonus instead of highest value
|
||||
if (RuleI(Spells, AdditiveBonusWornType) && RuleI(Spells, AdditiveBonusWornType) != ET_WornEffect){
|
||||
for (i = MainCharm; i < MainAmmo; i++) {
|
||||
const ItemInst* inst = m_inv[i];
|
||||
if(inst == 0)
|
||||
continue;
|
||||
AdditiveWornBonuses(inst, newbon);
|
||||
}
|
||||
}
|
||||
|
||||
// Caps
|
||||
if(newbon->HPRegen > CalcHPRegenCap())
|
||||
newbon->HPRegen = CalcHPRegenCap();
|
||||
@ -410,12 +425,12 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
else
|
||||
newbon->DSMitigation += item->DSMitigation;
|
||||
}
|
||||
if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true, true);
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
}
|
||||
|
||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true, false);
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0);
|
||||
}
|
||||
|
||||
switch(item->BardType)
|
||||
@ -537,6 +552,45 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
|
||||
}
|
||||
|
||||
void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug) {
|
||||
|
||||
/*
|
||||
Powerful Non-live like option allows developers to add worn effects on items that
|
||||
can stack with other worn effects of the same spell effect type, instead of only taking the highest value.
|
||||
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||
To enable use RuleI(Spells, AdditiveBonusWornType)
|
||||
Setting value = 2 Will force all live items to automatically be calculated additivily
|
||||
Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation
|
||||
which will also stack with regular (worntype 2) effects. [Ie set rule = 3 and item worntype = 3]
|
||||
*/
|
||||
|
||||
if(!inst || !inst->IsType(ItemClassCommon))
|
||||
return;
|
||||
|
||||
if(inst->GetAugmentType()==0 && isAug == true)
|
||||
return;
|
||||
|
||||
const Item_Struct *item = inst->GetItem();
|
||||
|
||||
if(!inst->IsEquipable(GetBaseRace(),GetClass()))
|
||||
return;
|
||||
|
||||
if(GetLevel() < item->ReqLevel)
|
||||
return;
|
||||
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType))
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects
|
||||
|
||||
|
||||
if (!isAug)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
AdditiveWornBonuses(inst->GetAugment(i),newbon,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::CalcEdibleBonuses(StatBonuses* newbon) {
|
||||
uint32 i;
|
||||
|
||||
@ -1393,7 +1447,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++) {
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN){
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, false, buffs[i].ticsremaining,i);
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i);
|
||||
|
||||
if (buffs[i].numhits > 0)
|
||||
Numhits(true);
|
||||
@ -1416,10 +1470,11 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
||||
}
|
||||
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, bool item_bonus, bool IsWornEffect, uint32 ticsremaining, int buffslot,
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
{
|
||||
int i, effect_value, base2, max, effectid;
|
||||
bool AdditiveWornBonus = false;
|
||||
Mob *caster = nullptr;
|
||||
|
||||
if(!IsAISpellEffect && !IsValidSpell(spell_id))
|
||||
@ -1439,15 +1494,19 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
uint8 focus = IsFocusEffect(spell_id, i);
|
||||
if (focus)
|
||||
{
|
||||
if (!IsWornEffect)
|
||||
new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effectid[i]);
|
||||
if (WornType){
|
||||
if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i];
|
||||
}
|
||||
|
||||
else if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i];
|
||||
else
|
||||
new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effectid[i]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType))
|
||||
AdditiveWornBonus = true;
|
||||
|
||||
effectid = spells[spell_id].effectid[i];
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining);
|
||||
@ -1813,7 +1872,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_CriticalHitChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus) {
|
||||
if (AdditiveWornBonus) {
|
||||
if(base2 == -1)
|
||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -1839,7 +1898,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_CrippBlowChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->CrippBlowChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->CrippBlowChance > effect_value))
|
||||
@ -1853,7 +1912,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_AvoidMeleeChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->AvoidMeleeChanceEffect += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->AvoidMeleeChanceEffect > effect_value))
|
||||
@ -1866,7 +1925,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_RiposteChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->RiposteChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->RiposteChance > effect_value))
|
||||
@ -1879,7 +1938,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DodgeChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->DodgeChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->DodgeChance > effect_value))
|
||||
@ -1892,7 +1951,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_ParryChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->ParryChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->ParryChance > effect_value))
|
||||
@ -1905,7 +1964,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DualWieldChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->DualWieldChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->DualWieldChance > effect_value))
|
||||
@ -1919,7 +1978,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_DoubleAttackChance:
|
||||
{
|
||||
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->DoubleAttackChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->DoubleAttackChance > effect_value))
|
||||
@ -1933,7 +1992,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_TripleAttackChance:
|
||||
{
|
||||
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->TripleAttackChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->TripleAttackChance > effect_value))
|
||||
@ -1946,7 +2005,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_MeleeLifetap:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->MeleeLifetap += spells[spell_id].base[i];
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->MeleeLifetap > effect_value))
|
||||
@ -1995,7 +2054,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_HundredHands:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->HundredHands += effect_value;
|
||||
|
||||
if (effect_value > 0 && effect_value > new_bonus->HundredHands)
|
||||
@ -2017,7 +2076,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_HitChance:
|
||||
{
|
||||
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus){
|
||||
if (AdditiveWornBonus){
|
||||
if(base2 == -1)
|
||||
new_bonus->HitChanceEffect[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -2084,7 +2143,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_ProcChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->ProcChanceSPA += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->ProcChanceSPA > effect_value))
|
||||
@ -2122,7 +2181,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DivineSave:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus) {
|
||||
if (AdditiveWornBonus) {
|
||||
new_bonus->DivineSaveChance[0] += effect_value;
|
||||
new_bonus->DivineSaveChance[1] = 0;
|
||||
}
|
||||
@ -2131,7 +2190,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
{
|
||||
new_bonus->DivineSaveChance[0] = effect_value;
|
||||
new_bonus->DivineSaveChance[1] = base2;
|
||||
//SetDeathSaveChance(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3051,12 +3109,12 @@ void NPC::CalcItemBonuses(StatBonuses *newbon)
|
||||
newbon->ProcChance += cur->CombatEffects;
|
||||
}
|
||||
if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon);
|
||||
ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, 0, cur->Worn.Type);
|
||||
}
|
||||
|
||||
if (RuleB(Spells, NPC_UseFocusFromItems)){
|
||||
if (cur->Focus.Effect>0 && (cur->Focus.Type == ET_Focus)){ // focus effects
|
||||
ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon, 0, true);
|
||||
ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10959,7 +10959,7 @@ void Bot::CalcItemBonuses()
|
||||
}
|
||||
}
|
||||
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses);
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11043,7 +11043,7 @@ void Bot::CalcItemBonuses()
|
||||
}
|
||||
}
|
||||
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses);
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,6 +141,10 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
merc_timer(RuleI(Mercs, UpkeepIntervalMS)),
|
||||
ItemTickTimer(10000),
|
||||
ItemQuestTimer(500),
|
||||
anon_toggle_timer(250),
|
||||
afk_toggle_timer(250),
|
||||
helm_toggle_timer(250),
|
||||
light_update_timer(600),
|
||||
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),
|
||||
@ -409,6 +413,69 @@ Client::~Client() {
|
||||
UninitializeBuffSlots();
|
||||
}
|
||||
|
||||
void Client::SendZoneInPackets()
|
||||
{
|
||||
//////////////////////////////////////////////////////
|
||||
// Spawn Appearance Packet
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// Inform the world about the client
|
||||
outapp = new EQApplicationPacket();
|
||||
|
||||
CreateSpawnPacket(outapp);
|
||||
outapp->priority = 6;
|
||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
SendAAStats();
|
||||
|
||||
// Send exp packets
|
||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
||||
|
||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
||||
eu->exp = (uint32)(330.0f * tmpxp);
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
SendAATimers();
|
||||
|
||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||
strcpy(zonesendname->name, m_pp.name);
|
||||
strcpy(zonesendname->name2, m_pp.name);
|
||||
zonesendname->unknown0 = 0x0A;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (IsInAGuild()) {
|
||||
SendGuildMembers();
|
||||
SendGuildURL();
|
||||
SendGuildChannel();
|
||||
SendGuildLFGuildStatus();
|
||||
}
|
||||
SendLFGuildStatus();
|
||||
|
||||
//No idea why live sends this if even were not in a guild
|
||||
SendGuildMOTD();
|
||||
}
|
||||
|
||||
void Client::SendLogoutPackets() {
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_CancelTrade, sizeof(CancelTrade_Struct));
|
||||
@ -2471,11 +2538,13 @@ void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32
|
||||
|
||||
bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
||||
EQApplicationPacket* outapp = 0;
|
||||
if(!fail) {
|
||||
if(!fail)
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct));
|
||||
BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer;
|
||||
// Start bind
|
||||
if(!bindwound_timer.Enabled()) {
|
||||
if(!bindwound_timer.Enabled())
|
||||
{
|
||||
//make sure we actually have a bandage... and consume it.
|
||||
int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal);
|
||||
if (bslot == INVALID_INDEX) {
|
||||
@ -2521,7 +2590,9 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
||||
; // Binding self
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if (bindwound_timer.Check()) // Did the timer finish?
|
||||
{
|
||||
// finish bind
|
||||
// disable complete timer
|
||||
bindwound_timer.Disable();
|
||||
|
||||
@ -1257,6 +1257,7 @@ protected:
|
||||
friend class Mob;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false);
|
||||
void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false);
|
||||
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
|
||||
void CalcEdibleBonuses(StatBonuses* newbon);
|
||||
void CalcAABonuses(StatBonuses* newbon);
|
||||
@ -1414,6 +1415,7 @@ private:
|
||||
|
||||
bool CanBeInZone();
|
||||
void SendLogoutPackets();
|
||||
void SendZoneInPackets();
|
||||
bool AddPacket(const EQApplicationPacket *, bool);
|
||||
bool AddPacket(EQApplicationPacket**, bool);
|
||||
bool SendAllPackets();
|
||||
@ -1464,6 +1466,10 @@ private:
|
||||
Timer TrackingTimer;
|
||||
Timer RespawnFromHoverTimer;
|
||||
Timer merc_timer;
|
||||
Timer anon_toggle_timer;
|
||||
Timer afk_toggle_timer;
|
||||
Timer helm_toggle_timer;
|
||||
Timer light_update_timer;
|
||||
|
||||
glm::vec3 m_Proximity;
|
||||
|
||||
|
||||
@ -1089,76 +1089,15 @@ void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app)
|
||||
{
|
||||
//////////////////////////////////////////////////////
|
||||
// Spawn Appearance Packet
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||
outapp->priority = 6;
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendExpZonein, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// Inform the world about the client
|
||||
outapp = new EQApplicationPacket();
|
||||
|
||||
CreateSpawnPacket(outapp);
|
||||
outapp->priority = 6;
|
||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
SendAAStats();
|
||||
|
||||
// Send exp packets
|
||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
||||
|
||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
||||
eu->exp = (uint32)(330.0f * tmpxp);
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
// SoF+ Gets Zone-In packets after sending OP_WorldObjectsSent
|
||||
if (GetClientVersion() < ClientVersion::SoF)
|
||||
{
|
||||
SendZoneInPackets();
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
SendAATimers();
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SendExpZonein, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||
strcpy(zonesendname->name, m_pp.name);
|
||||
strcpy(zonesendname->name2, m_pp.name);
|
||||
zonesendname->unknown0 = 0x0A;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
/* this is actually the guild MOTD
|
||||
outapp = new EQApplicationPacket(OP_ZoneInSendName2, sizeof(ZoneInSendName_Struct2));
|
||||
ZoneInSendName_Struct2* zonesendname2=(ZoneInSendName_Struct2*)outapp->pBuffer;
|
||||
strcpy(zonesendname2->name,m_pp.name);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);*/
|
||||
|
||||
if (IsInAGuild()) {
|
||||
SendGuildMembers();
|
||||
SendGuildURL();
|
||||
SendGuildChannel();
|
||||
SendGuildLFGuildStatus();
|
||||
}
|
||||
SendLFGuildStatus();
|
||||
|
||||
//No idea why live sends this if even were not in a guild
|
||||
SendGuildMOTD();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1216,72 +1155,13 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app)
|
||||
{
|
||||
//This is a copy of SendExpZonein created for SoF+ due to packet order change
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Spawn Appearance Packet
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||
outapp->priority = 6;
|
||||
// New for SoF+
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// Inform the world about the client
|
||||
outapp = new EQApplicationPacket();
|
||||
|
||||
CreateSpawnPacket(outapp);
|
||||
outapp->priority = 6;
|
||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
SendAAStats();
|
||||
|
||||
// Send exp packets
|
||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
||||
|
||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
||||
eu->exp = (uint32)(330.0f * tmpxp);
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
SendAATimers();
|
||||
|
||||
// New for Secrets of Faydwer - Used in Place of OP_SendExpZonein
|
||||
outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||
strcpy(zonesendname->name, m_pp.name);
|
||||
strcpy(zonesendname->name2, m_pp.name);
|
||||
zonesendname->unknown0 = 0x0A;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (IsInAGuild()) {
|
||||
SendGuildMembers();
|
||||
SendGuildURL();
|
||||
SendGuildChannel();
|
||||
SendGuildLFGuildStatus();
|
||||
}
|
||||
SendLFGuildStatus();
|
||||
|
||||
//No idea why live sends this if even were not in a guild
|
||||
SendGuildMOTD();
|
||||
// Packet order changed for SoF+, so below is sent here instead of OP_SendExpLogin
|
||||
SendZoneInPackets();
|
||||
|
||||
if (RuleB(Mercs, AllowMercs))
|
||||
{
|
||||
@ -1838,9 +1718,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);
|
||||
@ -7360,6 +7240,16 @@ void Client::Handle_OP_GuildInvite(const EQApplicationPacket *app)
|
||||
if (gc->guildeqid == 0)
|
||||
gc->guildeqid = GuildID();
|
||||
|
||||
// Convert Membership Level between RoF and previous clients.
|
||||
if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
gc->officer = 0;
|
||||
}
|
||||
if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF)
|
||||
{
|
||||
gc->officer = 8;
|
||||
}
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Guilds, "Sending OP_GuildInvite for invite to %s, length %d", client->GetName(), app->size);
|
||||
client->SetPendingGuildInvitation(true);
|
||||
client->QueuePacket(app);
|
||||
@ -7394,6 +7284,8 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
||||
|
||||
GuildInviteAccept_Struct* gj = (GuildInviteAccept_Struct*)app->pBuffer;
|
||||
|
||||
uint32 guildrank = gj->response;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
if (gj->response > 9)
|
||||
@ -7422,9 +7314,25 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
||||
Log.Out(Logs::Detail, Logs::Guilds, "Guild Invite Accept: guild %d, response %d, inviter %s, person %s",
|
||||
gj->guildeqid, gj->response, gj->inviter, gj->newmember);
|
||||
|
||||
//ok, the invite is also used for changing rank as well.
|
||||
Mob* inviter = entity_list.GetMob(gj->inviter);
|
||||
|
||||
if (inviter && inviter->IsClient())
|
||||
{
|
||||
Client* client = inviter->CastToClient();
|
||||
// Convert Membership Level between RoF and previous clients.
|
||||
if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
guildrank = 0;
|
||||
}
|
||||
if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF)
|
||||
{
|
||||
guildrank = 8;
|
||||
}
|
||||
}
|
||||
//we dont really care a lot about what this packet means, as long as
|
||||
//it has been authorized with the guild manager
|
||||
if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, gj->response)) {
|
||||
if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, guildrank)) {
|
||||
worldserver.SendEmoteMessage(gj->inviter, 0, 0, "%s has sent an invalid response to your invite!", GetName());
|
||||
Message(13, "Invalid invite response packet!");
|
||||
return;
|
||||
@ -7452,7 +7360,7 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
||||
|
||||
//change guild and rank
|
||||
|
||||
uint32 guildrank = gj->response;
|
||||
guildrank = gj->response;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
@ -12145,6 +12053,10 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
||||
mp->quantity = prevcharges;
|
||||
}
|
||||
|
||||
// Item's stackable, but the quantity they want to buy exceeds the max stackable quantity.
|
||||
if (item->Stackable && mp->quantity > item->StackSize)
|
||||
mp->quantity = item->StackSize;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct));
|
||||
Merchant_Sell_Struct* mpo = (Merchant_Sell_Struct*)outapp->pBuffer;
|
||||
mpo->quantity = mp->quantity;
|
||||
@ -12171,6 +12083,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
||||
mpo->price = SinglePrice;
|
||||
else
|
||||
mpo->price = SinglePrice * mp->quantity;
|
||||
|
||||
if (mpo->price < 0)
|
||||
{
|
||||
safe_delete(outapp);
|
||||
@ -12640,6 +12553,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
else if (sa->type == AT_Anim) {
|
||||
if (IsAIControlled())
|
||||
return;
|
||||
|
||||
if (sa->parameter == ANIM_STAND) {
|
||||
SetAppearance(eaStanding);
|
||||
playeraction = 0;
|
||||
@ -12673,15 +12587,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 +12595,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 +12620,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 +12643,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 +12655,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 +12664,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
|
||||
|
||||
@ -239,7 +239,8 @@ bool Client::Process() {
|
||||
if(IsAIControlled())
|
||||
AI_Process();
|
||||
|
||||
if (bindwound_timer.Check() && bindwound_target != 0) {
|
||||
// Don't reset the bindwound timer so we can check it in BindWound as well.
|
||||
if (bindwound_timer.Check(false) && bindwound_target != 0) {
|
||||
BindWound(bindwound_target, false);
|
||||
}
|
||||
|
||||
@ -260,6 +261,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:
|
||||
|
||||
@ -2614,7 +2614,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);
|
||||
@ -4280,31 +4280,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)
|
||||
|
||||
@ -136,7 +136,8 @@ enum {
|
||||
ALLOW_TO_TANK = 41,
|
||||
IGNORE_ROOT_AGGRO_RULES = 42,
|
||||
CASTING_RESIST_DIFF = 43,
|
||||
MAX_SPECIAL_ATTACK = 44
|
||||
COUNTER_AVOID_DAMAGE = 44,
|
||||
MAX_SPECIAL_ATTACK = 45
|
||||
};
|
||||
|
||||
typedef enum { //fear states
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -449,11 +449,11 @@ void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) {
|
||||
newbon->DSMitigation += item->DSMitigation;
|
||||
}
|
||||
if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true);
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
}
|
||||
|
||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true);
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0);
|
||||
}
|
||||
|
||||
switch(item->BardType)
|
||||
|
||||
@ -170,6 +170,7 @@ Mob::Mob(const char* in_name,
|
||||
findable = false;
|
||||
trackable = true;
|
||||
has_shieldequiped = false;
|
||||
has_twohandbluntequiped = false;
|
||||
has_numhits = false;
|
||||
has_MGB = false;
|
||||
has_ProjectIllusion = false;
|
||||
|
||||
@ -194,7 +194,7 @@ public:
|
||||
bool IsBeneficialAllowed(Mob *target);
|
||||
virtual int GetCasterLevel(uint16 spell_id);
|
||||
void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0,
|
||||
bool item_bonus = false, bool IsWornEffect = false, uint32 ticsremaining = 0, int buffslot = -1,
|
||||
uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1,
|
||||
bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0);
|
||||
void NegateSpellsBonuses(uint16 spell_id);
|
||||
virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false);
|
||||
@ -308,7 +308,9 @@ public:
|
||||
void SetTargetable(bool on);
|
||||
bool IsTargetable() const { return m_targetable; }
|
||||
bool HasShieldEquiped() const { return has_shieldequiped; }
|
||||
inline void ShieldEquiped(bool val) { has_shieldequiped = val; }
|
||||
inline void SetShieldEquiped(bool val) { has_shieldequiped = val; }
|
||||
bool HasTwoHandBluntEquiped() const { return has_twohandbluntequiped; }
|
||||
inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; }
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; }
|
||||
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
||||
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
@ -1150,6 +1152,7 @@ protected:
|
||||
uint16 viral_spells[MAX_SPELL_TRIGGER*2]; // Stores the spell ids of the viruses on target and caster ids
|
||||
bool offhand;
|
||||
bool has_shieldequiped;
|
||||
bool has_twohandbluntequiped;
|
||||
bool has_numhits;
|
||||
bool has_MGB;
|
||||
bool has_ProjectIllusion;
|
||||
|
||||
@ -2559,7 +2559,7 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
||||
|
||||
for(int i=0; i < AIspellsEffects.size(); i++)
|
||||
{
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, false, 0,-1,
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1,
|
||||
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||
}
|
||||
|
||||
|
||||
@ -297,7 +297,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id)
|
||||
}
|
||||
}
|
||||
|
||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0);
|
||||
database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), 0);
|
||||
found_spawn->SetCurrentNPCID(npcid);
|
||||
|
||||
auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading());
|
||||
@ -2388,7 +2388,7 @@ void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
database.UpdateSpawn2Timeleft(id, 0, (newTime/1000));
|
||||
database.UpdateRespawnTime(id, 0, (newTime/1000));
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements())
|
||||
|
||||
105
zone/spawn2.cpp
105
zone/spawn2.cpp
@ -214,9 +214,6 @@ bool Spawn2::Process() {
|
||||
if(IsDespawned)
|
||||
return true;
|
||||
|
||||
if(spawn2_id)
|
||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0);
|
||||
|
||||
currentnpcid = npcid;
|
||||
NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3);
|
||||
|
||||
@ -348,7 +345,7 @@ void Spawn2::DeathReset(bool realdeath)
|
||||
//if we have a valid spawn id
|
||||
if(spawn2_id)
|
||||
{
|
||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), (cur/1000));
|
||||
database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), (cur/1000));
|
||||
Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn reset by death, repop in %d ms", spawn2_id, timer.GetRemainingTime());
|
||||
//store it to database too
|
||||
}
|
||||
@ -356,28 +353,92 @@ void Spawn2::DeathReset(bool realdeath)
|
||||
|
||||
bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {
|
||||
|
||||
std::unordered_map<uint32, uint32> spawn_times;
|
||||
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
std::string spawn_query = StringFormat(
|
||||
"SELECT "
|
||||
"respawn_times.id, "
|
||||
"respawn_times.`start`, "
|
||||
"respawn_times.duration "
|
||||
"FROM "
|
||||
"respawn_times "
|
||||
"WHERE instance_id = %u",
|
||||
zone->GetInstanceID()
|
||||
);
|
||||
auto results = QueryDatabase(spawn_query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0;
|
||||
uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0;
|
||||
|
||||
/* Our current time was expired */
|
||||
if ((start_duration + end_duration) <= tv.tv_sec) {
|
||||
spawn_times[atoi(row[0])] = 0;
|
||||
}
|
||||
/* We still have time left on this timer */
|
||||
else {
|
||||
spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
const char *zone_name = database.GetZoneName(zoneid);
|
||||
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
|
||||
"respawntime, variance, pathgrid, _condition, "
|
||||
"cond_value, enabled, animation FROM spawn2 "
|
||||
"WHERE zone = '%s' AND version = %u",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"id, "
|
||||
"spawngroupID, "
|
||||
"x, "
|
||||
"y, "
|
||||
"z, "
|
||||
"heading, "
|
||||
"respawntime, "
|
||||
"variance, "
|
||||
"pathgrid, "
|
||||
"_condition, "
|
||||
"cond_value, "
|
||||
"enabled, "
|
||||
"animation "
|
||||
"FROM "
|
||||
"spawn2 "
|
||||
"WHERE zone = '%s' AND version = %u",
|
||||
zone_name,
|
||||
version
|
||||
);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Spawn2* newSpawn = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1? true: false;
|
||||
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
|
||||
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
|
||||
atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]),
|
||||
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
uint32 spawn_time_left = 0;
|
||||
Spawn2* new_spawn = 0;
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
|
||||
spawn2_list.Insert(newSpawn);
|
||||
}
|
||||
if (spawn_times.count(atoi(row[0])) != 0)
|
||||
spawn_time_left = spawn_times[atoi(row[0])];
|
||||
|
||||
new_spawn = new Spawn2( //
|
||||
atoi(row[0]), // uint32 in_spawn2_id
|
||||
atoi(row[1]), // uint32 spawngroup_id
|
||||
atof(row[2]), // float in_x
|
||||
atof(row[3]), // float in_y
|
||||
atof(row[4]), // float in_z
|
||||
atof(row[5]), // float in_heading
|
||||
atoi(row[6]), // uint32 respawn
|
||||
atoi(row[7]), // uint32 variance
|
||||
spawn_time_left, // uint32 timeleft
|
||||
atoi(row[8]), // uint32 grid
|
||||
atoi(row[9]), // uint16 in_cond_id
|
||||
atoi(row[10]), // int16 in_min_value
|
||||
perl_enabled, // bool in_enabled
|
||||
(EmuAppearance)atoi(row[12]) // EmuAppearance anim
|
||||
);
|
||||
|
||||
spawn2_list.Insert(new_spawn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -427,8 +488,6 @@ bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* z
|
||||
if (results.RowsAffected() != 1)
|
||||
return false;
|
||||
|
||||
if(client)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -931,6 +931,9 @@ bool Zone::Init(bool iStaticZone) {
|
||||
Log.Out(Logs::General, Logs::Error, "Loading World Objects failed. continuing.");
|
||||
}
|
||||
|
||||
Log.Out(Logs::General, Logs::Status, "Flushing old respawn timers...");
|
||||
database.QueryDatabase("DELETE FROM `respawn_times` WHERE (`start` + `duration`) < UNIX_TIMESTAMP(NOW())");
|
||||
|
||||
//load up the zone's doors (prints inside)
|
||||
zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion());
|
||||
zone->LoadBlockedSpells(zone->GetZoneID());
|
||||
|
||||
@ -185,30 +185,40 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct
|
||||
return true;
|
||||
}
|
||||
|
||||
//updates or clears the respawn time in the database for the current spawn id
|
||||
void ZoneDatabase::UpdateSpawn2Timeleft(uint32 id, uint16 instance_id, uint32 timeleft)
|
||||
void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint32 time_left)
|
||||
{
|
||||
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
uint32 cur = tv.tv_sec;
|
||||
uint32 current_time = tv.tv_sec;
|
||||
|
||||
//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);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
/* If we pass timeleft as 0 that means we clear from respawn time
|
||||
otherwise we update with a REPLACE INTO
|
||||
*/
|
||||
|
||||
if(time_left == 0) {
|
||||
std::string query = StringFormat("DELETE FROM `respawn_times` WHERE `id` = %u AND `instance_id` = %u", spawn2_id, instance_id);
|
||||
QueryDatabase(query);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string query = StringFormat("REPLACE INTO respawn_times (id, start, duration, instance_id) "
|
||||
"VALUES (%lu, %lu, %lu, %lu)",
|
||||
(unsigned long)id, (unsigned long)cur,
|
||||
(unsigned long)timeleft, (unsigned long)instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `respawn_times` "
|
||||
"(id, "
|
||||
"start, "
|
||||
"duration, "
|
||||
"instance_id) "
|
||||
"VALUES "
|
||||
"(%u, "
|
||||
"%u, "
|
||||
"%u, "
|
||||
"%u)",
|
||||
spawn2_id,
|
||||
current_time,
|
||||
time_left,
|
||||
instance_id
|
||||
);
|
||||
QueryDatabase(query);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -3246,7 +3256,7 @@ bool ZoneDatabase::LoadFactionData()
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
max_faction = atoi(row[0]);
|
||||
max_faction = row[0] ? atoi(row[0]) : 0;
|
||||
faction_array = new Faction*[max_faction+1];
|
||||
for(unsigned int index=0; index<max_faction; index++)
|
||||
faction_array[index] = nullptr;
|
||||
|
||||
@ -365,7 +365,7 @@ public:
|
||||
bool PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay = 0);
|
||||
Spawn2* LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft);
|
||||
bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value);
|
||||
void UpdateSpawn2Timeleft(uint32 id, uint16 instance_id,uint32 timeleft);
|
||||
void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft);
|
||||
uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id);
|
||||
void UpdateSpawn2Status(uint32 id, uint8 new_status);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user