mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-28 13:01:31 +00:00
Merge from master
This commit is contained in:
commit
7fd3cc3483
@ -1,5 +1,30 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 02/05/2015 ==
|
||||
Trevius: Fixed Environmental Damage for RoF2.
|
||||
|
||||
== 02/03/2015 ==
|
||||
Trevius: Crashfix for TempName() when numbers are passed at the end of the name.
|
||||
Uleat: Tweaking of item type exclusions to alleviate strobing conditions with light sources
|
||||
|
||||
== 02/02/2015 ==
|
||||
Akkadius: Implement Packet logs with dumps
|
||||
- Category: 41: Packet: Server -> Client With Dump
|
||||
- Category: 42: Packet: Server -> Client With Dump
|
||||
See: http://wiki.eqemulator.org/p?Logging_System_Overhaul#packet-logging-levels
|
||||
|
||||
== 02/01/2015 ==
|
||||
demonstar55: Add quest debugging to lua
|
||||
eq.debug("Test debug level implicit 1")
|
||||
eq.debug("Test debug level explicit 1", 1)
|
||||
eq.debug("Test debug level explicit 2", 2)
|
||||
eq.debug("Test debug level explicit 3", 3)
|
||||
Akkadius: Add Packet Logging Categories
|
||||
- 5 - Packet: Client -> Server - Logs::Client_Server_Packet
|
||||
- 39 - Packet: Server -> Client - Logs::Server_Client_Packet
|
||||
- 40 - Packet: Client -> Server Unhandled - Logs::Client_Server_Packet_Unhandled
|
||||
See: http://wiki.eqemulator.org/p?Logging_System_Overhaul#packet-logging
|
||||
|
||||
== 01/31/2015 ==
|
||||
Trevius: Fixed FindGroundZ() and GetGroundZ() to once again utilize the X and Y arguments that are passed to them.
|
||||
|
||||
|
||||
@ -1984,7 +1984,7 @@ void Database::GetRaidLeadershipInfo(uint32 rid, char *maintank,
|
||||
|
||||
void Database::SetRaidGroupLeaderInfo(uint32 gid, uint32 rid)
|
||||
{
|
||||
std::string query = StringFormat("UPDATE raid_leaders SET leadershipaa = '', WHERE gid = %lu AND rid = %lu",
|
||||
std::string query = StringFormat("UPDATE raid_leaders SET leadershipaa = '' WHERE gid = %lu AND rid = %lu",
|
||||
(unsigned long)gid, (unsigned long)rid);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -2154,6 +2154,16 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings)
|
||||
log_settings[log_category].log_to_file = atoi(row[3]);
|
||||
log_settings[log_category].log_to_gmsay = atoi(row[4]);
|
||||
|
||||
/* Determine if any output method is enabled for the category
|
||||
and set it to 1 so it can used to check if category is enabled */
|
||||
const bool log_to_console = log_settings[log_category].log_to_console > 0;
|
||||
const bool log_to_file = log_settings[log_category].log_to_file > 0;
|
||||
const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
|
||||
|
||||
if (is_category_enabled)
|
||||
log_settings[log_category].is_category_enabled = 1;
|
||||
|
||||
/*
|
||||
This determines whether or not the process needs to actually file log anything.
|
||||
If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open
|
||||
@ -2162,4 +2172,4 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings)
|
||||
Log.file_logs_enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,8 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo
|
||||
|
||||
/* Implement Logging at the Root */
|
||||
if (mysql_errno(&mysql) > 0 && strlen(query) > 0){
|
||||
Log.Out(Logs::General, Logs::MySQLError, "%i: %s \n %s", mysql_errno(&mysql), mysql_error(&mysql), query);
|
||||
if (Log.log_settings[Logs::MySQLError].is_category_enabled == 1)
|
||||
Log.Out(Logs::General, Logs::MySQLError, "%i: %s \n %s", mysql_errno(&mysql), mysql_error(&mysql), query);
|
||||
}
|
||||
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql),errorBuffer);
|
||||
@ -125,8 +126,9 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo
|
||||
rowCount = (uint32)mysql_num_rows(res);
|
||||
|
||||
MySQLRequestResult requestResult(res, (uint32)mysql_affected_rows(&mysql), rowCount, (uint32)mysql_field_count(&mysql), (uint32)mysql_insert_id(&mysql));
|
||||
|
||||
Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u rows returned)", query, rowCount, requestResult.RowCount());
|
||||
|
||||
if (Log.log_settings[Logs::MySQLQuery].is_category_enabled == 1)
|
||||
Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u rows returned)", query, rowCount, requestResult.RowCount());
|
||||
|
||||
return requestResult;
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "platform.h"
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef STATIC_OPCODE
|
||||
@ -440,3 +441,8 @@ void DumpPacket(const EQApplicationPacket* app, bool iShowInfo) {
|
||||
DumpPacketHex(app->pBuffer, app->size);
|
||||
}
|
||||
|
||||
std::string DumpPacketToString(const EQApplicationPacket* app){
|
||||
std::ostringstream out;
|
||||
out << DumpPacketHexToString(app->pBuffer, app->size);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
#include "base_packet.h"
|
||||
#include "platform.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef STATIC_OPCODE
|
||||
typedef unsigned short EmuOpcode;
|
||||
@ -146,6 +147,6 @@ protected:
|
||||
};
|
||||
|
||||
extern void DumpPacket(const EQApplicationPacket* app, bool iShowInfo = false);
|
||||
|
||||
extern std::string DumpPacketToString(const EQApplicationPacket* app);
|
||||
|
||||
#endif
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "op_codes.h"
|
||||
#include "crc16.h"
|
||||
#include "platform.h"
|
||||
#include "string_util.h"
|
||||
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
@ -555,9 +556,21 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
|
||||
|
||||
void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
|
||||
{
|
||||
uint32 chunksize,used;
|
||||
uint32 chunksize, used;
|
||||
uint32 length;
|
||||
|
||||
if (Log.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){
|
||||
if (p->GetOpcode() != OP_SpecialMesg){
|
||||
Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.log_settings[Logs::Server_Client_Packet_With_Dump].is_category_enabled == 1){
|
||||
if (p->GetOpcode() != OP_SpecialMesg){
|
||||
Log.Out(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets
|
||||
if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2)
|
||||
Log.Out(Logs::Detail, Logs::Netcode, _L "Making oversized packet, len %d" __L, p->size);
|
||||
@ -951,14 +964,12 @@ EQApplicationPacket *EQStream::PopPacket()
|
||||
}
|
||||
MInboundQueue.unlock();
|
||||
|
||||
//resolve the opcode if we can.
|
||||
if(p) {
|
||||
if(OpMgr != nullptr && *OpMgr != nullptr) {
|
||||
if (p) {
|
||||
if (OpMgr != nullptr && *OpMgr != nullptr) {
|
||||
EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode);
|
||||
if (emu_op == OP_Unknown) {
|
||||
Log.Out(Logs::General, Logs::Netcode, "[ERROR] Unable to convert EQ opcode 0x%.4x to an Application opcode.", p->opcode);
|
||||
}
|
||||
|
||||
// Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "Unknown :: [%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->opcode, p->Size(), DumpPacketToString(p).c_str());
|
||||
}
|
||||
p->SetOpcode(emu_op);
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::st
|
||||
|
||||
if (log_to_console) EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message);
|
||||
if (log_to_gmsay) EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message);
|
||||
if (log_to_file) EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_message);
|
||||
if (log_to_file) EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message);
|
||||
}
|
||||
|
||||
void EQEmuLogSys::SetCurrentTimeStamp(char* time_stamp)
|
||||
|
||||
@ -80,6 +80,10 @@ namespace Logs {
|
||||
MySQLQuery,
|
||||
Mercenaries,
|
||||
QuestDebug,
|
||||
Server_Client_Packet,
|
||||
Client_Server_Packet_Unhandled,
|
||||
Server_Client_Packet_With_Dump,
|
||||
Client_Server_Packet_With_Dump,
|
||||
MaxCategoryID /* Don't Remove this*/
|
||||
};
|
||||
|
||||
@ -90,7 +94,7 @@ namespace Logs {
|
||||
"AI",
|
||||
"Aggro",
|
||||
"Attack",
|
||||
"Client Server Packet",
|
||||
"Packet :: Client -> Server",
|
||||
"Combat",
|
||||
"Commands",
|
||||
"Crash",
|
||||
@ -125,7 +129,11 @@ namespace Logs {
|
||||
"MySQLError",
|
||||
"MySQLQuery",
|
||||
"Mercenaries",
|
||||
"QuestDebug"
|
||||
"Quest Debug",
|
||||
"Packet :: Server -> Client",
|
||||
"Packet :: Client -> Server Unhandled",
|
||||
"Packet :: Server -> Client (Dump)",
|
||||
"Packet :: Client -> Server (Dump)",
|
||||
};
|
||||
}
|
||||
|
||||
@ -164,6 +172,7 @@ public:
|
||||
uint8 log_to_file;
|
||||
uint8 log_to_console;
|
||||
uint8 log_to_gmsay;
|
||||
uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */
|
||||
};
|
||||
|
||||
/* Internally used memory reference for all log settings per category.
|
||||
|
||||
@ -1011,7 +1011,8 @@ uint8 Inventory::FindHighestLightValue()
|
||||
if (inst == nullptr) { continue; }
|
||||
auto item = inst->GetItem();
|
||||
if (item == nullptr) { continue; }
|
||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
||||
// 'Gloomingdeep lantern' is ItemTypeArmor in the database..there may be others instances and/or types that need to be handled
|
||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight && item->ItemType != ItemTypeArmor) { continue; }
|
||||
if (item->Light & 0xF0) { continue; }
|
||||
if (item->Light > light_value) { light_value = item->Light; }
|
||||
}
|
||||
@ -1441,6 +1442,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 +1468,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 +1489,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 +1543,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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdio.h>
|
||||
|
||||
@ -89,6 +90,54 @@ void DumpPacketHex(const uchar* buf, uint32 size, uint32 cols, uint32 skip) {
|
||||
safe_delete_array(ascii);
|
||||
}
|
||||
|
||||
std::string DumpPacketHexToString(const uchar* buf, uint32 size, uint32 cols, uint32 skip) {
|
||||
std::ostringstream out;
|
||||
if (size == 0 || size > 39565)
|
||||
return "";
|
||||
|
||||
out << "\n";
|
||||
|
||||
// Output as HEX
|
||||
char output[4];
|
||||
int j = 0;
|
||||
char* ascii = new char[cols + 1];
|
||||
memset(ascii, 0, cols + 1);
|
||||
uint32 i;
|
||||
for (i = skip; i < size; i++)
|
||||
{
|
||||
if ((i - skip) % cols == 0) {
|
||||
if (i != skip)
|
||||
out << " | " << ascii << std::endl;
|
||||
out << std::setw(4) << std::setfill(' ') << i - skip << ": ";
|
||||
memset(ascii, 0, cols + 1);
|
||||
j = 0;
|
||||
}
|
||||
else if ((i - skip) % (cols / 2) == 0) {
|
||||
out << "- ";
|
||||
}
|
||||
sprintf(output, "%02X ", (unsigned char)buf[i]);
|
||||
out << output;
|
||||
|
||||
if (buf[i] >= 32 && buf[i] < 127) {
|
||||
ascii[j++] = buf[i];
|
||||
}
|
||||
else {
|
||||
ascii[j++] = '.';
|
||||
}
|
||||
// std::cout << std::setfill(0) << std::setw(2) << std::hex << (int)buf[i] << " "; // unknown intent [CODEBUG]
|
||||
}
|
||||
uint32 k = ((i - skip) - 1) % cols;
|
||||
if (k < 8)
|
||||
out << " ";
|
||||
for (uint32 h = k + 1; h < cols; h++) {
|
||||
out << " ";
|
||||
}
|
||||
out << " | " << ascii << std::endl;
|
||||
safe_delete_array(ascii);
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void DumpPacket(const uchar* buf, uint32 size)
|
||||
{
|
||||
DumpPacketHex(buf, size);
|
||||
|
||||
@ -24,6 +24,7 @@ class ServerPacket;
|
||||
|
||||
void DumpPacketAscii(const uchar* buf, uint32 size, uint32 cols=16, uint32 skip=0);
|
||||
void DumpPacketHex(const uchar* buf, uint32 size, uint32 cols=16, uint32 skip=0);
|
||||
std::string DumpPacketHexToString(const uchar* buf, uint32 size, uint32 cols = 16, uint32 skip = 0);
|
||||
void DumpPacketBin(const void* data, uint32 len);
|
||||
void DumpPacket(const uchar* buf, uint32 size);
|
||||
void DumpPacket(const ServerPacket* pack, bool iShowInfo = false);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -2865,7 +2865,7 @@ struct SetRunMode_Struct {
|
||||
};
|
||||
|
||||
// EnvDamage is EnvDamage2 without a few bytes at the end.
|
||||
// Size: 37 bytes
|
||||
// Size: 39 bytes
|
||||
struct EnvDamage2_Struct {
|
||||
/*0000*/ uint32 id;
|
||||
/*0004*/ uint16 unknown4;
|
||||
@ -2877,7 +2877,8 @@ struct EnvDamage2_Struct {
|
||||
/*0031*/ uint16 unknown31; // New to Underfoot - Seen 66
|
||||
/*0033*/ uint16 constant; // Always FFFF
|
||||
/*0035*/ uint16 unknown35;
|
||||
/*0037*/
|
||||
/*0037*/ uint16 unknown37;
|
||||
/*0039*/
|
||||
};
|
||||
|
||||
//Bazaar Stuff
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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; }
|
||||
|
||||
|
||||
@ -102,6 +102,7 @@ RULE_INT ( Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods,
|
||||
RULE_INT ( Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225.
|
||||
RULE_INT ( Character, OrnamentationAugmentType, 20) //Ornamentation Augment Type
|
||||
RULE_REAL(Character, EnvironmentDamageMulipliter, 1)
|
||||
RULE_BOOL(Character, UnmemSpellsOnDeath, true)
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY( Mercs )
|
||||
@ -328,6 +329,7 @@ RULE_BOOL ( Spells, Jun182014HundredHandsRevamp, false) // this should be true f
|
||||
RULE_BOOL ( Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning.
|
||||
RULE_BOOL ( Spells, NPC_UseFocusFromSpells, true) // Allow npcs to use most spell derived focus effects.
|
||||
RULE_BOOL ( Spells, NPC_UseFocusFromItems, false) // Allow npcs to use most item derived focus effects.
|
||||
RULE_BOOL ( Spells, UseAdditiveFocusFromWornSlot, false) // Allows an additive focus effect to be calculated from worn slot.
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY( Combat )
|
||||
|
||||
@ -498,6 +498,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto timestamps = GetItemRecastTimestamps(char_id);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int16 slot_id = atoi(row[0]);
|
||||
uint32 item_id = atoi(row[1]);
|
||||
@ -582,6 +584,13 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv)
|
||||
else
|
||||
inst->SetCharges(charges);
|
||||
|
||||
if (item->RecastDelay) {
|
||||
if (timestamps.count(item->RecastType))
|
||||
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
|
||||
else
|
||||
inst->SetRecastTimestamp(0);
|
||||
}
|
||||
|
||||
if (item->ItemClass == ItemClassCommon) {
|
||||
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
if (aug[i])
|
||||
@ -725,6 +734,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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
@ -71,7 +71,6 @@ const std::string StringFormat(const char* format, ...)
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
// normal strncpy doesnt put a null term on copied strings, this one does
|
||||
// ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp
|
||||
char* strn0cpy(char* dest, const char* source, uint32 size) {
|
||||
@ -408,3 +407,11 @@ bool isAlphaNumeric(const char *text)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string) {
|
||||
auto index = string_subject.find_first_of(search_string);
|
||||
while (index != std::string::npos) {
|
||||
string_subject.replace(index, index + 1, replace_string);
|
||||
index = string_subject.find_first_of(search_string);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,37 +23,34 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
const std::string vStringFormat(const char* format, va_list args);
|
||||
const std::string StringFormat(const char* format, ...);
|
||||
std::string EscapeString(const std::string &s);
|
||||
std::string EscapeString(const char *src, size_t sz);
|
||||
|
||||
const char *MakeLowerString(const char *source);
|
||||
|
||||
void MakeLowerString(const char *source, char *target);
|
||||
|
||||
int MakeAnyLenString(char** ret, const char* format, ...);
|
||||
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...);
|
||||
|
||||
uint32 hextoi(const char* num);
|
||||
uint64 hextoi64(const char* num);
|
||||
bool atobool(const char* iBool);
|
||||
|
||||
char* strn0cpy(char* dest, const char* source, uint32 size);
|
||||
// return value =true if entire string(source) fit, false if it was truncated
|
||||
bool isAlphaNumeric(const char *text);
|
||||
bool strn0cpyt(char* dest, const char* source, uint32 size);
|
||||
|
||||
char *CleanMobName(const char *in, char *out);
|
||||
char *RemoveApostrophes(const char *s);
|
||||
char* strn0cpy(char* dest, const char* source, uint32 size);
|
||||
|
||||
const char *ConvertArray(int input, char *returnchar);
|
||||
const char *ConvertArrayF(float input, char *returnchar);
|
||||
const char *MakeLowerString(const char *source);
|
||||
const std::string StringFormat(const char* format, ...);
|
||||
const std::string vStringFormat(const char* format, va_list args);
|
||||
|
||||
void RemoveApostrophes(std::string &s);
|
||||
char *RemoveApostrophes(const char *s);
|
||||
int MakeAnyLenString(char** ret, const char* format, ...);
|
||||
|
||||
std::string EscapeString(const char *src, size_t sz);
|
||||
std::string EscapeString(const std::string &s);
|
||||
|
||||
std::vector<std::string> SplitString(const std::string &s, char delim);
|
||||
|
||||
bool isAlphaNumeric(const char *text);
|
||||
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...);
|
||||
uint32 hextoi(const char* num);
|
||||
|
||||
uint64 hextoi64(const char* num);
|
||||
|
||||
void MakeLowerString(const char *source, char *target);
|
||||
void RemoveApostrophes(std::string &s);
|
||||
void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string);
|
||||
|
||||
#endif
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
#define LOGIN_VERSION "0.8.0"
|
||||
#define EQEMU_PROTOCOL_VERSION "0.3.10"
|
||||
|
||||
#define CURRENT_VERSION "1.0.0"
|
||||
#define CURRENT_VERSION "1.1.3"
|
||||
|
||||
/*
|
||||
Everytime a Database SQL is added to Github,
|
||||
@ -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 9076
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
#ifndef WIN32
|
||||
|
||||
@ -394,6 +394,16 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) {
|
||||
log_settings[log_category].log_to_file = atoi(row[3]);
|
||||
log_settings[log_category].log_to_gmsay = atoi(row[4]);
|
||||
|
||||
/* Determine if any output method is enabled for the category
|
||||
and set it to 1 so it can used to check if category is enabled */
|
||||
const bool log_to_console = log_settings[log_category].log_to_console > 0;
|
||||
const bool log_to_file = log_settings[log_category].log_to_file > 0;
|
||||
const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
|
||||
|
||||
if (is_category_enabled)
|
||||
log_settings[log_category].is_category_enabled = 1;
|
||||
|
||||
/*
|
||||
This determines whether or not the process needs to actually file log anything.
|
||||
If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open
|
||||
|
||||
@ -621,6 +621,16 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) {
|
||||
log_settings[log_category].log_to_file = atoi(row[3]);
|
||||
log_settings[log_category].log_to_gmsay = atoi(row[4]);
|
||||
|
||||
/* Determine if any output method is enabled for the category
|
||||
and set it to 1 so it can used to check if category is enabled */
|
||||
const bool log_to_console = log_settings[log_category].log_to_console > 0;
|
||||
const bool log_to_file = log_settings[log_category].log_to_file > 0;
|
||||
const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
|
||||
|
||||
if (is_category_enabled)
|
||||
log_settings[log_category].is_category_enabled = 1;
|
||||
|
||||
/*
|
||||
This determines whether or not the process needs to actually file log anything.
|
||||
If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open
|
||||
|
||||
@ -326,6 +326,10 @@
|
||||
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|
|
||||
9074|2015_02_01_logsys_packet_logs.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client'|empty|
|
||||
9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty|
|
||||
9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
50
utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql
Normal file
50
utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql
Normal file
@ -0,0 +1,50 @@
|
||||
-- Updates live pets who should be type (5) - Pet locks onto target until dead.
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_74_";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_67_";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumSword";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer4";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumHammer";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "Burnout";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumSword";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumHammer";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_67_";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk3";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk1";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk2";
|
||||
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk3";
|
||||
@ -0,0 +1 @@
|
||||
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:UseAdditiveFocusFromWornSlot', 'false', '[Not live like] If a focus effect is placed in a worn slot the base value will calculated as an additive bonus to regular focus effects.');
|
||||
@ -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;
|
||||
3
utils/sql/git/required/2015_02_01_logsys_packet_logs.sql
Normal file
3
utils/sql/git/required/2015_02_01_logsys_packet_logs.sql
Normal file
@ -0,0 +1,3 @@
|
||||
REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('39', 'Packet: Server -> Client');
|
||||
REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('5', 'Packet: Client -> Server');
|
||||
REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('40', 'Packet: Client -> Server Unhandled');
|
||||
@ -0,0 +1,2 @@
|
||||
REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('41', 'Packet: Server -> Client With Dump');
|
||||
REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('42', 'Packet: Server -> Client With Dump');
|
||||
2
utils/sql/git/required/2015_02_04_average_coin.sql
Normal file
2
utils/sql/git/required/2015_02_04_average_coin.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE `loottable` CHANGE COLUMN `avgcoin` `avgcoin` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `maxcash`;
|
||||
UPDATE `loottable` SET avgcoin = 0;
|
||||
@ -1584,10 +1584,12 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
|
||||
//this generates a lot of 'updates' to the client that the client does not need
|
||||
BuffFadeNonPersistDeath();
|
||||
if((GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover))
|
||||
UnmemSpellAll(true);
|
||||
else
|
||||
UnmemSpellAll(false);
|
||||
if (RuleB(Character, UnmemSpellsOnDeath)) {
|
||||
if((GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover))
|
||||
UnmemSpellAll(true);
|
||||
else
|
||||
UnmemSpellAll(false);
|
||||
}
|
||||
|
||||
if((RuleB(Character, LeaveCorpses) && GetLevel() >= RuleI(Character, DeathItemLossLevel)) || RuleB(Character, LeaveNakedCorpses))
|
||||
{
|
||||
|
||||
@ -411,11 +411,11 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
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, true, true);
|
||||
}
|
||||
|
||||
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, true, false);
|
||||
}
|
||||
|
||||
switch(item->BardType)
|
||||
@ -639,7 +639,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||
if (focus)
|
||||
{
|
||||
newbon->FocusEffects[focus] = effect;
|
||||
newbon->FocusEffects[focus] = static_cast<uint8>(effect);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1393,7 +1393,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, buffs[i].ticsremaining,i);
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, false, buffs[i].ticsremaining,i);
|
||||
|
||||
if (buffs[i].numhits > 0)
|
||||
Numhits(true);
|
||||
@ -1416,7 +1416,7 @@ 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, uint32 ticsremaining, int buffslot,
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, bool item_bonus, bool IsWornEffect, 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;
|
||||
@ -1439,7 +1439,12 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
uint8 focus = IsFocusEffect(spell_id, i);
|
||||
if (focus)
|
||||
{
|
||||
new_bonus->FocusEffects[focus] = spells[spell_id].effectid[i];
|
||||
if (!IsWornEffect)
|
||||
new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effectid[i]);
|
||||
|
||||
else if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
112
zone/client.cpp
112
zone/client.cpp
@ -7516,7 +7516,6 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui
|
||||
int32 npc_value[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8 temp[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
int32 current_value;
|
||||
bool change = false;
|
||||
|
||||
// Get the npc faction list
|
||||
if (!database.GetNPCFactionList(npc_id, faction_id, npc_value, temp))
|
||||
@ -7525,43 +7524,81 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui
|
||||
{
|
||||
int32 faction_before_hit;
|
||||
int32 faction_to_use_for_messaging;
|
||||
FactionMods fm;
|
||||
int32 this_faction_max;
|
||||
int32 this_faction_min;
|
||||
|
||||
if (faction_id[i] <= 0)
|
||||
continue;
|
||||
|
||||
// Find out starting faction for this faction
|
||||
// It needs to be used to adj max and min personal
|
||||
// The range is still the same, 1200-3000(4200), but adjusted for base
|
||||
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
|
||||
faction_id[i]);
|
||||
|
||||
// Adjust the amount you can go up or down so the resulting range
|
||||
// is PERSONAL_MAX - PERSONAL_MIN
|
||||
//
|
||||
// Adjust these values for cases where starting faction is below
|
||||
// min or above max by not allowing any earn in those directions.
|
||||
this_faction_min = MIN_PERSONAL_FACTION - fm.base;
|
||||
this_faction_min = std::min(0, this_faction_min);
|
||||
this_faction_max = MAX_PERSONAL_FACTION - fm.base;
|
||||
this_faction_max = std::max(0, this_faction_max);
|
||||
|
||||
// Get the characters current value with that faction
|
||||
current_value = GetCharacterFactionLevel(faction_id[i]);
|
||||
faction_before_hit = current_value;
|
||||
|
||||
change = UpdatePersonalFaction(char_id, npc_value[i], faction_id[i], ¤t_value, temp[i]);
|
||||
UpdatePersonalFaction(char_id, npc_value[i], faction_id[i], ¤t_value, temp[i], this_faction_min, this_faction_max);
|
||||
|
||||
if (change)
|
||||
{
|
||||
SendFactionMessage(npc_value[i], faction_id[i], faction_before_hit, current_value, temp[i]);
|
||||
}
|
||||
//Message(14, "Min(%d) Max(%d) Before(%d), After(%d)\n", this_faction_min, this_faction_max, faction_before_hit, current_value);
|
||||
|
||||
SendFactionMessage(npc_value[i], faction_id[i], faction_before_hit, current_value, temp[i], this_faction_min, this_faction_max);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp)
|
||||
{
|
||||
int32 current_value;
|
||||
bool change=false;
|
||||
|
||||
//Get the npc faction list
|
||||
if(faction_id > 0 && value != 0) {
|
||||
int32 faction_before_hit;
|
||||
FactionMods fm;
|
||||
int32 this_faction_max;
|
||||
int32 this_faction_min;
|
||||
|
||||
// Find out starting faction for this faction
|
||||
// It needs to be used to adj max and min personal
|
||||
// The range is still the same, 1200-3000(4200), but adjusted for base
|
||||
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
|
||||
faction_id);
|
||||
|
||||
// Adjust the amount you can go up or down so the resulting range
|
||||
// is PERSONAL_MAX - PERSONAL_MIN
|
||||
//
|
||||
// Adjust these values for cases where starting faction is below
|
||||
// min or above max by not allowing any earn/loss in those directions.
|
||||
// At least one faction starts out way below min, so we don't want
|
||||
// to allow loses in those cases, just massive gains.
|
||||
this_faction_min = MIN_PERSONAL_FACTION - fm.base;
|
||||
this_faction_min = std::min(0, this_faction_min);
|
||||
this_faction_max = MAX_PERSONAL_FACTION - fm.base;
|
||||
this_faction_max = std::max(0, this_faction_max);
|
||||
|
||||
//Get the faction modifiers
|
||||
current_value = GetCharacterFactionLevel(faction_id);
|
||||
faction_before_hit = current_value;
|
||||
|
||||
change = UpdatePersonalFaction(char_id, value, faction_id, ¤t_value, temp);
|
||||
UpdatePersonalFaction(char_id, value, faction_id, ¤t_value, temp, this_faction_min, this_faction_max);
|
||||
|
||||
if (change)
|
||||
{
|
||||
SendFactionMessage(value, faction_id, faction_before_hit, current_value, temp);
|
||||
}
|
||||
//Message(14, "Min(%d) Max(%d) Before(%d), After(%d)\n", this_faction_min, this_faction_max, faction_before_hit, current_value);
|
||||
|
||||
SendFactionMessage(value, faction_id, faction_before_hit, current_value, temp, this_faction_min, this_faction_max);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -7583,7 +7620,7 @@ int32 Client::GetCharacterFactionLevel(int32 faction_id)
|
||||
// Checks for bottom out and max faction and old faction db entries
|
||||
// Updates the faction if we are not minned, maxed or we need to repair
|
||||
|
||||
bool Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp)
|
||||
void Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max)
|
||||
{
|
||||
bool repair = false;
|
||||
bool change = false;
|
||||
@ -7601,33 +7638,38 @@ bool Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction
|
||||
npc_value *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Set flag when to update db
|
||||
if (*current_value > MAX_PERSONAL_FACTION)
|
||||
// Repair needed, as db changes could modify a base value for a faction
|
||||
// and we need to auto correct when that happens.
|
||||
if (*current_value > this_faction_max)
|
||||
{
|
||||
*current_value = MAX_PERSONAL_FACTION;
|
||||
*current_value = this_faction_max;
|
||||
repair = true;
|
||||
}
|
||||
else if (*current_value < MIN_PERSONAL_FACTION)
|
||||
else if (*current_value < this_faction_min)
|
||||
{
|
||||
*current_value = MIN_PERSONAL_FACTION;
|
||||
*current_value = this_faction_min;
|
||||
repair = true;
|
||||
}
|
||||
else if ((m_pp.gm != 1) && (npc_value != 0) && ((*current_value != MAX_PERSONAL_FACTION) || (*current_value != MIN_PERSONAL_FACTION)))
|
||||
else if ((m_pp.gm != 1) && (npc_value != 0) &&
|
||||
((npc_value > 0 && *current_value != this_faction_max) ||
|
||||
((npc_value < 0 && *current_value != this_faction_min))))
|
||||
change = true;
|
||||
|
||||
*current_value += npc_value;
|
||||
|
||||
if (*current_value > MAX_PERSONAL_FACTION)
|
||||
*current_value = MAX_PERSONAL_FACTION;
|
||||
else if (*current_value < MIN_PERSONAL_FACTION)
|
||||
*current_value = MIN_PERSONAL_FACTION;
|
||||
|
||||
if (change || repair)
|
||||
{
|
||||
*current_value += npc_value;
|
||||
|
||||
if (*current_value > this_faction_max)
|
||||
*current_value = this_faction_max;
|
||||
else if (*current_value < this_faction_min)
|
||||
*current_value = this_faction_min;
|
||||
|
||||
database.SetCharacterFactionLevel(char_id, faction_id, *current_value, temp, factionvalues);
|
||||
}
|
||||
|
||||
return (repair || change);
|
||||
return;
|
||||
}
|
||||
|
||||
// returns the character's faction level, adjusted for racial, class, and deity modifiers
|
||||
@ -7708,21 +7750,21 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction)
|
||||
//o--------------------------------------------------------------
|
||||
//| Purpose: Send faction change message to client
|
||||
//o--------------------------------------------------------------
|
||||
void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp)
|
||||
void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max)
|
||||
{
|
||||
char name[50];
|
||||
int32 faction_value;
|
||||
|
||||
// If we're dropping from MAX or raising from MIN, we should
|
||||
// base the message on the new updated value so we don't show
|
||||
// If we're dropping from MAX or raising from MIN or repairing,
|
||||
// we should base the message on the new updated value so we don't show
|
||||
// a min MAX message
|
||||
//
|
||||
// If we're changing any other place, we use the value before the
|
||||
// hit. For example, if we go from 1199 to 1200 which is the MAX
|
||||
// we still want to say faction got better this time around.
|
||||
|
||||
if ( (faction_before_hit == MAX_PERSONAL_FACTION) ||
|
||||
(faction_before_hit == MIN_PERSONAL_FACTION))
|
||||
if ( (faction_before_hit >= this_faction_max) ||
|
||||
(faction_before_hit <= this_faction_min))
|
||||
faction_value = totalvalue;
|
||||
else
|
||||
faction_value = faction_before_hit;
|
||||
@ -7733,13 +7775,13 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_
|
||||
|
||||
if (tmpvalue == 0 || temp == 1 || temp == 2)
|
||||
return;
|
||||
else if (faction_value >= MAX_PERSONAL_FACTION)
|
||||
else if (faction_value >= this_faction_max)
|
||||
Message_StringID(15, FACTION_BEST, name);
|
||||
else if (faction_value <= MIN_PERSONAL_FACTION)
|
||||
else if (faction_value <= this_faction_min)
|
||||
Message_StringID(15, FACTION_WORST, name);
|
||||
else if (tmpvalue > 0 && faction_value < MAX_PERSONAL_FACTION && !RuleB(Client, UseLiveFactionMessage))
|
||||
else if (tmpvalue > 0 && faction_value < this_faction_max && !RuleB(Client, UseLiveFactionMessage))
|
||||
Message_StringID(15, FACTION_BETTER, name);
|
||||
else if (tmpvalue < 0 && faction_value > MIN_PERSONAL_FACTION && !RuleB(Client, UseLiveFactionMessage))
|
||||
else if (tmpvalue < 0 && faction_value > this_faction_min && !RuleB(Client, UseLiveFactionMessage))
|
||||
Message_StringID(15, FACTION_WORSE, name);
|
||||
else if (RuleB(Client, UseLiveFactionMessage))
|
||||
Message(15, "Your faction standing with %s has been adjusted by %i.", name, tmpvalue); //New Live faction message (14261)
|
||||
|
||||
@ -607,9 +607,9 @@ public:
|
||||
int32 GetCharacterFactionLevel(int32 faction_id);
|
||||
int32 GetModCharacterFactionLevel(int32 faction_id);
|
||||
void MerchantRejectMessage(Mob *merchant, int primaryfaction);
|
||||
void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp);
|
||||
void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max);
|
||||
|
||||
bool UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp);
|
||||
void UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max);
|
||||
void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity);
|
||||
void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp);
|
||||
int32 GetRawItemAC();
|
||||
|
||||
@ -398,12 +398,18 @@ void ClearMappedOpcode(EmuOpcode op)
|
||||
// client methods
|
||||
int Client::HandlePacket(const EQApplicationPacket *app)
|
||||
{
|
||||
if(Log.log_settings[Logs::LogCategory::Netcode].log_to_console > 0) {
|
||||
if (Log.log_settings[Logs::LogCategory::Netcode].is_category_enabled == 1) {
|
||||
char buffer[64];
|
||||
app->build_header_dump(buffer);
|
||||
Log.Out(Logs::Detail, Logs::Client_Server_Packet, "Dispatch opcode: %s", buffer);
|
||||
}
|
||||
|
||||
if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1)
|
||||
Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size());
|
||||
|
||||
if (Log.log_settings[Logs::Client_Server_Packet_With_Dump].is_category_enabled == 1)
|
||||
Log.Out(Logs::General, Logs::Client_Server_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str());
|
||||
|
||||
EmuOpcode opcode = app->GetOpcode();
|
||||
if (opcode == OP_AckPacket) {
|
||||
return true;
|
||||
@ -445,23 +451,16 @@ int Client::HandlePacket(const EQApplicationPacket *app)
|
||||
case CLIENT_CONNECTED: {
|
||||
ClientPacketProc p;
|
||||
p = ConnectedOpcodes[opcode];
|
||||
if(p == nullptr) {
|
||||
if(p == nullptr) {
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(const_cast<EQApplicationPacket*>(app));
|
||||
parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args);
|
||||
|
||||
char buffer[64];
|
||||
Log.Out(Logs::Detail, Logs::Client_Server_Packet, "Unhandled incoming opcode: %s - 0x%04x", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode());
|
||||
if (Log.log_settings[Logs::Client_Server_Packet].log_to_console > 0){
|
||||
if (Log.log_settings[Logs::Client_Server_Packet_Unhandled].is_category_enabled == 1){
|
||||
char buffer[64];
|
||||
app->build_header_dump(buffer);
|
||||
if (app->size < 1000)
|
||||
DumpPacket(app, app->size);
|
||||
else{
|
||||
std::cout << "Dump limited to 1000 characters:\n";
|
||||
DumpPacket(app, 1000);
|
||||
}
|
||||
Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "%s %s", buffer, DumpPacketToString(app).c_str());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1392,6 +1391,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 */
|
||||
@ -5516,7 +5516,7 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
if (damage < 0)
|
||||
damage = 31337;
|
||||
|
||||
if (admin >= minStatusToAvoidFalling && GetGM()){
|
||||
if (admin >= minStatusToAvoidFalling && GetGM()) {
|
||||
Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
|
||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||
return;
|
||||
@ -5526,11 +5526,11 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||
return;
|
||||
}
|
||||
|
||||
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184){
|
||||
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184) {
|
||||
// Hard coded tutorial and load zones for no fall damage
|
||||
return;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter)));
|
||||
|
||||
/* EVENT_ENVIRONMENTAL_DAMAGE */
|
||||
@ -9862,6 +9862,9 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST))
|
||||
return;
|
||||
|
||||
if (mypet->GetPetType() == petAnimation && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST) && !GetAA(aaAnimationEmpathy))
|
||||
return;
|
||||
|
||||
|
||||
@ -10591,6 +10591,15 @@ void command_logs(Client *c, const Seperator *sep){
|
||||
c->Message(15, "Your Log Settings have been applied");
|
||||
c->Message(15, "Output Method: %s :: Debug Level: %i - Category: %s", sep->arg[2], atoi(sep->arg[4]), Logs::LogCategoryName[atoi(sep->arg[3])]);
|
||||
}
|
||||
/* We use a general 'is_category_enabled' now, let's update when we update any output settings
|
||||
This is used in hot places of code to check if its enabled in any way before triggering logs
|
||||
*/
|
||||
if (sep->arg[4] > 0){
|
||||
Log.log_settings[atoi(sep->arg[3])].is_category_enabled = 1;
|
||||
}
|
||||
else{
|
||||
Log.log_settings[atoi(sep->arg[3])].is_category_enabled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@ -350,7 +350,8 @@ struct StatBonuses {
|
||||
int32 CharmBreakChance; // chance to break charm
|
||||
int32 SongRange; // increases range of beneficial bard songs
|
||||
uint32 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
||||
uint32 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||
uint8 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||
int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot
|
||||
bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses)
|
||||
int32 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage
|
||||
uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit
|
||||
@ -505,7 +506,7 @@ typedef enum {
|
||||
petOther,
|
||||
petCharmed,
|
||||
petNPCFollow,
|
||||
petHatelist //remain active as long something is on the hatelist. Don't listen to any commands
|
||||
petTargetLock //remain active as long something is on the hatelist. Don't listen to any commands
|
||||
} PetType;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,9 +749,9 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
if (bad) {
|
||||
if (!caster->IsAttackAllowed(curmob, true))
|
||||
continue;
|
||||
if (center && !center->CheckLosFN(curmob))
|
||||
if (center && !spells[spell_id].npc_no_los && !center->CheckLosFN(curmob))
|
||||
continue;
|
||||
if (!center && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ(), curmob->GetSize()))
|
||||
if (!center && !spells[spell_id].npc_no_los && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ(), curmob->GetSize()))
|
||||
continue;
|
||||
} else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
|
||||
// This does not check faction for beneficial AE buffs..only agro and attackable.
|
||||
|
||||
@ -72,8 +72,8 @@ public:
|
||||
uint32 GetTotalGroupDamage(Mob* other);
|
||||
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; };
|
||||
char* GetLeaderName() { return membername[0]; };
|
||||
inline Mob* GetLeader() { return leader; };
|
||||
const char* GetLeaderName() { return leader->GetName(); };
|
||||
void SendHPPacketsTo(Mob* newmember);
|
||||
void SendHPPacketsFrom(Mob* newmember);
|
||||
bool UpdatePlayer(Mob* update);
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/loottable.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/data_verification.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
@ -35,7 +36,7 @@
|
||||
|
||||
// Queries the loottable: adds item & coin to the npc
|
||||
void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
|
||||
const LootTable_Struct* lts = 0;
|
||||
const LootTable_Struct* lts = nullptr;
|
||||
*copper = 0;
|
||||
*silver = 0;
|
||||
*gold = 0;
|
||||
@ -45,44 +46,39 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
||||
if (!lts)
|
||||
return;
|
||||
|
||||
// do coin
|
||||
if (lts->mincash > lts->maxcash) {
|
||||
std::cerr << "Error in loottable #" << loottable_id << ": mincash > maxcash" << std::endl;
|
||||
uint32 min_cash = lts->mincash;
|
||||
uint32 max_cash = lts->maxcash;
|
||||
if(min_cash > max_cash) {
|
||||
uint32 t = min_cash;
|
||||
min_cash = max_cash;
|
||||
max_cash = t;
|
||||
}
|
||||
else if (lts->maxcash != 0) {
|
||||
uint32 cash = 0;
|
||||
if (lts->mincash == lts->maxcash)
|
||||
cash = lts->mincash;
|
||||
else
|
||||
cash = zone->random.Int(lts->mincash, lts->maxcash);
|
||||
if (cash != 0) {
|
||||
if (lts->avgcoin != 0) {
|
||||
//this is some crazy ass stuff... and makes very little sense... dont use it, k?
|
||||
uint32 mincoin = (uint32) (lts->avgcoin * 0.75 + 1);
|
||||
uint32 maxcoin = (uint32) (lts->avgcoin * 1.25 + 1);
|
||||
*copper = zone->random.Int(mincoin, maxcoin);
|
||||
*silver = zone->random.Int(mincoin, maxcoin);
|
||||
*gold = zone->random.Int(mincoin, maxcoin);
|
||||
if(*copper > cash) { *copper = cash; }
|
||||
cash -= *copper;
|
||||
if(*silver>(cash/10)) { *silver = (cash/10); }
|
||||
cash -= *silver*10;
|
||||
if(*gold > (cash/100)) { *gold = (cash/100); }
|
||||
cash -= *gold*100;
|
||||
}
|
||||
if (cash < 0) {
|
||||
cash = 0;
|
||||
}
|
||||
*plat = cash / 1000;
|
||||
cash -= *plat * 1000;
|
||||
uint32 gold2 = cash / 100;
|
||||
cash -= gold2 * 100;
|
||||
uint32 silver2 = cash / 10;
|
||||
cash -= silver2 * 10;
|
||||
*gold += gold2;
|
||||
*silver += silver2;
|
||||
*copper += cash;
|
||||
|
||||
uint32 cash = 0;
|
||||
if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) {
|
||||
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash);
|
||||
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0);
|
||||
|
||||
if(avg_cash_roll < upper_chance) {
|
||||
cash = zone->random.Int(lts->avgcoin, max_cash);
|
||||
} else {
|
||||
cash = zone->random.Int(min_cash, lts->avgcoin);
|
||||
}
|
||||
} else {
|
||||
cash = zone->random.Int(min_cash, max_cash);
|
||||
}
|
||||
|
||||
if(cash != 0) {
|
||||
*plat = cash / 1000;
|
||||
cash -= *plat * 1000;
|
||||
|
||||
*gold = cash / 100;
|
||||
cash -= *gold * 100;
|
||||
|
||||
*silver = cash / 10;
|
||||
cash -= *silver * 10;
|
||||
|
||||
*copper = cash;
|
||||
}
|
||||
|
||||
// Do items
|
||||
@ -97,11 +93,11 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
||||
|
||||
float drop_chance = 0.0f;
|
||||
if(ltchance > 0.0 && ltchance < 100.0) {
|
||||
drop_chance = zone->random.Real(0.0, 100.0);
|
||||
drop_chance = (float)zone->random.Real(0.0, 100.0);
|
||||
}
|
||||
|
||||
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance < ltchance)) {
|
||||
AddLootDropToNPC(npc,lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop);
|
||||
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance <= ltchance)) {
|
||||
AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,63 +110,76 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml
|
||||
if (!lds) {
|
||||
return;
|
||||
}
|
||||
if(lds->NumEntries == 0) //nothing possible to add
|
||||
|
||||
if(lds->NumEntries == 0)
|
||||
return;
|
||||
|
||||
// Too long a list needs to be limited.
|
||||
if(lds->NumEntries > 99 && droplimit < 1)
|
||||
droplimit = lds->NumEntries/100;
|
||||
|
||||
uint8 limit = 0;
|
||||
// Start at a random point in itemlist.
|
||||
uint32 item = zone->random.Int(0, lds->NumEntries-1);
|
||||
// Main loop.
|
||||
for (uint32 i=0; i<lds->NumEntries;)
|
||||
{
|
||||
//Force the itemlist back to beginning.
|
||||
if (item > (lds->NumEntries-1))
|
||||
item = 0;
|
||||
|
||||
uint8 charges = lds->Entries[item].multiplier;
|
||||
uint8 pickedcharges = 0;
|
||||
// Loop to check multipliers.
|
||||
for (uint32 x=1; x<=charges; x++)
|
||||
{
|
||||
// Actual roll.
|
||||
float thischance = 0.0;
|
||||
thischance = lds->Entries[item].chance;
|
||||
|
||||
float drop_chance = 0.0;
|
||||
if(thischance != 100.0)
|
||||
drop_chance = zone->random.Real(0.0, 100.0);
|
||||
|
||||
#if EQDEBUG>=11
|
||||
Log.Out(Logs::General, Logs::None, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance);
|
||||
#endif
|
||||
if (thischance == 100.0 || drop_chance < thischance)
|
||||
{
|
||||
uint32 itemid = lds->Entries[item].item_id;
|
||||
|
||||
const Item_Struct* dbitem = GetItem(itemid);
|
||||
npc->AddLootDrop(dbitem, itemlist, lds->Entries[item].item_charges, lds->Entries[item].minlevel, lds->Entries[item].maxlevel, lds->Entries[item].equip_item, false);
|
||||
pickedcharges++;
|
||||
if(droplimit == 0 && mindrop == 0) {
|
||||
for(uint32 i = 0; i < lds->NumEntries; ++i) {
|
||||
int charges = lds->Entries[i].multiplier;
|
||||
for(int j = 0; j < charges; ++j) {
|
||||
if(zone->random.Real(0.0, 100.0) <= lds->Entries[i].chance) {
|
||||
const Item_Struct* dbitem = GetItem(lds->Entries[i].item_id);
|
||||
npc->AddLootDrop(dbitem, itemlist, lds->Entries[i].item_charges, lds->Entries[i].minlevel,
|
||||
lds->Entries[i].maxlevel, lds->Entries[i].equip_item > 0 ? true : false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Items with multipliers only count as 1 towards the limit.
|
||||
if(pickedcharges > 0)
|
||||
limit++;
|
||||
return;
|
||||
}
|
||||
|
||||
// If true, limit reached.
|
||||
if(limit >= droplimit && droplimit > 0)
|
||||
break;
|
||||
if(lds->NumEntries > 100 && droplimit == 0) {
|
||||
droplimit = 10;
|
||||
}
|
||||
|
||||
item++;
|
||||
i++;
|
||||
if(droplimit < mindrop) {
|
||||
droplimit = mindrop;
|
||||
}
|
||||
|
||||
// We didn't reach our minimium, run loop again.
|
||||
if(i == lds->NumEntries){
|
||||
if(limit < mindrop){
|
||||
i = 0;
|
||||
float roll_t = 0.0f;
|
||||
bool active_item_list = false;
|
||||
for(uint32 i = 0; i < lds->NumEntries; ++i) {
|
||||
const Item_Struct* db_item = GetItem(lds->Entries[i].item_id);
|
||||
if(db_item) {
|
||||
roll_t += lds->Entries[i].chance;
|
||||
active_item_list = true;
|
||||
}
|
||||
}
|
||||
|
||||
roll_t = EQEmu::ClampLower(roll_t, 100.0f);
|
||||
|
||||
if(!active_item_list) {
|
||||
return;
|
||||
}
|
||||
|
||||
mindrop = EQEmu::ClampLower(mindrop, (uint8)1);
|
||||
int item_count = zone->random.Int(mindrop, droplimit);
|
||||
for(int i = 0; i < item_count; ++i) {
|
||||
float roll = (float)zone->random.Real(0.0, roll_t);
|
||||
for(uint32 j = 0; j < lds->NumEntries; ++j) {
|
||||
const Item_Struct* db_item = GetItem(lds->Entries[j].item_id);
|
||||
if(db_item) {
|
||||
if(roll < lds->Entries[j].chance) {
|
||||
npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel,
|
||||
lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false);
|
||||
|
||||
int charges = (int)lds->Entries[i].multiplier;
|
||||
charges = EQEmu::ClampLower(charges, 1);
|
||||
|
||||
for(int k = 1; k < charges; ++k) {
|
||||
float c_roll = (float)zone->random.Real(0.0, 100.0);
|
||||
if(c_roll <= lds->Entries[i].chance) {
|
||||
npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel,
|
||||
lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false);
|
||||
}
|
||||
}
|
||||
|
||||
j = lds->NumEntries;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
roll -= lds->Entries[j].chance;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // We either ran out of items or reached our limit.
|
||||
@ -215,6 +224,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
|
||||
item->attuned = 0;
|
||||
item->min_level = minlevel;
|
||||
item->max_level = maxlevel;
|
||||
|
||||
if (equipit) {
|
||||
uint8 eslot = 0xFF;
|
||||
char newid[20];
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#include "questmgr.h"
|
||||
#include "qglobals.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
struct Events { };
|
||||
struct Factions { };
|
||||
@ -1221,7 +1222,6 @@ std::string lua_get_encounter() {
|
||||
return quest_manager.GetEncounter();
|
||||
}
|
||||
|
||||
|
||||
void lua_map_opcodes() {
|
||||
MapOpcodes();
|
||||
}
|
||||
@ -1249,6 +1249,17 @@ double lua_clock() {
|
||||
return static_cast<double>(t) / 1000.0;
|
||||
}
|
||||
|
||||
void lua_debug(std::string message) {
|
||||
Log.Out(Logs::General, Logs::QuestDebug, message);
|
||||
}
|
||||
|
||||
void lua_debug(std::string message, int level) {
|
||||
if (level < Logs::General || level > Logs::Detail)
|
||||
return;
|
||||
|
||||
Log.Out(static_cast<Logs::DebugLevel>(level), Logs::QuestDebug, message);
|
||||
}
|
||||
|
||||
#define LuaCreateNPCParse(name, c_type, default_value) do { \
|
||||
cur = table[#name]; \
|
||||
if(luabind::type(cur) != LUA_TNIL) { \
|
||||
@ -1582,7 +1593,9 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("disable_recipe", &lua_disable_recipe),
|
||||
luabind::def("clear_npctype_cache", &lua_clear_npctype_cache),
|
||||
luabind::def("clock", &lua_clock),
|
||||
luabind::def("create_npc", &lua_create_npc)
|
||||
luabind::def("create_npc", &lua_create_npc),
|
||||
luabind::def("debug", (void(*)(std::string))&lua_debug),
|
||||
luabind::def("debug", (void(*)(std::string, int))&lua_debug)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -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",
|
||||
|
||||
29
zone/mob.cpp
29
zone/mob.cpp
@ -300,6 +300,7 @@ Mob::Mob(const char* in_name,
|
||||
focused = false;
|
||||
_IsTempPet = false;
|
||||
pet_owner_client = false;
|
||||
pet_targetlock_id = 0;
|
||||
|
||||
attacked_count = 0;
|
||||
mezzed = false;
|
||||
@ -1981,9 +1982,10 @@ void Mob::TempName(const char *newname)
|
||||
strn0cpy(temp_name, GetCleanName(), 64);
|
||||
}
|
||||
|
||||
// Remove Numbers before making name unique
|
||||
EntityList::RemoveNumbers(temp_name);
|
||||
// Make the new name unique and set it
|
||||
strn0cpy(temp_name, entity_list.MakeNameUnique(temp_name), 64);
|
||||
|
||||
entity_list.MakeNameUnique(temp_name);
|
||||
|
||||
// Send the new name to all clients
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MobRename, sizeof(MobRename_Struct));
|
||||
@ -5362,3 +5364,26 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool Mob::CanClassEquipItem(uint32 item_id)
|
||||
{
|
||||
const Item_Struct* itm = nullptr;
|
||||
itm = database.GetItem(item_id);
|
||||
|
||||
if (!itm)
|
||||
return false;
|
||||
|
||||
if(itm->Classes == 65535 )
|
||||
return true;
|
||||
|
||||
if (GetClass() > 16)
|
||||
return false;
|
||||
|
||||
int bitmask = 1;
|
||||
bitmask = bitmask << (GetClass() - 1);
|
||||
|
||||
if(!(itm->Classes & bitmask))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -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, uint32 ticsremaining = 0, int buffslot = -1,
|
||||
bool item_bonus = false, bool IsWornEffect = false, 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);
|
||||
@ -315,6 +315,7 @@ public:
|
||||
virtual int32 GetHerosForgeModel(uint8 material_slot) const;
|
||||
virtual uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
virtual uint32 IsEliteMaterialItem(uint8 material_slot) const;
|
||||
bool CanClassEquipItem(uint32 item_id);
|
||||
bool AffectedBySpellExcludingSlot(int slot, int effect);
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) = 0;
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill,
|
||||
@ -621,7 +622,7 @@ public:
|
||||
bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true);
|
||||
bool ImprovedTaunt();
|
||||
bool TryRootFadeByDamage(int buffslot, Mob* attacker);
|
||||
int16 GetSlowMitigation() const {return slow_mitigation;}
|
||||
float GetSlowMitigation() const { return slow_mitigation; }
|
||||
void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr);
|
||||
inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; };
|
||||
inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; };
|
||||
@ -675,6 +676,9 @@ public:
|
||||
bool IsFamiliar() const { return(typeofpet == petFamiliar); }
|
||||
bool IsAnimation() const { return(typeofpet == petAnimation); }
|
||||
bool IsCharmed() const { return(typeofpet == petCharmed); }
|
||||
bool IsTargetLockPet() const { return(typeofpet == petTargetLock); }
|
||||
inline uint32 GetPetTargetLockID() { return pet_targetlock_id; };
|
||||
inline void SetPetTargetLockID(uint32 value) { pet_targetlock_id = value; };
|
||||
void SetOwnerID(uint16 NewOwnerID);
|
||||
inline uint16 GetOwnerID() const { return ownerid; }
|
||||
inline virtual bool HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); }
|
||||
@ -1244,6 +1248,7 @@ protected:
|
||||
bool _IsTempPet;
|
||||
int16 count_TempPet;
|
||||
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
||||
uint32 pet_targetlock_id;
|
||||
|
||||
EGNode *_egnode; //the EG node we are in
|
||||
glm::vec3 m_TargetLocation;
|
||||
|
||||
10
zone/npc.cpp
10
zone/npc.cpp
@ -2419,4 +2419,14 @@ void NPC::DepopSwarmPets()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){
|
||||
|
||||
Mob *targMob = entity_list.GetMob(GetPetTargetLockID());
|
||||
|
||||
if(!targMob || (targMob && targMob->IsCorpse())){
|
||||
Kill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,7 +253,7 @@ public:
|
||||
|
||||
uint32 GetMaxDMG() const {return max_dmg;}
|
||||
uint32 GetMinDMG() const {return min_dmg;}
|
||||
int16 GetSlowMitigation() const {return slow_mitigation;}
|
||||
float GetSlowMitigation() const { return slow_mitigation; }
|
||||
float GetAttackSpeed() const {return attack_speed;}
|
||||
uint8 GetAttackDelay() const {return attack_delay;}
|
||||
bool IsAnimal() const { return(bodytype == BT_Animal); }
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -342,8 +342,8 @@ XS(XS_Group_GetLeaderName)
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetLeaderName(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
char * RETVAL;
|
||||
Group * THIS;
|
||||
const char * RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
|
||||
@ -8367,6 +8367,33 @@ XS(XS_Mob_ProcessSpecialAbilities)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_CanClassEquipItem); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_CanClassEquipItem)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::CanClassEquipItem(THIS, item_id)");
|
||||
{
|
||||
Mob * THIS;
|
||||
bool RETVAL;
|
||||
uint32 item_id = (uint32)SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->CanClassEquipItem(item_id);
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
@ -8675,6 +8702,7 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "SetSpecialAbilityParam"), XS_Mob_SetSpecialAbilityParam, file, "$$$$");
|
||||
newXSproto(strcpy(buf, "ClearSpecialAbilities"), XS_Mob_ClearSpecialAbilities, file, "$");
|
||||
newXSproto(strcpy(buf, "ProcessSpecialAbilities"), XS_Mob_ProcessSpecialAbilities, file, "$$");
|
||||
newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
@ -2076,7 +2076,7 @@ XS(XS_NPC_GetSlowMitigation)
|
||||
Perl_croak(aTHX_ "Usage: NPC::GetSlowMitigation(THIS)");
|
||||
{
|
||||
NPC * THIS;
|
||||
int16 RETVAL;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
@ -2089,7 +2089,7 @@ XS(XS_NPC_GetSlowMitigation)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetSlowMitigation();
|
||||
XSprePUSH; PUSHn((UV)RETVAL);
|
||||
XSprePUSH; PUSHn((double)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
@ -426,6 +426,20 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
entity_list.AddNPC(npc, true, true);
|
||||
SetPetID(npc->GetID());
|
||||
// We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet
|
||||
|
||||
|
||||
if (record.petcontrol == petTargetLock)
|
||||
{
|
||||
Mob* target = GetTarget();
|
||||
|
||||
if (target){
|
||||
npc->AddToHateList(target, 1);
|
||||
npc->SetPetTargetLockID(target->GetID());
|
||||
npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
|
||||
}
|
||||
else
|
||||
npc->Kill(); //On live casts spell 892 Unsummon (Kayen - Too limiting to use that for emu since pet can have more than 20k HP)
|
||||
}
|
||||
}
|
||||
/* This is why the pets ghost - pets were being spawned too far away from its npc owner and some
|
||||
into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I
|
||||
|
||||
@ -5527,7 +5527,12 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
//Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected
|
||||
//by reagent conservation for obvious reasons.
|
||||
|
||||
return realTotal + realTotal2 + realTotal3;
|
||||
//Non-Live like feature to allow for an additive focus bonus to be applied from foci that are placed in worn slot. (No limit checks)
|
||||
int16 worneffect_bonus = 0;
|
||||
if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||
worneffect_bonus = itembonuses.FocusEffectsWorn[type];
|
||||
|
||||
return realTotal + realTotal2 + realTotal3 + worneffect_bonus;
|
||||
}
|
||||
|
||||
int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -2872,7 +2872,13 @@ int ClientTaskState::GetTaskActivityDoneCountFromTaskID(int TaskID, int Activity
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount;
|
||||
|
||||
if (ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount){
|
||||
return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount;
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ClientTaskState::GetTaskStartTime(int index) {
|
||||
|
||||
31
zone/zone.h
31
zone/zone.h
@ -23,6 +23,7 @@
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/types.h"
|
||||
#include "../common/random.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "qglobals.h"
|
||||
#include "spawn2.h"
|
||||
#include "spawngroup.h"
|
||||
@ -67,16 +68,6 @@ struct item_tick_struct {
|
||||
std::string qglobal;
|
||||
};
|
||||
|
||||
// static uint32 gmsay_log_message_colors[EQEmuLogSys::MaxLogID] = {
|
||||
// 15, // "Status", - Yellow
|
||||
// 15, // "Normal", - Yellow
|
||||
// 3, // "Error", - Red
|
||||
// 14, // "Debug", - Light Green
|
||||
// 4, // "Quest",
|
||||
// 5, // "Command",
|
||||
// 3 // "Crash"
|
||||
// };
|
||||
|
||||
class Client;
|
||||
class Map;
|
||||
class Mob;
|
||||
@ -266,7 +257,25 @@ public:
|
||||
// random object that provides random values for the zone
|
||||
EQEmu::Random random;
|
||||
|
||||
static void GMSayHookCallBackProcess(uint16 log_category, const std::string& message){ entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "%s", message.c_str()); }
|
||||
static void GMSayHookCallBackProcess(uint16 log_category, std::string message){
|
||||
/* Cut messages down to 4000 max to prevent client crash */
|
||||
if (!message.empty())
|
||||
message = message.substr(0, 4000);
|
||||
|
||||
/* Replace Occurrences of % or MessageStatus will crash */
|
||||
find_replace(message, std::string("%"), std::string("."));
|
||||
|
||||
if (message.find("\n") != std::string::npos){
|
||||
auto message_split = SplitString(message, '\n');
|
||||
entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "%s", message_split[0].c_str());
|
||||
for (size_t iter = 1; iter < message_split.size(); ++iter) {
|
||||
entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "--- %s", message_split[iter].c_str());
|
||||
}
|
||||
}
|
||||
else{
|
||||
entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "%s", message.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//MODDING HOOKS
|
||||
void mod_init();
|
||||
|
||||
@ -1118,11 +1118,9 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile
|
||||
bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0;
|
||||
for (i = 0; i <= EmuConstants::BANDOLIERS_COUNT; i++){
|
||||
for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++){
|
||||
for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++)
|
||||
for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++)
|
||||
pp->bandoliers[i].items[si].icon = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
r = 0;
|
||||
@ -2999,6 +2997,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
|
||||
@ -3204,16 +3210,7 @@ bool ZoneDatabase::GetNPCFactionList(uint32 npcfaction_id, int32* faction_id, in
|
||||
bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list)
|
||||
{
|
||||
|
||||
std::string query = StringFormat("DELETE FROM faction_values "
|
||||
"WHERE char_id=%i AND faction_id = %i",
|
||||
char_id, faction_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(value == 0)
|
||||
return true;
|
||||
std::string query;
|
||||
|
||||
if(temp == 2)
|
||||
temp = 0;
|
||||
@ -3221,17 +3218,18 @@ bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, in
|
||||
if(temp == 3)
|
||||
temp = 1;
|
||||
|
||||
query = StringFormat("INSERT INTO faction_values (char_id, faction_id, current_value, temp) "
|
||||
"VALUES (%i, %i, %i, %i)", char_id, faction_id, value, temp);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
query = StringFormat("INSERT INTO `faction_values` "
|
||||
"(`char_id`, `faction_id`, `current_value`, `temp`) "
|
||||
"VALUES (%i, %i, %i, %i) "
|
||||
"ON DUPLICATE KEY UPDATE `current_value`=%i,`temp`=%i",
|
||||
char_id, faction_id, value, temp, value, temp);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
val_list[faction_id] = value;
|
||||
|
||||
if (results.RowsAffected() == 0)
|
||||
return false;
|
||||
|
||||
val_list[faction_id] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user