Conflicts:
	common/eqemu_logsys.h
This commit is contained in:
Akkadius 2015-02-01 15:56:05 -06:00
commit f9ba99e99f
53 changed files with 366 additions and 302 deletions

View File

@ -1,5 +1,8 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 01/31/2015 ==
Trevius: Fixed FindGroundZ() and GetGroundZ() to once again utilize the X and Y arguments that are passed to them.
== 01/30/2015 ==
Akkadius: Implemented event type "EVENT_ENVIRONMENTAL_DAMAGE"
- This event triggers when taking any sort of environmental damage. Example use:

View File

@ -107,9 +107,9 @@ public:
/* General Information Queries */
bool AddBannedIP(char* bannedIP, const char* notes); //Lieka Edit: Add IP address to the Banned_IPs table.
bool AddBannedIP(char* bannedIP, const char* notes); //Add IP address to the Banned_IPs table.
bool AddGMIP(char* ip_address, char* name);
bool CheckBannedIPs(const char* loginIP); //Lieka Edit: Check incoming connection against banned IP table.
bool CheckBannedIPs(const char* loginIP); //Check incoming connection against banned IP table.
bool CheckGMIPs(const char* loginIP, uint32 account_id);
bool CheckNameFilter(const char* name, bool surname = false);
bool CheckUsedName(const char* name);
@ -118,7 +118,7 @@ public:
uint32 GetAccountIDByChar(uint32 char_id);
uint32 GetAccountIDByName(const char* accname, int16* status = 0, uint32* lsid = 0);
uint32 GetCharacterID(const char *name);
uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0,float* oX = 0, float* oY = 0, float* oZ = 0);
uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0);
uint32 GetGuildIDByCharID(uint32 char_id);
void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0);

View File

@ -368,7 +368,7 @@ enum {
#define AT_DamageState 44 // The damage state of a destructible object (0 through 4)
//#define AT_Trader 300 // Bazzar Trader Mode
// solar: animations for AT_Anim
// animations for AT_Anim
#define ANIM_FREEZE 102
#define ANIM_STAND 0x64
#define ANIM_SIT 0x6e

View File

@ -540,7 +540,7 @@ struct SpawnAppearance_Struct
};
// solar: this is used inside profile
// this is used inside profile
struct SpellBuff_Struct
{
/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise
@ -1268,7 +1268,7 @@ struct Animation_Struct {
/*04*/
};
// solar: this is what causes the caster to animate and the target to
// this is what causes the caster to animate and the target to
// get the particle effects around them when a spell is cast
// also causes a buff icon
struct Action_Struct
@ -1292,7 +1292,7 @@ struct Action_Struct
/* 31 */
};
// solar: this is what prints the You have been struck. and the regular
// this is what prints the You have been struck. and the regular
// melee messages like You try to pierce, etc. It's basically the melee
// and spell damage message
struct CombatDamage_Struct
@ -1811,7 +1811,7 @@ struct RandomReq_Struct {
uint32 high;
};
/* solar: 9/23/03 reply to /random command; struct from Zaphod */
/* 9/23/03 reply to /random command */
struct RandomReply_Struct {
/* 00 */ uint32 low;
/* 04 */ uint32 high;

View File

@ -72,7 +72,7 @@ namespace Console {
LightRed = 12,
LightMagenta = 13,
Yellow = 14,
White = 15,
White = 15
};
}
@ -174,7 +174,7 @@ void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const
process_log << time_stamp << " " << message << std::endl;
}
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category){
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category) {
switch (log_category) {
case Logs::Status:
case Logs::Normal:
@ -197,7 +197,7 @@ uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category){
}
}
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category){
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category) {
switch (log_category) {
case Logs::Status:
case Logs::Normal:
@ -220,7 +220,7 @@ std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category){
}
}
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category){
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category) {
switch (log_category) {
case Logs::Status:
case Logs::Normal:
@ -317,7 +317,7 @@ void EQEmuLogSys::MakeDirectory(const std::string &directory_name)
void EQEmuLogSys::CloseFileLogs()
{
if (process_log.is_open()){
if (process_log.is_open()) {
process_log.close();
}
}

View File

@ -26,11 +26,11 @@
#include "types.h"
namespace Logs{
namespace Logs {
enum DebugLevel {
General = 1, /* 1 - Low-Level general debugging, useful info on single line */
Moderate, /* 2 - Informational based, used in functions, when particular things load */
Detail, /* 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication */
Detail /* 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication */
};
/*
@ -124,6 +124,7 @@ namespace Logs{
"MySQL Query",
"Mercenaries",
"Quest Debug",
"Quest Debug"
"Packet :: Server -> Client",
"Packet :: Client -> Server Unhandled",
};
@ -160,7 +161,7 @@ public:
log_to_gmsay[category_id] = [1-3] - Sets debug level for category to output to gmsay
*/
struct LogSettings{
struct LogSettings {
uint8 log_to_file;
uint8 log_to_console;
uint8 log_to_gmsay;

View File

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

View File

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

View File

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

View File

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

View File

@ -1394,7 +1394,7 @@ struct Animation_Struct {
/*04*/
};
// solar: this is what causes the caster to animate and the target to
// this is what causes the caster to animate and the target to
// get the particle effects around them when a spell is cast
// also causes a buff icon
struct Action_Struct
@ -1445,7 +1445,7 @@ struct ActionAlt_Struct
/*56*/
};
// solar: this is what prints the You have been struck. and the regular
// this is what prints the You have been struck. and the regular
// melee messages like You try to pierce, etc. It's basically the melee
// and spell damage message
struct CombatDamage_Struct
@ -1997,7 +1997,7 @@ struct RandomReq_Struct {
uint32 high;
};
/* solar: 9/23/03 reply to /random command; struct from Zaphod */
/* 9/23/03 reply to /random command */
struct RandomReply_Struct {
/* 00 */ uint32 low;
/* 04 */ uint32 high;

View File

@ -1425,7 +1425,7 @@ struct Animation_Struct {
/*04*/
};
// solar: this is what causes the caster to animate and the target to
// this is what causes the caster to animate and the target to
// get the particle effects around them when a spell is cast
// also causes a buff icon
struct Action_Struct
@ -1476,7 +1476,7 @@ struct ActionAlt_Struct
/*56*/
};
// solar: this is what prints the You have been struck. and the regular
// this is what prints the You have been struck. and the regular
// melee messages like You try to pierce, etc. It's basically the melee
// and spell damage message
struct CombatDamage_Struct
@ -2028,7 +2028,7 @@ struct RandomReq_Struct {
uint32 high;
};
/* solar: 9/23/03 reply to /random command; struct from Zaphod */
/* 9/23/03 reply to /random command */
struct RandomReply_Struct {
/* 00 */ uint32 low;
/* 04 */ uint32 high;

View File

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

View File

@ -538,7 +538,7 @@ struct SpawnAppearance_Struct
};
// solar: this is used inside profile
// this is used inside profile
struct SpellBuff_Struct
{
/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise
@ -1196,7 +1196,7 @@ struct Animation_Struct {
/*04*/
};
// solar: this is what causes the caster to animate and the target to
// this is what causes the caster to animate and the target to
// get the particle effects around them when a spell is cast
// also causes a buff icon
struct Action_Struct
@ -1248,7 +1248,7 @@ struct ActionAlt_Struct // ActionAlt_Struct - Size: 56 bytes
/*0056*/
};
// solar: this is what prints the You have been struck. and the regular
// this is what prints the You have been struck. and the regular
// melee messages like You try to pierce, etc. It's basically the melee
// and spell damage message
struct CombatDamage_Struct
@ -1791,7 +1791,7 @@ struct RandomReq_Struct {
uint32 high;
};
/* solar: 9/23/03 reply to /random command; struct from Zaphod */
/* 9/23/03 reply to /random command */
struct RandomReply_Struct {
/* 00 */ uint32 low;
/* 04 */ uint32 high;

View File

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

View File

@ -515,7 +515,7 @@ struct SpawnAppearance_Struct
};
// solar: this is used inside profile
// this is used inside profile
struct SpellBuff_Struct
{
/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise
@ -1172,7 +1172,7 @@ struct Animation_Struct {
/*04*/
};
// solar: this is what causes the caster to animate and the target to
// this is what causes the caster to animate and the target to
// get the particle effects around them when a spell is cast
// also causes a buff icon
struct Action_Struct
@ -1224,7 +1224,7 @@ struct ActionAlt_Struct // ActionAlt_Struct - Size: 56 bytes
/*0056*/
};
// solar: this is what prints the You have been struck. and the regular
// this is what prints the You have been struck. and the regular
// melee messages like You try to pierce, etc. It's basically the melee
// and spell damage message
struct CombatDamage_Struct
@ -1768,7 +1768,7 @@ struct RandomReq_Struct {
uint32 high;
};
/* solar: 9/23/03 reply to /random command; struct from Zaphod */
/* 9/23/03 reply to /random command */
struct RandomReply_Struct {
/* 00 */ uint32 low;
/* 04 */ uint32 high;

View File

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

View File

@ -438,7 +438,7 @@ struct SpawnAppearance_Struct
};
// solar: this is used inside profile
// this is used inside profile
struct SpellBuff_Struct
{
/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise
@ -1054,7 +1054,7 @@ struct Animation_Struct {
/*04*/
};
// solar: this is what causes the caster to animate and the target to
// this is what causes the caster to animate and the target to
// get the particle effects around them when a spell is cast
// also causes a buff icon
struct Action_Struct
@ -1078,7 +1078,7 @@ struct Action_Struct
/* 31 */
};
// solar: this is what prints the You have been struck. and the regular
// this is what prints the You have been struck. and the regular
// melee messages like You try to pierce, etc. It's basically the melee
// and spell damage message
struct CombatDamage_Struct
@ -1516,7 +1516,7 @@ struct RandomReq_Struct {
uint32 high;
};
/* solar: 9/23/03 reply to /random command; struct from Zaphod */
/* 9/23/03 reply to /random command */
struct RandomReply_Struct {
/* 00 */ uint32 low;
/* 04 */ uint32 high;

View File

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

View File

@ -1250,7 +1250,7 @@ struct Animation_Struct {
/*04*/
};
// solar: this is what causes the caster to animate and the target to
// this is what causes the caster to animate and the target to
// get the particle effects around them when a spell is cast
// also causes a buff icon
struct Action_Struct
@ -1305,7 +1305,7 @@ struct ActionAlt_Struct
/*64*/
};
// solar: this is what prints the You have been struck. and the regular
// this is what prints the You have been struck. and the regular
// melee messages like You try to pierce, etc. It's basically the melee
// and spell damage message
struct CombatDamage_Struct
@ -1849,7 +1849,7 @@ struct RandomReq_Struct {
uint32 high;
};
/* solar: 9/23/03 reply to /random command; struct from Zaphod */
/* 9/23/03 reply to /random command */
struct RandomReply_Struct {
/* 00 */ uint32 low;
/* 04 */ uint32 high;

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@
/*
solar: General outline of spell casting process
General outline of spell casting process
1.
a) Client clicks a spell bar gem, ability, or item. client_process.cpp

View File

@ -618,7 +618,7 @@ typedef enum {
#define DF_Permanent 50
// solar: note this struct is historical, we don't actually need it to be
// note this struct is historical, we don't actually need it to be
// aligned to anything, but for maintaining it it is kept in the order that
// the fields in the text file are. the numbering is not offset, but field
// number. note that the id field is counted as 0, this way the numbers

View File

@ -255,7 +255,7 @@ bool atobool(const char* iBool) {
return false;
}
// solar: removes the crap and turns the underscores into spaces.
// removes the crap and turns the underscores into spaces.
char *CleanMobName(const char *in, char *out)
{
unsigned i, j;
@ -414,4 +414,4 @@ void find_replace(std::string& string_subject, std::string& search_string, std::
string_subject.replace(index, index + 1, replace_string);
index = string_subject.find_first_of(search_string);
}
}
}

View File

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

View File

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

View File

@ -1 +1 @@
INSERT INTO `logsys_categories` (`log_category_id`, `log_category_description`, `log_to_gmsay`) VALUES ('38', 'Quest Debug', '1')
INSERT INTO `logsys_categories` (`log_category_id`, `log_category_description`, `log_to_gmsay`) VALUES ('38', 'Quest Debug', '1');

View File

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

View File

@ -1616,7 +1616,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
int Charerrors = 0;
// solar: if this is increased you'll have to add a column to the classrace
// if this is increased you'll have to add a column to the classrace
// table below
#define _TABLE_RACES 16
@ -1678,7 +1678,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
{ /*Enchanter*/ true, false, true, false, true, true, false, false, false, false, false, true, false, false, false, true},
{ /*Beastlord*/ false, true, false, false, false, false, false, false, true, true, false, false, true, true, false, false},
{ /*Berserker*/ false, true, false, false, false, false, false, true, true, true, false, false, false, true, false, false}
};//Initial table by kathgar, editted by Wiz for accuracy, solar too
};
if (!cc)
return false;
@ -1711,7 +1711,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
return false;
}
// solar: add up the base values for this class/race
// add up the base values for this class/race
// this is what they start with, and they have stat_points more
// that can distributed
bSTR = BaseClass[classtemp][0] + BaseRace[racetemp][0];
@ -1725,7 +1725,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
bTOTAL = bSTR + bSTA + bAGI + bDEX + bWIS + bINT + bCHA;
cTOTAL = cc->STR + cc->STA + cc->AGI + cc->DEX + cc->WIS + cc->INT + cc->CHA;
// solar: the first check makes sure the total is exactly what was expected.
// the first check makes sure the total is exactly what was expected.
// this will catch all the stat cheating, but there's still the issue
// of reducing CHA or INT or something, to use for STR, so we check
// that none are lower than the base or higher than base + stat_points

View File

@ -32,7 +32,7 @@ extern std::vector<RaceClassAllocation> character_create_allocations;
extern std::vector<RaceClassCombos> character_create_race_class_combos;
// solar: the current stuff is at the bottom of this function
// the current stuff is at the bottom of this function
void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* cs, uint32 ClientVersion) {
Inventory *inv;
uint8 has_home = 0;

View File

@ -665,7 +665,7 @@ bool ZoneServer::Process() {
}
case ServerOP_ZoneToZoneRequest: {
//
// solar: ZoneChange is received by the zone the player is in, then the
// ZoneChange is received by the zone the player is in, then the
// zone sends a ZTZ which ends up here. This code then find the target
// (ingress point) and boots it if needed, then sends the ZTZ to it.
// The ingress server will decide wether the player can enter, then will

View File

@ -481,7 +481,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
}
/*
solar: returns false if attack should not be allowed
returns false if attack should not be allowed
I try to list every type of conflict that's possible here, so it's easy
to see how the decision is made. Yea, it could be condensed and made
faster, but I'm doing it this way to make it readable and easy to modify
@ -550,7 +550,7 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
}
}
// solar: the format here is a matrix of mob type vs mob type.
// the format here is a matrix of mob type vs mob type.
// redundant ones are omitted and the reverse is tried if it falls through.
// first figure out if we're pets. we always look at the master's flags.
@ -701,7 +701,7 @@ type', in which case, the answer is yes.
}
// solar: this is to check if non detrimental things are allowed to be done
// this is to check if non detrimental things are allowed to be done
// to the target. clients cannot affect npcs and vice versa, and clients
// cannot affect other clients that are not of the same pvp flag as them.
// also goes for their pets
@ -717,7 +717,7 @@ bool Mob::IsBeneficialAllowed(Mob *target)
if (target->GetAllowBeneficial())
return true;
// solar: see IsAttackAllowed for notes
// see IsAttackAllowed for notes
// first figure out if we're pets. we always look at the master's flags.
// no need to compare pets to anything

View File

@ -343,7 +343,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
{
/* solar: called when a mob is attacked, does the checks to see if it's a hit
/* called when a mob is attacked, does the checks to see if it's a hit
* and does other mitigation checks. 'this' is the mob being attacked.
*
* special return values:
@ -1378,7 +1378,7 @@ void Client::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes att
if(spell_id==0)
spell_id = SPELL_UNKNOWN;
// cut all PVP spell damage to 2/3 -solar
// cut all PVP spell damage to 2/3
// Blasting ourselfs is considered PvP
//Don't do PvP mitigation if the caster is damaging himself
if(other && other->IsClient() && (other != this) && damage > 0) {
@ -2545,7 +2545,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
}
// solar: this is called from Damage() when 'this' is attacked by 'other.
// this is called from Damage() when 'this' is attacked by 'other.
// 'this' is the one being attacked
// 'other' is the attacker
// a damage shield causes damage (or healing) to whoever attacks the wearer

View File

@ -18,7 +18,7 @@
/*
solar: Beacon class, extends Mob. Used for AE rain spells to have a mob
Beacon class, extends Mob. Used for AE rain spells to have a mob
target to center around.
*/
@ -48,7 +48,7 @@ class Zone;
extern EntityList entity_list;
extern Zone* zone;
// solar: if lifetime is 0 this is a permanent beacon.. not sure if that'll be
// if lifetime is 0 this is a permanent beacon.. not sure if that'll be
// useful for anything
Beacon::Beacon(Mob *at_mob, int lifetime)
:Mob

View File

@ -7406,7 +7406,7 @@ float Bot::GetProcChances(float ProcBonus, uint16 hand) {
bool Bot::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
{
/* solar: called when a mob is attacked, does the checks to see if it's a hit
/* called when a mob is attacked, does the checks to see if it's a hit
* and does other mitigation checks. 'this' is the mob being attacked.
*
* special return values:
@ -7781,7 +7781,7 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) {
if (bIsBehind || bCanFrontalBS){ // Bot is behind other OR can do Frontal Backstab
// solar - chance to assassinate
// chance to assassinate
int chance = 10 + (GetDEX()/10) + (itembonuses.HeroicDEX/10); //18.5% chance at 85 dex 40% chance at 300 dex
if(
level >= 60 && // bot is 60 or higher

View File

@ -416,15 +416,6 @@ int Client::HandlePacket(const EQApplicationPacket *app)
std::cout << "Received 0x" << std::hex << std::setw(4) << std::setfill('0') << opcode << ", size=" << std::dec << app->size << std::endl;
#endif
#ifdef SOLAR
if(0 && opcode != OP_ClientUpdate)
{
Log.LogDebug(Logs::General,"HandlePacket() OPCODE debug enabled client %s", GetName());
std::cerr << "OPCODE: " << std::hex << std::setw(4) << std::setfill('0') << opcode << std::dec << ", size: " << app->size << std::endl;
DumpPacket(app);
}
#endif
switch(client_state) {
case CLIENT_CONNECTING: {
if(ConnectingOpcodes.count(opcode) != 1) {
@ -1395,6 +1386,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (RuleB(Character, SharedBankPlat))
m_pp.platinum_shared = database.GetSharedPlatinum(this->AccountID());
database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */

View File

@ -960,6 +960,9 @@ void Client::BulkSendInventoryItems()
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
const Item_Struct* handyitem = nullptr;
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
if (ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items
numItemSlots = 200;
}
const Item_Struct *item;
std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
std::list<MerchantList>::const_iterator itr;

View File

@ -7,7 +7,7 @@
#define HIGHEST_RESIST 9 //Max resist type value
#define MAX_SPELL_PROJECTILE 10 //Max amount of spell projectiles that can be active by a single mob.
/* solar: macros for IsAttackAllowed, IsBeneficialAllowed */
/* macros for IsAttackAllowed, IsBeneficialAllowed */
#define _CLIENT(x) (x && x->IsClient() && !x->CastToClient()->IsBecomeNPC())
#define _NPC(x) (x && x->IsNPC() && !x->CastToMob()->GetOwnerID())
#define _BECOMENPC(x) (x && x->IsClient() && x->CastToClient()->IsBecomeNPC())

View File

@ -318,7 +318,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
// get their tints
memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint));
// solar: TODO soulbound items need not be added to corpse, but they need
// TODO soulbound items need not be added to corpse, but they need
// to go into the regular slots on the player, out of bags
std::list<uint32> removed_list;
@ -965,6 +965,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
Save();
}
auto timestamps = database.GetItemRecastTimestamps(client->CharacterID());
outapp->priority = 6;
client->QueuePacket(outapp);
safe_delete(outapp);
@ -973,6 +974,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
const Item_Struct* item = database.GetItem(pkitem);
ItemInst* inst = database.CreateItem(item, item->MaxCharges);
if(inst) {
if (item->RecastDelay)
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
client->SendItemPacket(EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot);
safe_delete(inst);
}
@ -1004,6 +1007,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
if(client && item) {
ItemInst* inst = database.CreateItem(item, item_data->charges, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned);
if(inst) {
if (item->RecastDelay)
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
// MainGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = MainGeneral1 + MainCursor
client->SendItemPacket(i + EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot);
safe_delete(inst);
@ -1460,4 +1465,4 @@ void Corpse::LoadPlayerCorpseDecayTime(uint32 corpse_db_id){
else {
corpse_graveyard_timer.SetTimer(3000);
}
}
}

View File

@ -684,7 +684,7 @@ void EntityList::AETaunt(Client* taunter, float range)
}
}
// solar: causes caster to hit every mob within dist range of center with
// causes caster to hit every mob within dist range of center with
// spell_id.
// NPC spells will only affect other NPCs with compatible faction
void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust)
@ -820,7 +820,7 @@ void EntityList::MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool a
}
}
// solar: causes caster to hit every mob within dist range of center with
// causes caster to hit every mob within dist range of center with
// a bard pulse of spell_id.
// NPC spells will only affect other NPCs with compatible faction
void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster)

View File

@ -879,7 +879,7 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI
if(bag_item_data) { // bag contents
int16 interior_slot;
// solar: our bag went into slot_id, now let's pack the contents in
// our bag went into slot_id, now let's pack the contents in
for(int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) {
if(bag_item_data[i] == nullptr)
continue;
@ -993,7 +993,7 @@ bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_curs
return false;
}
// solar: helper function for AutoPutLootInInventory
// helper function for AutoPutLootInInventory
void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
{
ItemInst *tmp_inst = m_inv.GetItem(to_slot);

View File

@ -35,14 +35,13 @@
#include "zone.h"
#include "lua_parser.h"
const char *LuaEvents[_LargestEventID] = {
const char *LuaEvents[_LargestEventID] = {
"event_say",
"event_trade",
"event_death",
"event_spawn",
"event_attack",
"event_combat",
"event_environmental_damage",
"event_aggro",
"event_slay",
"event_npc_slay",
@ -68,6 +67,7 @@ const char *LuaEvents[_LargestEventID] = {
"event_aggro_say",
"event_player_pickup",
"event_popup_response",
"event_environmental_damage",
"event_proximity_say",
"event_cast",
"event_cast_begin",

View File

@ -2792,7 +2792,7 @@ void Mob::Say(const char *format, ...)
}
//
// solar: this is like the above, but the first parameter is a string id
// this is like the above, but the first parameter is a string id
//
void Mob::Say_StringID(uint32 string_id, const char *message3, const char *message4, const char *message5, const char *message6, const char *message7, const char *message8, const char *message9)
{
@ -3092,8 +3092,8 @@ float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
if (zone->zonemap != nullptr)
{
glm::vec3 me;
me.x = m_Position.x;
me.y = m_Position.y;
me.x = new_x;
me.y = new_y;
me.z = m_Position.z + z_offset;
glm::vec3 hit;
float best_z = zone->zonemap->FindBestZ(me, &hit);
@ -3112,8 +3112,8 @@ float Mob::GetGroundZ(float new_x, float new_y, float z_offset)
if (zone->zonemap != 0)
{
glm::vec3 me;
me.x = m_Position.x;
me.y = m_Position.y;
me.x = new_x;
me.y = new_y;
me.z = m_Position.z+z_offset;
glm::vec3 hit;
float best_z = zone->zonemap->FindBestZ(me, &hit);

View File

@ -123,7 +123,7 @@ public:
//Attack
virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10);
virtual void RogueAssassinate(Mob* other); // solar
virtual void RogueAssassinate(Mob* other);
float MobAngle(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const;
// greater than 90 is behind
inline bool BehindMob(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const

View File

@ -987,298 +987,267 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
}
}
uint32 ZoneDatabase::CreateNewNPCCommand(const char* zone, uint32 zone_version,Client *client, NPC* spawn, uint32 extra) {
uint32 ZoneDatabase::CreateNewNPCCommand(const char *zone, uint32 zone_version, Client *client, NPC *spawn,
uint32 extra)
{
uint32 npc_type_id = 0;
uint32 npc_type_id = 0;
if (extra && client && client->GetZoneID())
{
if (extra && client && client->GetZoneID()) {
// Set an npc_type ID within the standard range for the current zone if possible (zone_id * 1000)
int starting_npc_id = client->GetZoneID() * 1000;
std::string query = StringFormat("SELECT MAX(id) FROM npc_types WHERE id >= %i AND id < %i",
starting_npc_id, starting_npc_id + 1000);
auto results = QueryDatabase(query);
starting_npc_id, starting_npc_id + 1000);
auto results = QueryDatabase(query);
if (results.Success()) {
if (results.RowCount() != 0)
{
auto row = results.begin();
npc_type_id = atoi(row[0]) + 1;
// Prevent the npc_type id from exceeding the range for this zone
if (npc_type_id >= (starting_npc_id + 1000))
npc_type_id = 0;
}
else // No npc_type IDs set in this range yet
npc_type_id = starting_npc_id;
}
}
if (results.RowCount() != 0) {
auto row = results.begin();
npc_type_id = atoi(row[0]) + 1;
// Prevent the npc_type id from exceeding the range for this zone
if (npc_type_id >= (starting_npc_id + 1000))
npc_type_id = 0;
} else // No npc_type IDs set in this range yet
npc_type_id = starting_npc_id;
}
}
char tmpstr[64];
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
std::string query;
if (npc_type_id)
{
query = StringFormat("INSERT INTO npc_types (id, name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (npc_type_id) {
query = StringFormat("INSERT INTO npc_types (id, name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
npc_type_id = results.LastInsertedID();
} else {
query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(),
spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(),
spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
npc_type_id = results.LastInsertedID();
}
else
{
query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
npc_type_id = results.LastInsertedID();
}
if(client)
query = StringFormat("INSERT INTO spawngroup (id, name) VALUES(%i, '%s-%s')", 0, zone, spawn->GetName());
auto results = QueryDatabase(query);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
uint32 spawngroupid = results.LastInsertedID();
uint32 spawngroupid = results.LastInsertedID();
if(client)
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200,
spawn->GetHeading(), spawngroupid);
results = QueryDatabase(query);
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200, spawn->GetHeading(),
spawngroupid);
results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
if(client)
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
spawngroupid, npc_type_id, 100);
results = QueryDatabase(query);
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)", spawngroupid,
npc_type_id, 100);
results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
if(client)
return true;
}
uint32 ZoneDatabase::AddNewNPCSpawnGroupCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 respawnTime) {
uint32 last_insert_id = 0;
uint32 ZoneDatabase::AddNewNPCSpawnGroupCommand(const char *zone, uint32 zone_version, Client *client, NPC *spawn,
uint32 respawnTime)
{
uint32 last_insert_id = 0;
std::string query = StringFormat("INSERT INTO spawngroup (name) VALUES('%s%s%i')",
zone, spawn->GetName(), Timer::GetCurrentTime());
auto results = QueryDatabase(query);
std::string query = StringFormat("INSERT INTO spawngroup (name) VALUES('%s%s%i')", zone, spawn->GetName(),
Timer::GetCurrentTime());
auto results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
last_insert_id = results.LastInsertedID();
last_insert_id = results.LastInsertedID();
uint32 respawntime = 0;
uint32 spawnid = 0;
if (respawnTime)
respawntime = respawnTime;
else if(spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
respawntime = spawn->respawn2->RespawnTimer();
else
respawntime = 1200;
uint32 respawntime = 0;
uint32 spawnid = 0;
if (respawnTime)
respawntime = respawnTime;
else if (spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
respawntime = spawn->respawn2->RespawnTimer();
else
respawntime = 1200;
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime,
spawn->GetHeading(), last_insert_id);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
spawnid = results.LastInsertedID();
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime,
spawn->GetHeading(), last_insert_id);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
spawnid = results.LastInsertedID();
if(client)
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)", last_insert_id,
spawn->GetNPCTypeID(), 100);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
last_insert_id, spawn->GetNPCTypeID(), 100);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
if(client)
return spawnid;
return spawnid;
}
uint32 ZoneDatabase::UpdateNPCTypeAppearance(Client *client, NPC* spawn) {
std::string query = StringFormat("UPDATE npc_types SET name = \"%s\", level = %i, race = %i, class = %i, "
"hp = %i, gender = %i, texture = %i, helmtexture = %i, size = %i, "
"loottable_id = %i, merchant_id = %i, face = %i, WHERE id = %i",
spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, spawn->GetNPCTypeID());
auto results = QueryDatabase(query);
if (!results.Success() && client)
return results.Success() == true? 1: 0;
uint32 ZoneDatabase::UpdateNPCTypeAppearance(Client *client, NPC *spawn)
{
std::string query =
StringFormat("UPDATE npc_types SET name = \"%s\", level = %i, race = %i, class = %i, "
"hp = %i, gender = %i, texture = %i, helmtexture = %i, size = %i, "
"loottable_id = %i, merchant_id = %i, face = %i, WHERE id = %i",
spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(),
spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(),
spawn->GetLoottableID(), spawn->MerchantType, spawn->GetNPCTypeID());
auto results = QueryDatabase(query);
return results.Success() == true ? 1 : 0;
}
uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const char* zone, Client *client, NPC* spawn) {
uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const char *zone, Client *client, NPC *spawn)
{
uint32 id = 0;
uint32 spawngroupID = 0;
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE "
"zone='%s' AND spawngroupID=%i", zone, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
"zone='%s' AND spawngroupID=%i",
zone, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
if (row[0])
id = atoi(row[0]);
id = atoi(row[0]);
if (row[1])
spawngroupID = atoi(row[1]);
spawngroupID = atoi(row[1]);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
results = QueryDatabase(query);
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
results = QueryDatabase(query);
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
return 1;
}
uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char* zone, uint32 zone_version, Client *client, NPC* spawn) {
uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char *zone, uint32 zone_version, Client *client,
NPC *spawn)
{
uint32 id = 0;
uint32 spawngroupID = 0;
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE zone = '%s' "
"AND version = %u AND spawngroupID = %i",
zone, zone_version, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
"AND version = %u AND spawngroupID = %i",
zone, zone_version, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
if (row[0])
id = atoi(row[0]);
id = atoi(row[0]);
if (row[1])
spawngroupID = atoi(row[1]);
spawngroupID = atoi(row[1]);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM npc_types WHERE id = '%i'", spawn->GetNPCTypeID());
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM npc_types WHERE id = '%i'", spawn->GetNPCTypeID());
results = QueryDatabase(query);
if (!results.Success())
return 0;
return 1;
}
uint32 ZoneDatabase::AddSpawnFromSpawnGroup(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
uint32 ZoneDatabase::AddSpawnFromSpawnGroup(const char *zone, uint32 zone_version, Client *client, NPC *spawn,
uint32 spawnGroupID)
{
uint32 last_insert_id = 0;
std::string query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, client->GetX(), client->GetY(), client->GetZ(),
120, client->GetHeading(), spawnGroupID);
auto results = QueryDatabase(query);
if (!results.Success())
std::string query =
StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, client->GetX(), client->GetY(), client->GetZ(), 120, client->GetHeading(),
spawnGroupID);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
return 1;
return 1;
}
uint32 ZoneDatabase::AddNPCTypes(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
uint32 npc_type_id;
uint32 ZoneDatabase::AddNPCTypes(const char *zone, uint32 zone_version, Client *client, NPC *spawn, uint32 spawnGroupID)
{
uint32 npc_type_id;
char numberlessName[64];
EntityList::RemoveNumbers(strn0cpy(numberlessName, spawn->GetName(), sizeof(numberlessName)));
std::string query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
numberlessName, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
std::string query =
StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
numberlessName, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(),
spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(),
spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
npc_type_id = results.LastInsertedID();
npc_type_id = results.LastInsertedID();
if(client)
if(client)
client->Message(0, "%s npc_type ID %i created successfully!", numberlessName, npc_type_id);
if (client)
client->Message(0, "%s npc_type ID %i created successfully!", numberlessName, npc_type_id);
return 1;
}

View File

@ -467,16 +467,21 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
if (m_inst && sender) {
// if there is a lore conflict, delete the offending item from the server inventory
// the client updates itself and takes care of sending "duplicate lore item" messages
if(sender->CheckLoreConflict(m_inst->GetItem())) {
int16 loreslot = sender->GetInv().HasItem(m_inst->GetItem()->ID, 0, invWhereBank);
auto item = m_inst->GetItem();
if(sender->CheckLoreConflict(item)) {
int16 loreslot = sender->GetInv().HasItem(item->ID, 0, invWhereBank);
if (loreslot != INVALID_INDEX) // if the duplicate is in the bank, delete it.
sender->DeleteItemInInventory(loreslot);
else
cursordelete = true; // otherwise, we delete the new one
}
if (item->RecastDelay)
m_inst->SetRecastTimestamp(
database.GetItemRecastTimestamp(sender->CharacterID(), item->RecastType));
char buf[10];
snprintf(buf, 9, "%u", m_inst->GetItem()->ID);
snprintf(buf, 9, "%u", item->ID);
buf[9] = '\0';
std::vector<EQEmu::Any> args;
args.push_back(m_inst);

View File

@ -663,7 +663,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
DoAnim(animPiercing);
}
// solar - assassinate [Kayen: No longer used for regular assassinate 6-29-14]
// assassinate [No longer used for regular assassinate 6-29-14]
void Mob::RogueAssassinate(Mob* other)
{
//can you dodge, parry, etc.. an assassinate??

View File

@ -1242,6 +1242,8 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
{
//Can we start the timer here? I don't see why not.
CastToClient()->GetPTimers().Start((pTimerItemStart + recasttype), recastdelay);
database.UpdateItemRecastTimestamps(CastToClient()->CharacterID(), recasttype,
CastToClient()->GetPTimers().Get(pTimerItemStart + recasttype)->GetReadyTimestamp());
}
}
@ -2023,6 +2025,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
//
// Switch #2 - execute the spell
//
switch(CastAction)
{
default:
@ -2146,6 +2149,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
// caster if they're not using TGB
// NOTE: this will always hit the caster, plus the target's group so
// it can affect up to 7 people if the targeted group is not our own
// Allow pets who cast group spells to affect the group.
if (spell_target->IsPetOwnerClient()){
Mob* owner = spell_target->GetOwner();
if (owner)
spell_target = owner;
}
if(spell_target->IsGrouped())
{
Group *target_group = entity_list.GetGroupByMob(spell_target);
@ -2270,11 +2282,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
{
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
if(itm && itm->GetItem()->RecastDelay > 0){
CastToClient()->GetPTimers().Start((pTimerItemStart + itm->GetItem()->RecastType), itm->GetItem()->RecastDelay);
auto recast_type = itm->GetItem()->RecastType;
CastToClient()->GetPTimers().Start((pTimerItemStart + recast_type), itm->GetItem()->RecastDelay);
database.UpdateItemRecastTimestamps(
CastToClient()->CharacterID(), recast_type,
CastToClient()->GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp());
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
ird->recast_delay = itm->GetItem()->RecastDelay;
ird->recast_type = itm->GetItem()->RecastType;
ird->recast_type = recast_type;
CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}

View File

@ -647,7 +647,7 @@ void WorldServer::Process() {
case ServerOP_Petition: {
std::cout << "Got Server Requested Petition List Refresh" << std::endl;
ServerPetitionUpdate_Struct* sus = (ServerPetitionUpdate_Struct*) pack->pBuffer;
// solar: this was typoed to = instead of ==, not that it acts any different now though..
// this was typoed to = instead of ==, not that it acts any different now though..
if (sus->status == 0) petition_list.ReadDatabase();
else if (sus->status == 1) petition_list.ReadDatabase(); // Until I fix this to be better....
break;

View File

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

View File

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