merge upstream

This commit is contained in:
Arthur Ice 2015-01-08 19:40:00 -08:00
commit cd9ca65587
142 changed files with 5443 additions and 3716 deletions

View File

@ -1,7 +1,70 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 01/08/2015 ==
Trevius: Added some extra checks and clean-up related to Groups and Mercenaries.
== 01/07/2015 ==
Uleat: Excluded text link body from message scrambling in Client::GarbleMessage()
Trevius: Mercenaries now load directly from tables only. The vwMercNpcTypes view is no longer required and can be deleted.
Trevius: Query fix for group_leaders table. This may resolve some crashes/bugs related to Mercs/Bots and Groups.
== 01/06/2015 ==
Trevius: Changed the pet command #defines to be based on RoF2 list of pet commands and added decodes to Titanium, SoF and SoD.
Trevius: (RoF+) The /pet focus on/off and /pet hold on/off commands are now functional.
Trevius: Added defines for all remaining pet commands and some support for them as well.
== 01/05/2015 ==
Uleat: Fixed (added translators for) item/text links. Only 'OP_ChannelMessage' and 'OP_SpecialMesg' are currently handled..more text channels will be added as the need arises.
== 01/03/2015 ==
Trevius: (RoF2) /shield (shielding) and /key (key ring) are both now functional after opcode updates.
== 01/02/2015 ==
Trevius: (RoF2) *Hopefully* Fixed looting incorrect items from NPCs. Please report any issues!
Trevius: (RoF2) Now able to loot items past the 10th slot on NPC corpses.
Trevius: Attuned Items can now be auto-looted and will equip properly.
Trevius: Mercenaries and Bots will no longer take a share from /split or /autosplit.
== 12/30/2014 ==
Trevius: (RoF2) Aug Type 21 no longer shows the "Buy Now" button in the aug slot of items.
Trevius: (RoF2) Identified the "Copied" item flag with the help of Uleat.
== 12/29/2014 ==
Trevius: (RoF2) Identified a few Item Fields and resolved an issue with cloth armor not accepting certain augments that they should.
Akkadius: Updated $client->UpdateTaskActivity to have optional argument ignore_quest_update IE: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count, [ignore_quest_update])
Akkadius: Also updated internal UpdateTaskActivity methods to optionally ignore quest based task updates to prevent feedback
== 12/28/2014 ==
Uleat: Implemented class Client::TextLink as a replacement for the dozens of individual link formatters.
== 12/27/2014 ==
Akkadius: Add option to automatic database upgrade script 5) Download latest Opcodes from Github
Trevius: (RoF2) Fixed dropping items on the ground so they go to ground level instead of camera height.
Trevius: Show Helm Option should be functional again.
Kayen: Implemened npc special ability (43) CASTING_RESIST_DIFF which sets innate resist modifier on
ALL spells used by that NPC. Ie. 43,1,-200 will set a -200 innate resist diff, so if your npc cast
a spell that has a -10 resist modifier the final resist diff would be -210.
== 12/25/2014 ==
Uleat: Updated 'links' code for all clients
== 12/24/2014 ==
Trevius: (RoF+) Added herosforgemodel field to the npc_types table.
Trevius: (RoF2) Updated item links from #npcstat command output.
Trevius: (RoF+) Implemented Hero's Forge Armor for NPCs. Set the herosforgemodel field in npc_types table to the model (example: 84 for full set, or 12107 for robe).
Trevius: (RoF+) Hero's Forge Armor now overrides NPC texture settings. To display Hero's Forge Armor Helms, set helmtexture field to anything other than 0.
== 12/23/2014 ==
Uleat: Tidied up some ItemInst* declarations and added some nullptr checks.
Trevius: (RoF+) Added support for Hero's Forge Robe Models. Set herosforgemodel field in items table to exact model such as 11607, 11707, etc.
== 12/22/2014 ==
Trevius: (RoF2) Fixed Tracking.
Trevius: (RoF+) Added a work-around for the cursor buffer issue.
== 12/21/2014 ==
Trevius: (RoF2) Fixed Extended Targets Window by correcting opcodes.
Trevius: (RoF/RoF2) Fixed Guild Rank in the Player Profile, which prevents the guild rank message on login/zone.
== 12/20/2014 ==
Akkadius: Updated #cvs to display RoF2 Client Stream count

View File

@ -33,22 +33,22 @@ int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientExport);
set_exception_handler();
LogFile->write(EQEMuLog::Status, "Client Files Export Utility");
LogFile->write(EQEmuLog::Status, "Client Files Export Utility");
if(!EQEmuConfig::LoadConfig()) {
LogFile->write(EQEMuLog::Error, "Unable to load configuration file.");
LogFile->write(EQEmuLog::Error, "Unable to load configuration file.");
return 1;
}
const EQEmuConfig *config = EQEmuConfig::get();
if(!load_log_settings(config->LogSettingsFile.c_str())) {
LogFile->write(EQEMuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
LogFile->write(EQEmuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
}
SharedDatabase database;
LogFile->write(EQEMuLog::Status, "Connecting to database...");
LogFile->write(EQEmuLog::Status, "Connecting to database...");
if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(),
config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) {
LogFile->write(EQEMuLog::Error, "Unable to connect to the database, cannot continue without a "
LogFile->write(EQEmuLog::Error, "Unable to connect to the database, cannot continue without a "
"database connection");
return 1;
}
@ -61,11 +61,11 @@ int main(int argc, char **argv) {
}
void ExportSpells(SharedDatabase *db) {
LogFile->write(EQEMuLog::Status, "Exporting Spells...");
LogFile->write(EQEmuLog::Status, "Exporting Spells...");
FILE *f = fopen("export/spells_us.txt", "w");
if(!f) {
LogFile->write(EQEMuLog::Error, "Unable to open export/spells_us.txt to write, skipping.");
LogFile->write(EQEmuLog::Error, "Unable to open export/spells_us.txt to write, skipping.");
return;
}
@ -89,7 +89,7 @@ void ExportSpells(SharedDatabase *db) {
fprintf(f, "%s\n", line.c_str());
}
} else {
LogFile->write(EQEMuLog::Error, "Error in ExportSpells query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ExportSpells query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
}
fclose(f);
@ -103,7 +103,7 @@ bool SkillUsable(SharedDatabase *db, int skill_id, int class_id) {
class_id, skill_id);
auto results = db->QueryDatabase(query);
if(!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in skill_usable query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in skill_usable query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -123,7 +123,7 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level) {
class_id, skill_id, level);
auto results = db->QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in get_skill query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in get_skill query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
return 0;
}
@ -135,11 +135,11 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level) {
}
void ExportSkillCaps(SharedDatabase *db) {
LogFile->write(EQEMuLog::Status, "Exporting Skill Caps...");
LogFile->write(EQEmuLog::Status, "Exporting Skill Caps...");
FILE *f = fopen("export/SkillCaps.txt", "w");
if(!f) {
LogFile->write(EQEMuLog::Error, "Unable to open export/SkillCaps.txt to write, skipping.");
LogFile->write(EQEmuLog::Error, "Unable to open export/SkillCaps.txt to write, skipping.");
return;
}
@ -164,11 +164,11 @@ void ExportSkillCaps(SharedDatabase *db) {
}
void ExportBaseData(SharedDatabase *db) {
LogFile->write(EQEMuLog::Status, "Exporting Base Data...");
LogFile->write(EQEmuLog::Status, "Exporting Base Data...");
FILE *f = fopen("export/BaseData.txt", "w");
if(!f) {
LogFile->write(EQEMuLog::Error, "Unable to open export/BaseData.txt to write, skipping.");
LogFile->write(EQEmuLog::Error, "Unable to open export/BaseData.txt to write, skipping.");
return;
}
@ -190,7 +190,7 @@ void ExportBaseData(SharedDatabase *db) {
fprintf(f, "%s\n", line.c_str());
}
} else {
LogFile->write(EQEMuLog::Error, "Error in ExportBaseData query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ExportBaseData query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
}
fclose(f);

View File

@ -32,22 +32,22 @@ int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientImport);
set_exception_handler();
LogFile->write(EQEMuLog::Status, "Client Files Import Utility");
LogFile->write(EQEmuLog::Status, "Client Files Import Utility");
if(!EQEmuConfig::LoadConfig()) {
LogFile->write(EQEMuLog::Error, "Unable to load configuration file.");
LogFile->write(EQEmuLog::Error, "Unable to load configuration file.");
return 1;
}
const EQEmuConfig *config = EQEmuConfig::get();
if(!load_log_settings(config->LogSettingsFile.c_str())) {
LogFile->write(EQEMuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
LogFile->write(EQEmuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
}
SharedDatabase database;
LogFile->write(EQEMuLog::Status, "Connecting to database...");
LogFile->write(EQEmuLog::Status, "Connecting to database...");
if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(),
config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) {
LogFile->write(EQEMuLog::Error, "Unable to connect to the database, cannot continue without a "
LogFile->write(EQEmuLog::Error, "Unable to connect to the database, cannot continue without a "
"database connection");
return 1;
}
@ -64,7 +64,7 @@ int GetSpellColumns(SharedDatabase *db) {
const std::string query = "DESCRIBE spells_new";
auto results = db->QueryDatabase(query);
if(!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetSpellColumns query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetSpellColumns query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
return 0;
}
@ -72,10 +72,10 @@ int GetSpellColumns(SharedDatabase *db) {
}
void ImportSpells(SharedDatabase *db) {
LogFile->write(EQEMuLog::Status, "Importing Spells...");
LogFile->write(EQEmuLog::Status, "Importing Spells...");
FILE *f = fopen("import/spells_us.txt", "r");
if(!f) {
LogFile->write(EQEMuLog::Error, "Unable to open import/spells_us.txt to read, skipping.");
LogFile->write(EQEmuLog::Error, "Unable to open import/spells_us.txt to read, skipping.");
return;
}
@ -138,23 +138,23 @@ void ImportSpells(SharedDatabase *db) {
spells_imported++;
if(spells_imported % 1000 == 0) {
LogFile->write(EQEMuLog::Status, "%d spells imported.", spells_imported);
LogFile->write(EQEmuLog::Status, "%d spells imported.", spells_imported);
}
}
if(spells_imported % 1000 != 0) {
LogFile->write(EQEMuLog::Status, "%d spells imported.", spells_imported);
LogFile->write(EQEmuLog::Status, "%d spells imported.", spells_imported);
}
fclose(f);
}
void ImportSkillCaps(SharedDatabase *db) {
LogFile->write(EQEMuLog::Status, "Importing Skill Caps...");
LogFile->write(EQEmuLog::Status, "Importing Skill Caps...");
FILE *f = fopen("import/SkillCaps.txt", "r");
if(!f) {
LogFile->write(EQEMuLog::Error, "Unable to open import/SkillCaps.txt to read, skipping.");
LogFile->write(EQEmuLog::Error, "Unable to open import/SkillCaps.txt to read, skipping.");
return;
}
@ -186,11 +186,11 @@ void ImportSkillCaps(SharedDatabase *db) {
}
void ImportBaseData(SharedDatabase *db) {
LogFile->write(EQEMuLog::Status, "Importing Base Data...");
LogFile->write(EQEmuLog::Status, "Importing Base Data...");
FILE *f = fopen("import/BaseData.txt", "r");
if(!f) {
LogFile->write(EQEMuLog::Error, "Unable to open import/BaseData.txt to read, skipping.");
LogFile->write(EQEmuLog::Error, "Unable to open import/BaseData.txt to read, skipping.");
return;
}

View File

@ -24,7 +24,7 @@ public:
}
}
LogFile->write(EQEMuLog::Crash, buffer);
LogFile->write(EQEmuLog::Crash, buffer);
StackWalker::OnOutput(szText);
}
};
@ -34,67 +34,67 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_ACCESS_VIOLATION");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_ACCESS_VIOLATION");
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
break;
case EXCEPTION_BREAKPOINT:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_BREAKPOINT");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_BREAKPOINT");
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_DATATYPE_MISALIGNMENT");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_DATATYPE_MISALIGNMENT");
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_FLT_DENORMAL_OPERAND");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_FLT_DENORMAL_OPERAND");
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_FLT_DIVIDE_BY_ZERO");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_FLT_DIVIDE_BY_ZERO");
break;
case EXCEPTION_FLT_INEXACT_RESULT:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_FLT_INEXACT_RESULT");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_FLT_INEXACT_RESULT");
break;
case EXCEPTION_FLT_INVALID_OPERATION:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_FLT_INVALID_OPERATION");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_FLT_INVALID_OPERATION");
break;
case EXCEPTION_FLT_OVERFLOW:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_FLT_OVERFLOW");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_FLT_OVERFLOW");
break;
case EXCEPTION_FLT_STACK_CHECK:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_FLT_STACK_CHECK");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_FLT_STACK_CHECK");
break;
case EXCEPTION_FLT_UNDERFLOW:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_FLT_UNDERFLOW");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_FLT_UNDERFLOW");
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_ILLEGAL_INSTRUCTION");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_ILLEGAL_INSTRUCTION");
break;
case EXCEPTION_IN_PAGE_ERROR:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_IN_PAGE_ERROR");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_IN_PAGE_ERROR");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_INT_DIVIDE_BY_ZERO");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_INT_DIVIDE_BY_ZERO");
break;
case EXCEPTION_INT_OVERFLOW:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_INT_OVERFLOW");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_INT_OVERFLOW");
break;
case EXCEPTION_INVALID_DISPOSITION:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_INVALID_DISPOSITION");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_INVALID_DISPOSITION");
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_NONCONTINUABLE_EXCEPTION");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_NONCONTINUABLE_EXCEPTION");
break;
case EXCEPTION_PRIV_INSTRUCTION:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_PRIV_INSTRUCTION");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_PRIV_INSTRUCTION");
break;
case EXCEPTION_SINGLE_STEP:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_SINGLE_STEP");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_SINGLE_STEP");
break;
case EXCEPTION_STACK_OVERFLOW:
LogFile->write(EQEMuLog::Crash, "EXCEPTION_STACK_OVERFLOW");
LogFile->write(EQEmuLog::Crash, "EXCEPTION_STACK_OVERFLOW");
break;
default:
LogFile->write(EQEMuLog::Crash, "Unknown Exception");
LogFile->write(EQEmuLog::Crash, "Unknown Exception");
break;
}

View File

@ -84,12 +84,12 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c
uint32 errnum= 0;
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(host, user, passwd, database, port, &errnum, errbuf)) {
LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf);
LogFile->write(EQEmuLog::Error, "Failed to connect to database: Error: %s", errbuf);
return false;
}
else {
LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port);
LogFile->write(EQEmuLog::Status, "Using database '%s' at %s:%d",database,host,port);
return true;
}
}
@ -706,7 +706,7 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inven
charid = GetCharacterID(pp->name);
if(!charid) {
LogFile->write(EQEMuLog::Error, "StoreCharacter: no character id");
LogFile->write(EQEmuLog::Error, "StoreCharacter: no character id");
return false;
}
@ -736,10 +736,10 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inven
auto results = QueryDatabase(invquery);
if (!results.RowsAffected())
LogFile->write(EQEMuLog::Error, "StoreCharacter inventory failed. Query '%s' %s", invquery.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "StoreCharacter inventory failed. Query '%s' %s", invquery.c_str(), results.ErrorMessage().c_str());
#if EQDEBUG >= 9
else
LogFile->write(EQEMuLog::Debug, "StoreCharacter inventory succeeded. Query '%s'", invquery.c_str());
LogFile->write(EQEmuLog::Debug, "StoreCharacter inventory succeeded. Query '%s'", invquery.c_str());
#endif
}
@ -805,7 +805,7 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) {
std::string query = StringFormat("SELECT `account_id` FROM `character_data` WHERE `id` = %i LIMIT 1", char_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetAccountIDByChar query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetAccountIDByChar query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return 0;
}
@ -3162,28 +3162,28 @@ void Database::SetLFP(uint32 CharID, bool LFP) {
std::string query = StringFormat("UPDATE `character_data` SET `lfp` = %i WHERE `id` = %i",LFP, CharID);
auto results = QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error updating LFP for character %i : %s", CharID, results.ErrorMessage().c_str());
}
void Database::SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon) {
std::string query = StringFormat("update `character_data` SET `lfp` = %i, `lfg` = %i, `firstlogon` = %i WHERE `id` = %i",LFP, LFG, firstlogon, CharID);
auto results = QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error updating LFP for character %i : %s", CharID, results.ErrorMessage().c_str());
}
void Database::SetLFG(uint32 CharID, bool LFG) {
std::string query = StringFormat("update `character_data` SET `lfg` = %i WHERE `id` = %i",LFG, CharID);
auto results = QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error updating LFP for character %i : %s", CharID, results.ErrorMessage().c_str());
}
void Database::SetFirstLogon(uint32 CharID, uint8 firstlogon) {
std::string query = StringFormat( "UPDATE `character_data` SET `firstlogon` = %i WHERE `id` = %i",firstlogon, CharID);
auto results = QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Error updating firstlogon for character %i : %s", CharID, results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error updating firstlogon for character %i : %s", CharID, results.ErrorMessage().c_str());
}
void Database::AddReport(std::string who, std::string against, std::string lines) {
@ -3195,7 +3195,7 @@ void Database::AddReport(std::string who, std::string against, std::string lines
safe_delete_array(escape_str);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Error adding a report for %s: %s", who.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error adding a report for %s: %s", who.c_str(), results.ErrorMessage().c_str());
}
void Database::SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc) {
@ -3206,7 +3206,7 @@ void Database::SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ism
auto results = QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Error deleting character from group id: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error deleting character from group id: %s", results.ErrorMessage().c_str());
return;
}
@ -3216,7 +3216,7 @@ void Database::SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ism
auto results = QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Error adding character to group id: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error adding character to group id: %s", results.ErrorMessage().c_str());
}
void Database::ClearAllGroups(void)
@ -3255,13 +3255,13 @@ uint32 Database::GetGroupID(const char* name){
if (!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error getting group id: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting group id: %s", results.ErrorMessage().c_str());
return 0;
}
if (results.RowCount() == 0)
{
LogFile->write(EQEMuLog::Debug, "Character not in a group: %s", name);
LogFile->write(EQEmuLog::Debug, "Character not in a group: %s", name);
return 0;
}
@ -3303,12 +3303,12 @@ void Database::SetGroupLeaderName(uint32 gid, const char* name) {
return;
}
query = StringFormat("INSERT INTO group_leaders(gid, leadername, marknpc, leadershipaa, maintank, assist, puller, mentoree, mentor_percent) VALUES(%u, '%s', '', '', '', '', '', '', '0')",
query = StringFormat("REPLACE INTO group_leaders(gid, leadername, marknpc, leadershipaa, maintank, assist, puller, mentoree, mentor_percent) VALUES(%u, '%s', '', '', '', '', '', '', '0')",
gid, EscapeString(name).c_str());
result = QueryDatabase(query);
if(!result.Success()) {
LogFile->write(EQEMuLog::Debug, "Error in Database::SetGroupLeaderName: %s", result.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Debug, "Error in Database::SetGroupLeaderName: %s", result.ErrorMessage().c_str());
}
}
@ -4048,7 +4048,7 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
if (!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error in GetCharactersInInstace query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetCharactersInInstace query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return;
}

View File

@ -9,6 +9,31 @@
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#include <conio.h>
#include <iostream>
#include <dos.h>
namespace ConsoleColor {
enum Colors {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightMagenta = 13,
Yellow = 14,
White = 15,
};
}
#else
#include <sys/types.h>
@ -25,13 +50,13 @@
#endif
static volatile bool logFileValid = false;
static EQEMuLog realLogFile;
EQEMuLog *LogFile = &realLogFile;
static EQEmuLog realLogFile;
EQEmuLog *LogFile = &realLogFile;
static const char* FileNames[EQEMuLog::MaxLogID] = { "logs/eqemu", "logs/eqemu", "logs/eqemu_error", "logs/eqemu_debug", "logs/eqemu_quest", "logs/eqemu_commands", "logs/crash" };
static const char* LogNames[EQEMuLog::MaxLogID] = { "Status", "Normal", "Error", "Debug", "Quest", "Command", "Crash" };
static const char* FileNames[EQEmuLog::MaxLogID] = { "logs/eqemu", "logs/eqemu", "logs/eqemu_error", "logs/eqemu_debug", "logs/eqemu_quest", "logs/eqemu_commands", "logs/crash" };
static const char* LogNames[EQEmuLog::MaxLogID] = { "Status", "Normal", "Error", "Debug", "Quest", "Command", "Crash" };
EQEMuLog::EQEMuLog()
EQEmuLog::EQEmuLog()
{
for (int i = 0; i < MaxLogID; i++) {
fp[i] = 0;
@ -39,17 +64,17 @@ EQEMuLog::EQEMuLog()
logCallbackBuf[i] = nullptr;
logCallbackPva[i] = nullptr;
}
pLogStatus[EQEMuLog::LogIDs::Status] = LOG_LEVEL_STATUS;
pLogStatus[EQEMuLog::LogIDs::Normal] = LOG_LEVEL_NORMAL;
pLogStatus[EQEMuLog::LogIDs::Error] = LOG_LEVEL_ERROR;
pLogStatus[EQEMuLog::LogIDs::Debug] = LOG_LEVEL_DEBUG;
pLogStatus[EQEMuLog::LogIDs::Quest] = LOG_LEVEL_QUEST;
pLogStatus[EQEMuLog::LogIDs::Commands] = LOG_LEVEL_COMMANDS;
pLogStatus[EQEMuLog::LogIDs::Crash] = LOG_LEVEL_CRASH;
pLogStatus[EQEmuLog::LogIDs::Status] = LOG_LEVEL_STATUS;
pLogStatus[EQEmuLog::LogIDs::Normal] = LOG_LEVEL_NORMAL;
pLogStatus[EQEmuLog::LogIDs::Error] = LOG_LEVEL_ERROR;
pLogStatus[EQEmuLog::LogIDs::Debug] = LOG_LEVEL_DEBUG;
pLogStatus[EQEmuLog::LogIDs::Quest] = LOG_LEVEL_QUEST;
pLogStatus[EQEmuLog::LogIDs::Commands] = LOG_LEVEL_COMMANDS;
pLogStatus[EQEmuLog::LogIDs::Crash] = LOG_LEVEL_CRASH;
logFileValid = true;
}
EQEMuLog::~EQEMuLog()
EQEmuLog::~EQEmuLog()
{
logFileValid = false;
for (int i = 0; i < MaxLogID; i++) {
@ -60,7 +85,7 @@ EQEMuLog::~EQEMuLog()
}
}
bool EQEMuLog::open(LogIDs id)
bool EQEmuLog::open(LogIDs id)
{
if (!logFileValid) {
return false;
@ -112,7 +137,7 @@ bool EQEMuLog::open(LogIDs id)
return true;
}
bool EQEMuLog::write(LogIDs id, const char *fmt, ...)
bool EQEmuLog::write(LogIDs id, const char *fmt, ...)
{
if (!logFileValid) {
return false;
@ -156,15 +181,45 @@ bool EQEMuLog::write(LogIDs id, const char *fmt, ...)
if (pLogStatus[id] & 8) {
fprintf(stderr, "[%s] ", LogNames[id]);
vfprintf( stderr, fmt, argptr );
} else {
}
/* This is what's outputted to console */
else {
#ifdef _WINDOWS
HANDLE console_handle;
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFOEX info = { 0 };
info.cbSize = sizeof(info);
info.dwFontSize.Y = 12; // leave X as zero
info.FontWeight = FW_NORMAL;
wcscpy(info.FaceName, L"Lucida Console");
SetCurrentConsoleFontEx(console_handle, NULL, &info);
if (id == EQEmuLog::LogIDs::Status){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::Yellow); }
if (id == EQEmuLog::LogIDs::Error){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); }
if (id == EQEmuLog::LogIDs::Normal){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightGreen); }
if (id == EQEmuLog::LogIDs::Debug){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::Yellow); }
if (id == EQEmuLog::LogIDs::Quest){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightCyan); }
if (id == EQEmuLog::LogIDs::Commands){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightMagenta); }
if (id == EQEmuLog::LogIDs::Crash){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); }
#endif
fprintf(stdout, "[%s] ", LogNames[id]);
vfprintf( stdout, fmt, argptr );
#ifdef _WINDOWS
/* Always set back to white*/
SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::White);
#endif
}
}
va_end(argptr);
if (dofile) {
fprintf(fp[id], "\n");
}
/* Print Lind Endings */
if (pLogStatus[id] & 2) {
if (pLogStatus[id] & 8) {
fprintf(stderr, "\n");
@ -181,7 +236,7 @@ bool EQEMuLog::write(LogIDs id, const char *fmt, ...)
}
//write with Prefix and a VA_list
bool EQEMuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list argptr)
bool EQEmuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list argptr)
{
if (!logFileValid) {
return false;
@ -223,9 +278,38 @@ bool EQEMuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list
if (pLogStatus[id] & 8) {
fprintf(stderr, "[%s] %s", LogNames[id], prefix);
vfprintf( stderr, fmt, argptr );
} else {
}
/* Console Output */
else {
#ifdef _WINDOWS
HANDLE console_handle;
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFOEX info = { 0 };
info.cbSize = sizeof(info);
info.dwFontSize.Y = 12; // leave X as zero
info.FontWeight = FW_NORMAL;
wcscpy(info.FaceName, L"Lucida Console");
SetCurrentConsoleFontEx(console_handle, NULL, &info);
if (id == EQEmuLog::LogIDs::Status){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::Yellow); }
if (id == EQEmuLog::LogIDs::Error){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); }
if (id == EQEmuLog::LogIDs::Normal){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightGreen); }
if (id == EQEmuLog::LogIDs::Debug){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::Yellow); }
if (id == EQEmuLog::LogIDs::Quest){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightCyan); }
if (id == EQEmuLog::LogIDs::Commands){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightMagenta); }
if (id == EQEmuLog::LogIDs::Crash){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); }
#endif
fprintf(stdout, "[%s] %s", LogNames[id], prefix);
vfprintf( stdout, fmt, argptr );
vfprintf(stdout, fmt, argptr);
#ifdef _WINDOWS
/* Always set back to white*/
SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::White);
#endif
}
}
va_end(argptr);
@ -245,7 +329,7 @@ bool EQEMuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list
return true;
}
bool EQEMuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count)
bool EQEmuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count)
{
if (!logFileValid) {
return false;
@ -288,9 +372,36 @@ bool EQEMuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count)
fwrite(buf, size, count, stderr);
fprintf(stderr, "\n");
} else {
#ifdef _WINDOWS
HANDLE console_handle;
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFOEX info = { 0 };
info.cbSize = sizeof(info);
info.dwFontSize.Y = 12; // leave X as zero
info.FontWeight = FW_NORMAL;
wcscpy(info.FaceName, L"Lucida Console");
SetCurrentConsoleFontEx(console_handle, NULL, &info);
if (id == EQEmuLog::LogIDs::Status){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::Yellow); }
if (id == EQEmuLog::LogIDs::Error){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); }
if (id == EQEmuLog::LogIDs::Normal){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightGreen); }
if (id == EQEmuLog::LogIDs::Debug){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightGreen); }
if (id == EQEmuLog::LogIDs::Quest){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightCyan); }
if (id == EQEmuLog::LogIDs::Commands){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightMagenta); }
if (id == EQEmuLog::LogIDs::Crash){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); }
#endif
fprintf(stdout, "[%s] ", LogNames[id]);
fwrite(buf, size, count, stdout);
fprintf(stdout, "\n");
#ifdef _WINDOWS
/* Always set back to white*/
SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::White);
#endif
}
}
if (dofile) {
@ -299,7 +410,7 @@ bool EQEMuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count)
return true;
}
bool EQEMuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...)
bool EQEmuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...)
{
va_list argptr, tmpargptr;
va_start(argptr, fmt);
@ -318,7 +429,7 @@ bool EQEMuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...)
return true;
};
bool EQEMuLog::Dump(LogIDs id, uint8* data, uint32 size, uint32 cols, uint32 skip)
bool EQEmuLog::Dump(LogIDs id, uint8* data, uint32 size, uint32 cols, uint32 skip)
{
if (!logFileValid) {
#if EQDEBUG >= 10
@ -386,7 +497,7 @@ bool EQEMuLog::Dump(LogIDs id, uint8* data, uint32 size, uint32 cols, uint32 ski
return true;
}
void EQEMuLog::SetCallback(LogIDs id, msgCallbackFmt proc)
void EQEmuLog::SetCallback(LogIDs id, msgCallbackFmt proc)
{
if (!logFileValid) {
return;
@ -397,7 +508,7 @@ void EQEMuLog::SetCallback(LogIDs id, msgCallbackFmt proc)
logCallbackFmt[id] = proc;
}
void EQEMuLog::SetCallback(LogIDs id, msgCallbackBuf proc)
void EQEmuLog::SetCallback(LogIDs id, msgCallbackBuf proc)
{
if (!logFileValid) {
return;
@ -408,7 +519,7 @@ void EQEMuLog::SetCallback(LogIDs id, msgCallbackBuf proc)
logCallbackBuf[id] = proc;
}
void EQEMuLog::SetCallback(LogIDs id, msgCallbackPva proc)
void EQEmuLog::SetCallback(LogIDs id, msgCallbackPva proc)
{
if (!logFileValid) {
return;
@ -419,7 +530,7 @@ void EQEMuLog::SetCallback(LogIDs id, msgCallbackPva proc)
logCallbackPva[id] = proc;
}
void EQEMuLog::SetAllCallbacks(msgCallbackFmt proc)
void EQEmuLog::SetAllCallbacks(msgCallbackFmt proc)
{
if (!logFileValid) {
return;
@ -430,7 +541,7 @@ void EQEMuLog::SetAllCallbacks(msgCallbackFmt proc)
}
}
void EQEMuLog::SetAllCallbacks(msgCallbackBuf proc)
void EQEmuLog::SetAllCallbacks(msgCallbackBuf proc)
{
if (!logFileValid) {
return;
@ -441,7 +552,7 @@ void EQEMuLog::SetAllCallbacks(msgCallbackBuf proc)
}
}
void EQEMuLog::SetAllCallbacks(msgCallbackPva proc)
void EQEmuLog::SetAllCallbacks(msgCallbackPva proc)
{
if (!logFileValid) {
return;

View File

@ -74,10 +74,10 @@
#include <stdarg.h>
class EQEMuLog {
class EQEmuLog {
public:
EQEMuLog();
~EQEMuLog();
EQEmuLog();
~EQEmuLog();
enum LogIDs {
Status = 0, /* This must stay the first entry in this list */
@ -128,7 +128,7 @@ private:
msgCallbackPva logCallbackPva[MaxLogID];
};
extern EQEMuLog* LogFile;
extern EQEmuLog* LogFile;
#ifdef _EQDEBUG
class PerformanceMonitor {

View File

@ -149,6 +149,8 @@ public:
static const uint32 BANDOLIER_SIZE = Titanium::consts::BANDOLIER_SIZE; // size = number of equipment slots in bandolier instance
static const uint32 POTION_BELT_SIZE = Titanium::consts::POTION_BELT_SIZE;
static const size_t TEXT_LINK_BODY_LENGTH = 56;
// legacy-related functions
//static int ServerToPerlSlot(int slot); // encode
//static int PerlToServerSlot(int slot); // decode

View File

@ -1509,7 +1509,8 @@ enum ItemPacketType
ItemPacketTributeItem = 0x6C,
ItemPacketMerchant = 0x64,
ItemPacketWorldContainer = 0x6B,
ItemPacketCharmUpdate = 0x6E
ItemPacketCharmUpdate = 0x6E,
ItemPacketInvalid = 0xFF
};
struct ItemPacket_Struct
{
@ -3015,14 +3016,14 @@ struct ClientError_Struct
};
struct Track_Struct {
uint16 entityid;
uint16 padding002;
uint32 entityid;
float distance;
// Fields for SoD and later
uint8 level;
uint8 NPC;
uint8 GroupMember;
uint8 is_npc;
char name[64];
uint8 is_pet;
uint8 is_merc;
};
struct Tracking_Struct {
@ -5268,6 +5269,23 @@ struct ClientMarqueeMessage_Struct {
typedef std::list<ServerLootItem_Struct*> ItemList;
struct TextLinkBody_Struct {
// Current server mask: EQClientRoF2
uint8 unknown_1; /* %1X */
uint32 item_id; /* %05X */
uint32 augment_1; /* %05X */
uint32 augment_2; /* %05X */
uint32 augment_3; /* %05X */
uint32 augment_4; /* %05X */
uint32 augment_5; /* %05X */
uint32 augment_6; /* %05X */
uint8 is_evolving; /* %1X */
uint32 evolve_group; /* %05X */
uint8 evolve_level; /* %02X */
uint32 ornament_icon; /* %05X */
int hash; /* %08X */
};
// Restore structure packing to default
#pragma pack()

View File

@ -987,7 +987,7 @@ EQRawApplicationPacket *p=nullptr;
EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode);
#if EQDEBUG >= 4
if(emu_op == OP_Unknown) {
LogFile->write(EQEMuLog::Debug, "Unable to convert EQ opcode 0x%.4x to an Application opcode.", p->opcode);
LogFile->write(EQEmuLog::Debug, "Unable to convert EQ opcode 0x%.4x to an Application opcode.", p->opcode);
}
#endif
p->SetOpcode(emu_op);

View File

@ -140,7 +140,7 @@ bool EQTime::saveFile(const char *filename)
of.open(filename);
if(!of)
{
LogFile->write(EQEMuLog::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename);
LogFile->write(EQEmuLog::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename);
return false;
}
//Enable for debugging
@ -164,14 +164,14 @@ bool EQTime::loadFile(const char *filename)
in.open(filename);
if(!in)
{
LogFile->write(EQEMuLog::Error, "Could not load EQTime file %s", filename);
LogFile->write(EQEmuLog::Error, "Could not load EQTime file %s", filename);
return false;
}
in >> version;
in.ignore(80, '\n');
if(version != EQT_VERSION)
{
LogFile->write(EQEMuLog::Error, "'%s' is NOT a valid EQTime file. File version is %i, EQTime version is %i", filename, version, EQT_VERSION);
LogFile->write(EQEmuLog::Error, "'%s' is NOT a valid EQTime file. File version is %i, EQTime version is %i", filename, version, EQT_VERSION);
return false;
}
//in >> eqTime.start_eqtime.day;

View File

@ -337,7 +337,7 @@ uint32 BaseGuildManager::_GetFreeGuildID() {
if (!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error in _GetFreeGuildID query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in _GetFreeGuildID query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
continue;
}

View File

@ -89,6 +89,17 @@ ItemInst* ItemInstQueue::pop()
return inst;
}
// Remove item from back of queue
ItemInst* ItemInstQueue::pop_back()
{
if (m_list.size() == 0)
return nullptr;
ItemInst* inst = m_list.back();
m_list.pop_back();
return inst;
}
// Look at item at front of queue
ItemInst* ItemInstQueue::peek_front() const
{
@ -259,6 +270,11 @@ int16 Inventory::PushCursor(const ItemInst& inst)
return MainCursor;
}
ItemInst* Inventory::GetCursorItem()
{
return m_cursor.peek_front();
}
// Swap items in inventory
bool Inventory::SwapItem(int16 slot_a, int16 slot_b)
{
@ -1135,7 +1151,7 @@ int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst)
}
if (result == INVALID_INDEX) {
LogFile->write(EQEMuLog::Error, "Inventory::_PutItem: Invalid slot_id specified (%i)", slot_id);
LogFile->write(EQEmuLog::Error, "Inventory::_PutItem: Invalid slot_id specified (%i)", slot_id);
Inventory::MarkDirty(inst); // Slot not found, clean up
}
@ -1170,13 +1186,13 @@ int16 Inventory::_HasItem(std::map<int16, ItemInst*>& bucket, uint32 item_id, ui
for (itb = inst->_begin(); itb != inst->_end(); ++itb) {
ItemInst* baginst = itb->second;
if (baginst->GetID() == item_id) {
if (baginst && baginst->GetID() == item_id) {
quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges();
if (quantity_found >= quantity)
return Inventory::CalcSlotId(it->first, itb->first);
}
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
if (baginst && baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
return legacy::SLOT_AUGMENT; // Only one augment per slot.
}
}
@ -1214,13 +1230,13 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
for (itb = inst->_begin(); itb != inst->_end(); ++itb) {
ItemInst* baginst = itb->second;
if (baginst->GetID() == item_id) {
if (baginst && baginst->GetID() == item_id) {
quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges();
if (quantity_found >= quantity)
return Inventory::CalcSlotId(MainCursor, itb->first);
}
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
if (baginst && baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
return legacy::SLOT_AUGMENT; // Only one augment per slot.
}
@ -1314,7 +1330,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
if (inst->GetItem()->LoreGroup == loregroup)
return it->first;
ItemInst* Aug;
ItemInst* Aug = nullptr;
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
Aug = inst->GetAugment(i);
if (Aug && Aug->GetItem()->LoreGroup == loregroup)
@ -1329,7 +1345,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup)
return Inventory::CalcSlotId(it->first, itb->first);
ItemInst* Aug2;
ItemInst* Aug2 = nullptr;
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
Aug2 = baginst->GetAugment(i);
if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup)
@ -1357,7 +1373,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
if (inst->GetItem()->LoreGroup == loregroup)
return MainCursor;
ItemInst* Aug;
ItemInst* Aug = nullptr;
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
Aug = inst->GetAugment(i);
if (Aug && Aug->GetItem()->LoreGroup == loregroup)
@ -1373,7 +1389,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
return Inventory::CalcSlotId(MainCursor, itb->first);
ItemInst* Aug2;
ItemInst* Aug2 = nullptr;
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
Aug2 = baginst->GetAugment(i);
if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup)
@ -1703,6 +1719,8 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent)
end = m_contents.end();
for (; cur != end;) {
ItemInst* inst = cur->second;
if (inst == nullptr)
continue;
const Item_Struct* item = inst->GetItem();
del = cur;
++cur;

View File

@ -93,6 +93,7 @@ public:
void push(ItemInst* inst);
void push_front(ItemInst* inst);
ItemInst* pop();
ItemInst* pop_back();
ItemInst* peek_front() const;
inline int size() { return static_cast<int>(m_list.size()); }
@ -152,6 +153,9 @@ public:
// Add item to cursor queue
int16 PushCursor(const ItemInst& inst);
// Get cursor item in front of queue
ItemInst* GetCursorItem();
// Swap items in inventory
bool SwapItem(int16 slot_a, int16 slot_b);

View File

@ -35,6 +35,6 @@ void log_message(LogType type, const char *fmt, ...) {
void log_messageVA(LogType type, const char *fmt, va_list args) {
std::string prefix_buffer = StringFormat("[%s] ", log_type_info[type].name);
LogFile->writePVA(EQEMuLog::Debug, prefix_buffer.c_str(), fmt, args);
LogFile->writePVA(EQEmuLog::Debug, prefix_buffer.c_str(), fmt, args);
}

View File

@ -33,6 +33,12 @@ namespace RoF
static inline uint32 RoFToServerMainInvSlot(structs::MainInvItemSlotStruct RoFSlot);
static inline uint32 RoFToServerCorpseSlot(uint32 RoFCorpse);
// server to client text link converter
static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink);
// client to server text link converter
static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink);
void Register(EQStreamIdentifier &into)
{
//create our opcode manager if we havent already
@ -488,7 +494,13 @@ namespace RoF
unsigned char *__emu_buffer = in->pBuffer;
in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
std::string old_message = emu->message;
std::string new_message;
ServerToRoFTextLink(new_message, old_message);
//in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39;
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
@ -501,7 +513,7 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->message);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
@ -2315,7 +2327,7 @@ namespace RoF
outapp->WriteUInt8(emu->gm);
outapp->WriteUInt32(emu->guild_id);
outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet.
outapp->WriteUInt8(emu->guildrank); // guildrank
outapp->WriteUInt32(0); // Unknown - observed 1 in a live packet.
outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet.
outapp->WriteUInt32(0); // Unknown
@ -2576,7 +2588,7 @@ namespace RoF
strn0cpy(general->player_name, raid_create->leader_name, 64);
dest->FastQueuePacket(&outapp_create);
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_RaidUpdate)
@ -2643,7 +2655,7 @@ namespace RoF
dest->FastQueuePacket(&outapp);
}
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_ReadBook)
@ -2900,7 +2912,7 @@ namespace RoF
{
eq->entries[i] = emu->entries[i];
}
eq->entries[21] = 0;
eq->entries[21] = 1;
FINISH_ENCODE();
}
@ -3096,6 +3108,44 @@ namespace RoF
FINISH_ENCODE();
}
ENCODE(OP_SpecialMesg)
{
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = &emu->message[strlen(emu->sayer)];
std::string new_message;
ServerToRoFTextLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = 25 + strlen(emu->sayer) + new_message.length();
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_Stun)
{
ENCODE_LENGTH_EXACT(Stun_Struct);
@ -3294,9 +3344,9 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
}
delete[] __emu_buffer;
@ -4041,7 +4091,13 @@ namespace RoF
uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
std::string old_message = InBuffer;
std::string new_message;
RoFToServerTextLink(new_message, old_message);
//__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
__packet->pBuffer = new unsigned char[__packet->size];
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
@ -4050,7 +4106,7 @@ namespace RoF
emu->language = Language;
emu->chan_num = Channel;
emu->skill_in_language = Skill;
strcpy(emu->message, InBuffer);
strcpy(emu->message, new_message.c_str());
delete[] __eq_buffer;
}
@ -4456,47 +4512,8 @@ namespace RoF
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
switch (eq->command)
{
case 0x00:
emu->command = 0x04; // Health
break;
case 0x01:
emu->command = 0x10; // Leader
break;
case 0x02:
emu->command = 0x07; // Attack
break;
case 0x04:
emu->command = 0x08; // Follow
break;
case 0x05:
emu->command = 0x05; // Guard
break;
case 0x06:
emu->command = 0x09; // Sit. Needs work. This appears to be a toggle between Sit/Stand now.
break;
case 0x0c:
emu->command = 0x0b; // Taunt
break;
case 0x0f:
emu->command = 0x0c; // Hold
break;
case 0x10:
emu->command = 0x1b; // Hold on
break;
case 0x11:
emu->command = 0x1c; // Hold off
break;
case 0x1c:
emu->command = 0x01; // Back
break;
case 0x1d:
emu->command = 0x02; // Leave/Go Away
break;
default:
emu->command = eq->command;
}
IN(command);
emu->unknown = eq->unknown04;
FINISH_DIRECT_DECODE();
}
@ -4854,27 +4871,8 @@ namespace RoF
ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem));
}
//ORNAMENT IDFILE / ICON
uint16 ornaIcon = 0;
int32 heroModel = 0;
/*
if (inst->GetOrnamentationAug(ornamentationAugtype))
{
const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
//Mainhand
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
ss.write((const char*)&null_term, sizeof(uint8));
//Offhand
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
ss.write((const char*)&null_term, sizeof(uint8));
//Icon
ornaIcon = aug_weap->Icon;
if (aug_weap->HerosForgeModel > 0)
{
heroModel = (aug_weap->HerosForgeModel * 100) + Inventory::CalcMaterialFromSlot(slot_id_in);
}
}
else
*/
uint32 ornaIcon = 0;
uint32 heroModel = 0;
if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon())
{
@ -4896,8 +4894,6 @@ namespace RoF
RoF::structs::ItemSerializationHeaderFinish hdrf;
hdrf.ornamentIcon = ornaIcon;
hdrf.unknown061 = 0;
hdrf.unknown062 = 0;
hdrf.unknowna1 = 0xffffffff;
hdrf.ornamentHeroModel = heroModel;
hdrf.unknown063 = 0;
@ -5506,7 +5502,6 @@ namespace RoF
static inline uint32 ServerToRoFCorpseSlot(uint32 ServerCorpse)
{
//uint32 RoFCorpse;
return (ServerCorpse + 1);
}
@ -5647,8 +5642,80 @@ namespace RoF
static inline uint32 RoFToServerCorpseSlot(uint32 RoFCorpse)
{
//uint32 ServerCorpse;
return (RoFCorpse - 1);
}
static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink)
{
const char delimiter = 0x12;
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
rofTextLink = serverTextLink;
return;
}
auto segments = SplitString(serverTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55)
// Diff: ^
new_segment.append(segments[segment_iter].substr(0, 41).c_str());
if (segments[segment_iter].substr(41, 1) == "0")
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
else
new_segment.append("F");
new_segment.append(segments[segment_iter].substr(43).c_str());
rofTextLink.push_back(delimiter);
rofTextLink.append(new_segment.c_str());
rofTextLink.push_back(delimiter);
}
else {
rofTextLink.append(segments[segment_iter].c_str());
}
}
}
static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink)
{
const char delimiter = 0x12;
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rofTextLink.find(delimiter) == std::string::npos)) {
serverTextLink = rofTextLink;
return;
}
auto segments = SplitString(rofTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 42 47 (Source)
// RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// Diff: ^
new_segment.append(segments[segment_iter].substr(0, 41).c_str());
new_segment.append("0");
new_segment.append(segments[segment_iter].substr(41).c_str());
serverTextLink.push_back(delimiter);
serverTextLink.append(new_segment.c_str());
serverTextLink.push_back(delimiter);
}
else {
serverTextLink.append(segments[segment_iter].c_str());
}
}
}
}
// end namespace RoF

View File

@ -21,18 +21,24 @@ namespace RoF2
static OpcodeManager *opcodes = nullptr;
static Strategy struct_strategy;
char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth);
char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth, ItemPacketType packet_type);
// server to client inventory location converters
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot);
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot, ItemPacketType PacketType = ItemPacketInvalid);
static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 ServerSlot);
static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse);
// client to server inventory location converters
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot);
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot, ItemPacketType PacketType = ItemPacketInvalid);
static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct RoF2Slot);
static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse);
// server to client text link converter
static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink);
// client to server text link converter
static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink);
void Register(EQStreamIdentifier &into)
{
//create our opcode manager if we havent already
@ -116,6 +122,72 @@ namespace RoF2
#include "ss_define.h"
// ENCODE methods
// RoF2 Specific Encodes Begin
ENCODE(OP_SendMembershipDetails)
{
ENCODE_LENGTH_EXACT(Membership_Details_Struct);
SETUP_DIRECT_ENCODE(Membership_Details_Struct, structs::Membership_Details_Struct);
eq->membership_setting_count = 72;
for (uint32 i = 0; i < emu->membership_setting_count; ++i) // 66
{
OUT(settings[i].setting_index);
OUT(settings[i].setting_id);
OUT(settings[i].setting_value);
}
// Last 6 new settings fields are all 0s on Live as of 12/29/14
eq->race_entry_count = emu->race_entry_count;
for (uint32 i = 0; i < emu->race_entry_count; ++i) // 15
{
OUT(membership_races[i].purchase_id);
OUT(membership_races[i].bitwise_entry);
}
eq->class_entry_count = emu->class_entry_count;
for (uint32 i = 0; i < emu->class_entry_count; ++i) // 15
{
OUT(membership_classes[i].purchase_id);
OUT(membership_classes[i].bitwise_entry);
}
eq->exit_url_length = emu->exit_url_length;
eq->exit_url_length2 = emu->exit_url_length2;
FINISH_ENCODE();
}
ENCODE(OP_SendMembership)
{
ENCODE_LENGTH_EXACT(Membership_Struct);
SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct);
eq->membership = emu->membership;
eq->races = emu->races;
eq->classes = emu->classes;
eq->entrysize = 25; //emu->entrysize;
for (uint32 i = 0; i < emu->entrysize; ++i) // 21
{
OUT(entries[i]);
}
// Last 4 new entries are 0s on Live Silver as of 12/29/14
// Setting them each to 1 for now.
// This removes the "Buy Now" button from aug type 21 slots on items.
for (uint32 i = 21; i < 25; ++i) // 4
{
eq->entries[i] = 1;
}
FINISH_ENCODE();
}
// RoF2 Specific Encodes End
ENCODE(OP_Action)
{
ENCODE_LENGTH_EXACT(Action_Struct);
@ -488,7 +560,13 @@ namespace RoF2
unsigned char *__emu_buffer = in->pBuffer;
in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
std::string old_message = emu->message;
std::string new_message;
ServerToRoF2TextLink(new_message, old_message);
//in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39;
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
@ -501,7 +579,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->message);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
@ -556,7 +634,7 @@ namespace RoF2
uint32 Length = 0;
char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0);
char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0, ItemPacketCharInventory);
if (Serialized) {
@ -1370,7 +1448,7 @@ namespace RoF2
InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem);
uint32 length;
char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0);
char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType);
if (!serialized) {
_log(NET__STRUCTS, "Serialization failed on item slot %d.", int_struct->slot_id);
@ -1676,8 +1754,15 @@ namespace RoF2
eq->FogDensity = emu->fog_density;
/*fill in some unknowns with observed values, hopefully it will help */
eq->unknown569 = 0;
eq->unknown571 = 0;
eq->unknown572 = 4;
eq->unknown576 = 2;
eq->unknown580 = 0;
eq->unknown800 = -1;
eq->unknown844 = 600;
eq->unknown848 = 2008; // Guild Lobby observed value
eq->unknown880 = 50;
eq->unknown884 = 10;
eq->unknown888 = 1;
@ -1987,17 +2072,17 @@ namespace RoF2
outapp->WriteUInt32(emu->drakkin_tattoo);
outapp->WriteUInt32(emu->drakkin_details);
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown 0
outapp->WriteUInt8(0xff); // Unknown 0xff
outapp->WriteUInt8(1); // Unknown 1
outapp->WriteUInt8(0xff); // Unknown 0xff
outapp->WriteUInt8(1); // Unknown 1
outapp->WriteFloat(5.0f); // Height ?
outapp->WriteFloat(5.0f); // Height
outapp->WriteFloat(3.0f); // Unknown
outapp->WriteFloat(2.5f); // Unknown
outapp->WriteFloat(5.5f); // Unknown
outapp->WriteFloat(3.0f); // Unknown 3.0
outapp->WriteFloat(2.5f); // Unknown 2.5
outapp->WriteFloat(5.5f); // Unknown 5.5
outapp->WriteUInt32(0); // Primary ?
outapp->WriteUInt32(0); // Secondary ?
@ -2316,14 +2401,14 @@ namespace RoF2
outapp->WriteUInt8(emu->gm);
outapp->WriteUInt32(emu->guild_id);
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(emu->guildrank); // guildrank
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt64(emu->exp); // int32 in client
outapp->WriteUInt8(0); // Unknown - Seen 5 on Live
outapp->WriteUInt8(5); // Unknown - Seen 5 on Live - Eye Height?
outapp->WriteUInt32(emu->platinum_bank);
outapp->WriteUInt32(emu->gold_bank);
@ -2587,7 +2672,7 @@ namespace RoF2
strn0cpy(general->player_name, raid_create->leader_name, 64);
dest->FastQueuePacket(&outapp_create);
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_RaidUpdate)
@ -2654,7 +2739,7 @@ namespace RoF2
dest->FastQueuePacket(&outapp);
}
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_ReadBook)
@ -2898,24 +2983,6 @@ namespace RoF2
FINISH_ENCODE();
}
ENCODE(OP_SendMembership)
{
ENCODE_LENGTH_EXACT(Membership_Struct);
SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct);
eq->membership = emu->membership;
eq->races = emu->races;
eq->classes = emu->classes;
eq->entrysize = 22;
for (int i = 0; i<21; i++)
{
eq->entries[i] = emu->entries[i];
}
eq->entries[21] = 0;
FINISH_ENCODE();
}
ENCODE(OP_SendZonepoints)
{
SETUP_VAR_ENCODE(ZonePoints);
@ -3107,6 +3174,44 @@ namespace RoF2
FINISH_ENCODE();
}
ENCODE(OP_SpecialMesg)
{
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = &emu->message[strlen(emu->sayer)];
std::string new_message;
ServerToRoF2TextLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = 25 + strlen(emu->sayer) + new_message.length();
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_Stun)
{
ENCODE_LENGTH_EXACT(Stun_Struct);
@ -3289,7 +3394,7 @@ namespace RoF2
int PacketSize = 2;
for (int i = 0; i < EntryCount; ++i, ++emu)
PacketSize += (12 + strlen(emu->name));
PacketSize += (13 + strlen(emu->name));
emu = (Track_Struct *)__emu_buffer;
@ -3305,9 +3410,10 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_pet);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
}
delete[] __emu_buffer;
@ -3734,7 +3840,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_tattoo);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_details);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2); // unknown8
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown9
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown10
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->helm); // unknown11
@ -4057,7 +4163,13 @@ namespace RoF2
uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
std::string old_message = InBuffer;
std::string new_message;
RoF2ToServerTextLink(new_message, old_message);
//__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
__packet->pBuffer = new unsigned char[__packet->size];
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
@ -4066,7 +4178,7 @@ namespace RoF2
emu->language = Language;
emu->chan_num = Channel;
emu->skill_in_language = Skill;
strcpy(emu->message, InBuffer);
strcpy(emu->message, new_message.c_str());
delete[] __eq_buffer;
}
@ -4471,47 +4583,8 @@ namespace RoF2
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
switch (eq->command)
{
case 0x00:
emu->command = 0x04; // Health
break;
case 0x01:
emu->command = 0x10; // Leader
break;
case 0x02:
emu->command = 0x07; // Attack
break;
case 0x04:
emu->command = 0x08; // Follow
break;
case 0x05:
emu->command = 0x05; // Guard
break;
case 0x06:
emu->command = 0x09; // Sit. Needs work. This appears to be a toggle between Sit/Stand now.
break;
case 0x0c:
emu->command = 0x0b; // Taunt
break;
case 0x0f:
emu->command = 0x0c; // Hold
break;
case 0x10:
emu->command = 0x1b; // Hold on
break;
case 0x11:
emu->command = 0x1c; // Hold off
break;
case 0x1c:
emu->command = 0x01; // Back
break;
case 0x1d:
emu->command = 0x02; // Leave/Go Away
break;
default:
emu->command = eq->command;
}
IN(command);
emu->unknown = eq->unknown04;
FINISH_DIRECT_DECODE();
}
@ -4811,7 +4884,7 @@ namespace RoF2
return NextItemInstSerialNumber;
}
char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth)
char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth, ItemPacketType packet_type)
{
int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
uint8 null_term = 0;
@ -4835,15 +4908,14 @@ namespace RoF2
hdr.stacksize = stackable ? charges : 1;
hdr.unknown004 = 0;
structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in);
structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in, packet_type);
hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items?
hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot;
hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff;
hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff;
hdr.aug_slot = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff;
hdr.price = inst->GetPrice();
hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount();
//hdr.merchant_slot = (merchant_slot == 0) ? 1 : 0xffffffff;
hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0;
hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot;
hdr.unknown028 = 0;
@ -4869,28 +4941,9 @@ namespace RoF2
ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem));
}
//ORNAMENT IDFILE / ICON
uint16 ornaIcon = 0;
int32 heroModel = 0;
/*
if (inst->GetOrnamentationAug(ornamentationAugtype))
{
const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
//Mainhand
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
ss.write((const char*)&null_term, sizeof(uint8));
//Offhand
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
ss.write((const char*)&null_term, sizeof(uint8));
//Icon
ornaIcon = aug_weap->Icon;
if (aug_weap->HerosForgeModel > 0)
{
heroModel = (aug_weap->HerosForgeModel * 100) + Inventory::CalcMaterialFromSlot(slot_id_in);
}
}
else
*/
uint32 ornaIcon = 0;
uint32 heroModel = 0;
if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon())
{
char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile());
@ -4911,12 +4964,10 @@ namespace RoF2
RoF2::structs::ItemSerializationHeaderFinish hdrf;
hdrf.ornamentIcon = ornaIcon;
hdrf.unknown061 = 0;
hdrf.unknown062 = 0;
hdrf.unknowna1 = 0xffffffff;
hdrf.ornamentHeroModel = heroModel;
hdrf.unknown063 = 0;
hdrf.unknowna3 = 0;
hdrf.Copied = 0;
hdrf.unknowna4 = 0xffffffff;
hdrf.unknowna5 = 0;
hdrf.ItemClass = item->ItemClass;
@ -5066,7 +5117,7 @@ namespace RoF2
memset(&isbs, 0, sizeof(RoF2::structs::ItemSecondaryBodyStruct));
isbs.augtype = item->AugType;
isbs.augdistiller = 65535;
isbs.augrestrict2 = -1;
isbs.augrestrict = item->AugRestrict;
for (int x = AUG_BEGIN; x < consts::ITEM_COMMON_SIZE; x++)
@ -5310,9 +5361,21 @@ namespace RoF2
iqbs.HealAmt = item->HealAmt;
iqbs.SpellDmg = item->SpellDmg;
iqbs.clairvoyance = item->Clairvoyance;
iqbs.unknown28 = 0;
iqbs.unknown30 = 0;
iqbs.unknown37a = 0;
//unknown18; //Power Source Capacity or evolve filename?
//evolve_string; // Some String, but being evolution related is just a guess
iqbs.Heirloom = 0;
iqbs.Placeable = 0;
iqbs.unknown28 = -1;
iqbs.unknown30 = -1;
iqbs.NoZone = 0;
iqbs.NoGround = 0;
iqbs.unknown37a = 0; // (guessed position) New to RoF2
iqbs.unknown38 = 0;
iqbs.unknown39 = 1;
iqbs.subitem_count = 0;
@ -5350,7 +5413,7 @@ namespace RoF2
SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x);
*/
SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1);
SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1, packet_type);
}
}
@ -5376,7 +5439,7 @@ namespace RoF2
return item_serial;
}
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot)
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot, ItemPacketType PacketType)
{
structs::ItemSlotStruct RoF2Slot;
RoF2Slot.SlotType = INVALID_INDEX;
@ -5389,13 +5452,21 @@ namespace RoF2
uint32 TempSlot = 0;
if (ServerSlot < 56 || ServerSlot == MainPowerSource) { // Main Inventory and Cursor
RoF2Slot.SlotType = maps::MapPossessions;
RoF2Slot.MainSlot = ServerSlot;
if (PacketType == ItemPacketLoot)
{
RoF2Slot.SlotType = maps::MapCorpse;
RoF2Slot.MainSlot = ServerSlot - EmuConstants::CORPSE_BEGIN;
}
else
{
RoF2Slot.SlotType = maps::MapPossessions;
RoF2Slot.MainSlot = ServerSlot;
}
if (ServerSlot == MainPowerSource)
RoF2Slot.MainSlot = slots::MainPowerSource;
else if (ServerSlot >= MainCursor) // Cursor and Extended Corpse Inventory
else if (ServerSlot >= MainCursor && PacketType != ItemPacketLoot) // Cursor and Extended Corpse Inventory
RoF2Slot.MainSlot += 3;
else if (ServerSlot >= MainAmmo) // (> 20)
@ -5522,11 +5593,10 @@ namespace RoF2
static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse)
{
//uint32 RoF2Corpse;
return (ServerCorpse + 1);
return (ServerCorpse - EmuConstants::CORPSE_BEGIN + 1);
}
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot)
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot, ItemPacketType PacketType)
{
uint32 ServerSlot = INVALID_INDEX;
uint32 TempSlot = 0;
@ -5621,6 +5691,10 @@ namespace RoF2
ServerSlot = INVALID_INDEX;
}
else if (RoF2Slot.SlotType == maps::MapCorpse) {
ServerSlot = RoF2Slot.MainSlot + EmuConstants::CORPSE_BEGIN;
}
_log(NET__ERROR, "Convert RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", RoF2Slot.SlotType, RoF2Slot.Unknown02, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01, ServerSlot);
return ServerSlot;
@ -5663,8 +5737,71 @@ namespace RoF2
static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse)
{
//uint32 ServerCorpse;
return (RoF2Corpse - 1);
return (RoF2Corpse + EmuConstants::CORPSE_BEGIN - 1);
}
static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink)
{
const char delimiter = 0x12;
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
rof2TextLink = serverTextLink;
return;
}
auto segments = SplitString(serverTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// Diff:
new_segment.append(segments[segment_iter]);
rof2TextLink.push_back(delimiter);
rof2TextLink.append(new_segment.c_str());
rof2TextLink.push_back(delimiter);
}
else {
rof2TextLink.append(segments[segment_iter].c_str());
}
}
}
static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink)
{
const char delimiter = 0x12;
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rof2TextLink.find(delimiter) == std::string::npos)) {
serverTextLink = rof2TextLink;
return;
}
auto segments = SplitString(rof2TextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// Diff:
new_segment.append(segments[segment_iter]);
serverTextLink.push_back(delimiter);
serverTextLink.append(new_segment.c_str());
serverTextLink.push_back(delimiter);
}
else {
serverTextLink.append(segments[segment_iter].c_str());
}
}
}
}
// end namespace RoF2

View File

@ -181,6 +181,8 @@ namespace RoF2 {
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
static const uint32 POTION_BELT_SIZE = 5;
static const size_t TEXT_LINK_BODY_LENGTH = 56;
}
namespace limits {

View File

@ -1,6 +1,8 @@
// out-going packets that require an ENCODE translation:
// Begin RoF2 Encodes
E(OP_SendMembershipDetails)
// incoming packets that require a DECODE translation:
// Begin RoF2 Decodes
@ -93,6 +95,7 @@ E(OP_SkillUpdate)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnAppearance)
E(OP_SpawnDoor)
E(OP_SpecialMesg)
E(OP_Stun)
E(OP_TargetBuffs)
E(OP_TaskDescription)

View File

@ -243,11 +243,11 @@ struct Membership_Setting_Struct
struct Membership_Details_Struct
{
/*0000*/ uint32 membership_setting_count; // Seen 66
/*0016*/ Membership_Setting_Struct settings[66];
/*0016*/ Membership_Setting_Struct settings[72]; // 864 Bytes
/*0012*/ uint32 race_entry_count; // Seen 15
/*1044*/ Membership_Entry_Struct membership_races[15];
/*1044*/ Membership_Entry_Struct membership_races[15]; // 120 Bytes
/*0012*/ uint32 class_entry_count; // Seen 15
/*1044*/ Membership_Entry_Struct membership_classes[15];
/*1044*/ Membership_Entry_Struct membership_classes[15]; // 120 Bytes
/*1044*/ uint32 exit_url_length; // Length of the exit_url string (0 for none)
/*1048*/ //char exit_url[42]; // Upgrade to Silver or Gold Membership URL
/*1048*/ uint32 exit_url_length2; // Length of the exit_url2 string (0 for none)
@ -260,7 +260,7 @@ struct Membership_Struct
/*004*/ uint32 races; // Seen ff ff 01 00
/*008*/ uint32 classes; // Seen ff ff 01 01
/*012*/ uint32 entrysize; // Seen 22
/*016*/ int32 entries[22]; // Most -1, 1, and 0 for Gold Status
/*016*/ int32 entries[25]; // Most -1, 1, and 0 for Gold Status
/*104*/
};
@ -537,9 +537,13 @@ struct NewZone_Struct {
/*0525*/ uint8 rain_duration[4];
/*0529*/ uint8 snow_chance[4];
/*0533*/ uint8 snow_duration[4];
/*0537*/ uint8 unknown537[33];
/*0537*/ uint8 unknown537[32]; // Seen all 0xff
/*0569*/ uint8 unknown569; // Unknown - Seen 0
/*0570*/ uint8 sky; // Sky Type
/*0571*/ uint8 unknown571[13]; // ***Placeholder
/*0571*/ uint8 unknown571; // Unknown - Seen 0
/*0572*/ uint32 unknown572; // Unknown - Seen 4 in Guild Lobby
/*0576*/ uint32 unknown576; // Unknown - Seen 2 in Guild Lobby
/*0580*/ uint32 unknown580; // Unknown - Seen 0 in Guild Lobby
/*0584*/ float zone_exp_multiplier; // Experience Multiplier
/*0588*/ float safe_y; // Zone Safe Y
/*0592*/ float safe_x; // Zone Safe X
@ -554,7 +558,7 @@ struct NewZone_Struct {
/*0800*/ int32 unknown800; //seen -1
/*0804*/ char unknown804[40]; //
/*0844*/ int32 unknown844; //seen 600
/*0848*/ int32 unknown848;
/*0848*/ int32 unknown848; //seen 2008
/*0852*/ uint16 zone_id;
/*0854*/ uint16 zone_instance;
/*0856*/ char unknown856[20];
@ -581,7 +585,7 @@ struct NewZone_Struct {
/*0932*/ int32 unknown932; // Seen -1
/*0936*/ int32 unknown936; // Seen -1
/*0940*/ uint32 unknown940; // Seen 0
/*0944*/ float unknown944; // Seen 1.0
/*0944*/ float unknown944; // Seen 1.0 in PoK, and 0.25 in Guild Lobby
/*0948*/ uint32 unknown948; // Seen 0 - New on Live as of Dec 15 2014
/*0952*/ uint32 unknown952; // Seen 100 - New on Live as of Dec 15 2014
/*0956*/
@ -880,6 +884,12 @@ struct Disciplines_Struct {
};
struct DisciplineTimer_Struct
{
/*00*/ uint32 TimerID;
/*04*/ uint32 Duration;
/*08*/ uint32 Unknown08;
};
struct Tribute_Struct {
uint32 tribute;
@ -1219,64 +1229,17 @@ union
/*
///////////////////// - Haven't identified the below fields in the PP yet
uint8 pvp; // 1=pvp, 0=not pvp
uint8 anon; // 2=roleplay, 1=anon, 0=not anon
uint8 gm; // 0=no, 1=yes (guessing!)
uint32 guild_id; // guildid
uint8 guildrank; // 0=member, 1=officer, 2=guildleader -1=no guild
uint32 guildbanker;
uint32 available_slots;
uint32 endurance; // Current endurance
uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; // Refresh time (millis) - 4 bytes Each * 16 = 64 bytes
uint32 abilitySlotRefresh;
///////////////////////
uint32 platinum_bank; // Platinum Pieces in Bank
uint32 gold_bank; // Gold Pieces in Bank
uint32 silver_bank; // Silver Pieces in Bank
uint32 copper_bank; // Copper Pieces in Bank
uint32 platinum_shared; // Shared platinum pieces
uint32 autosplit; // 0 = off, 1 = on
char groupMembers[MAX_GROUP_MEMBERS][64];// 384 all the members in group, including self
char groupLeader[64]; // Leader of the group ?
uint32 entityid;
uint32 leadAAActive; // 0 = leader AA off, 1 = leader AA on
int32 ldon_points_guk; // Earned GUK points
int32 ldon_points_mir; // Earned MIR points
int32 ldon_points_mmc; // Earned MMC points
int32 ldon_points_ruj; // Earned RUJ points
int32 ldon_points_tak; // Earned TAK points
int32 ldon_points_available;// Available LDON points
float tribute_time_remaining;// Time remaining on tribute (millisecs)
uint32 career_tribute_points;// Total favor points for this char
uint32 tribute_points; // Current tribute points
uint32 tribute_active; // 0 = off, 1=on
Tribute_Struct tributes[MAX_PLAYER_TRIBUTES]; // [40] Current tribute loadout
double group_leadership_exp; // Current group lead exp points
double raid_leadership_exp; // Current raid lead AA exp points
uint32 group_leadership_points; // Unspent group lead AA points
uint32 raid_leadership_points; // Unspent raid lead AA points
LeadershipAA_Struct leader_abilities; // [128]Leader AA ranks 19332
uint32 PVPKills;
uint32 PVPDeaths;
uint32 PVPCurrentPoints;
uint32 PVPCareerPoints;
uint32 PVPBestKillStreak;
uint32 PVPWorstDeathStreak;
uint32 PVPCurrentKillStreak;
PVPStatsEntry_Struct PVPLastKill; // size 88
PVPStatsEntry_Struct PVPLastDeath; // size 88
uint32 PVPNumberOfKillsInLast24Hours;
PVPStatsEntry_Struct PVPRecentKills[50]; // size 4400 - 88 each
uint32 expAA; // Exp earned in current AA point
uint32 currentRadCrystals; // Current count of radiant crystals
uint32 careerRadCrystals; // Total count of radiant crystals ever
uint32 currentEbonCrystals; // Current count of ebon crystals
uint32 careerEbonCrystals; // Total count of ebon crystals ever
*/
};
@ -1886,8 +1849,8 @@ struct LootingItem_Struct {
/*000*/ uint32 lootee;
/*004*/ uint32 looter;
/*008*/ uint16 slot_id;
/*010*/ uint16 unknown10;
/*012*/ uint32 auto_loot;
/*010*/ uint16 unknown10; // slot_id is probably uint32
/*012*/ int32 auto_loot;
/*016*/ uint32 unknown16;
/*020*/
};
@ -2892,7 +2855,8 @@ struct Resurrect_Struct
/*160*/ char corpse_name[64];
/*224*/ uint32 action;
/*228*/ uint32 unknown228;
/*232*/
/*232*/ uint32 unknown232;
/*236*/
};
struct SetRunMode_Struct {
@ -3111,29 +3075,24 @@ struct MobHealth
};
struct Track_Struct {
uint16 entityid;
uint16 y;
uint16 x;
uint16 z;
uint32 entityid;
float distance;
// Fields for SoD and later
uint8 level;
uint8 is_npc;
char name[64];
uint8 is_pet;
uint8 is_merc;
};
struct Tracking_Struct {
uint16 entry_count;
Track_Struct Entrys[0];
};
// Looks like new tracking structures - Opcode: 0x57a7
struct Tracking_Struct_New {
uint16 totalcount; // Total Count of mobs within tracking range
Track_Struct Entrys[0];
};
struct Track_Struct_New {
uint16 entityid; // Entity ID
uint16 unknown002; // 00 00
uint32 unknown004; //
uint8 level; // level of mob
uint8 unknown009; // 01 maybe type of mob? player/npc?
char name[1]; // name of mob
struct TrackTarget_Struct
{
uint32 EntityID;
};
@ -4399,7 +4358,7 @@ struct ItemSerializationHeader
/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ?
/*026*/ uint16 main_slot;
/*028*/ uint16 sub_slot;
/*030*/ uint16 unknown013; // 0xffff
/*030*/ uint16 aug_slot; // 0xffff
/*032*/ uint32 price;
/*036*/ uint32 merchant_slot; //1 if not a merchant item
/*040*/ uint32 scaled_value; //0
@ -4428,17 +4387,14 @@ struct EvolvingItem {
struct ItemSerializationHeaderFinish
{
/*079*/ uint16 ornamentIcon;
/*081*/ uint8 unknown061; // 0 - Add Evolving Item struct if this isn't set to 0?
/*082*/ uint8 unknown062; // 0
/*083*/ int32 unknowna1; // 0xffffffff
/*087*/ uint32 ornamentHeroModel; // 0
/*091*/ uint8 unknown063; // 0
/*092*/ uint32 unknowna3; // 0
/*096*/ int32 unknowna4; // 0xffffffff
/*100*/ uint32 unknowna5; // 0
/*104*/ uint8 ItemClass; //0, 1, or 2
/*105*/
uint32 ornamentIcon;
int32 unknowna1; // 0xffffffff
uint32 ornamentHeroModel;
int32 unknown063; // 0
uint8 Copied; // Copied Flag - Possibly for items copied during server transfer?
int32 unknowna4; // 0xffffffff
int32 unknowna5; // 0
uint8 ItemClass; //0, 1, or 2
};
struct ItemBodyStruct
@ -4542,7 +4498,7 @@ struct ItemSecondaryBodyStruct
// swapped augrestrict and augdistiller positions
// (this swap does show the proper augment restrictions in Item Information window now)
// unsure what the purpose of augdistiller is at this time -U 3/17/2014
uint32 augdistiller; // New to December 10th 2012 client - NEW
int32 augrestrict2; // New to December 10th 2012 client - Hidden Aug Restriction
uint32 augrestrict;
AugSlotStruct augslots[6];
@ -4647,7 +4603,7 @@ struct ItemQuaternaryBodyStruct
uint8 quest_item;
uint32 Power; // Enables "Power" percentage field used by Power Sources
uint32 Purity;
uint8 unknown16; // RoF2
uint8 unknown16; // RoF
uint32 BackstabDmg;
uint32 DSMitigation;
int32 HeroicStr;
@ -4669,15 +4625,19 @@ struct ItemQuaternaryBodyStruct
uint8 unknown18; //Power Source Capacity or evolve filename?
uint32 evolve_string; // Some String, but being evolution related is just a guess
uint8 unknown19;
uint32 unknown20; // Bard Stuff?
//uint32 unknown21;
uint8 unknown22;
uint16 unknown20;
uint8 unknown21;
uint8 Heirloom; // Heirloom Flag
uint8 Placeable; // Placeable Flag
uint8 unknown22b;
uint8 unknown22c;
uint8 unknown22d;
uint32 unknown23;
uint32 unknown24;
uint32 unknown25;
float unknown26;
float unknown27;
uint32 unknown_RoF26; // 0 New to March 21 2012 client
uint32 unknown_RoF_6; // 0 New to March 21 2012 client
uint32 unknown28; // 0xffffffff
uint16 unknown29;
uint32 unknown30; // 0xffffffff
@ -4688,9 +4648,15 @@ struct ItemQuaternaryBodyStruct
uint32 unknown35;
uint32 unknown36;
uint32 unknown37;
uint32 unknown_RoF27;
uint32 unknown_RoF28;
uint8 unknown37a; // (guessed position) New to RoF2
uint8 NoZone; // No Zone Flag - Item will disappear upon zoning?
uint8 unknown_RoF_7b; // Maybe Uint32 ?
uint8 unknown_RoF_7c;
uint8 unknown_RoF_7d;
uint8 unknown_RoF_8a;
uint8 NoGround; // No Ground Flag - Item cannot be dropped on the ground?
uint8 unknown_RoF_8c;
uint8 unknown_RoF_8d;
uint8 unknown37a; // New to RoF2 - Probably variable length string
uint8 unknown38; // 0
uint8 unknown39; // 1
uint32 subitem_count;

View File

@ -180,6 +180,8 @@ namespace RoF {
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
static const uint32 POTION_BELT_SIZE = 5;
static const size_t TEXT_LINK_BODY_LENGTH = 55;
}
namespace limits {

View File

@ -84,6 +84,7 @@ E(OP_SkillUpdate)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnAppearance)
E(OP_SpawnDoor)
E(OP_SpecialMesg)
E(OP_Stun)
E(OP_TargetBuffs)
E(OP_TaskDescription)

View File

@ -3103,32 +3103,25 @@ struct MobHealth
};
struct Track_Struct {
uint16 entityid;
uint16 y;
uint16 x;
uint16 z;
uint32 entityid;
float distance;
// Fields for SoD and later
uint8 level;
uint8 is_npc;
char name[64];
uint8 is_merc;
};
struct Tracking_Struct {
uint16 entry_count;
Track_Struct Entrys[0];
};
// Looks like new tracking structures - Opcode: 0x57a7
struct Tracking_Struct_New {
uint16 totalcount; // Total Count of mobs within tracking range
Track_Struct Entrys[0];
struct TrackTarget_Struct
{
uint32 EntityID;
};
struct Track_Struct_New {
uint16 entityid; // Entity ID
uint16 unknown002; // 00 00
uint32 unknown004; //
uint8 level; // level of mob
uint8 unknown009; // 01 maybe type of mob? player/npc?
char name[1]; // name of mob
};
/*
** ZoneServerInfo_Struct
** Zone server information
@ -4420,9 +4413,7 @@ struct EvolvingItem {
struct ItemSerializationHeaderFinish
{
/*079*/ uint16 ornamentIcon;
/*081*/ uint8 unknown061; // 0 - Add Evolving Item struct if this isn't set to 0?
/*082*/ uint8 unknown062; // 0
/*079*/ uint32 ornamentIcon;
/*083*/ int32 unknowna1; // 0xffffffff
/*087*/ uint32 ornamentHeroModel; // 0
/*091*/ uint8 unknown063; // 0

View File

@ -31,6 +31,12 @@ namespace SoD
static inline uint32 SoDToServerSlot(uint32 SoDSlot);
static inline uint32 SoDToServerCorpseSlot(uint32 SoDCorpse);
// server to client text link converter
static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink);
// client to server text link converter
static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink);
void Register(EQStreamIdentifier &into)
{
//create our opcode manager if we havent already
@ -296,6 +302,35 @@ namespace SoD
FINISH_ENCODE();
}
ENCODE(OP_ChannelMessage)
{
EQApplicationPacket *in = *p;
*p = nullptr;
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = emu->message;
std::string new_message;
ServerToSoDTextLink(new_message, old_message);
in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
memcpy(OutBuffer, __emu_buffer, sizeof(ChannelMessage_Struct));
OutBuffer += sizeof(ChannelMessage_Struct);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_CharInventory)
{
//consume the packet
@ -1638,7 +1673,7 @@ namespace SoD
strn0cpy(general->player_name, raid_create->leader_name, 64);
dest->FastQueuePacket(&outapp_create);
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_RaidUpdate)
@ -1705,7 +1740,7 @@ namespace SoD
dest->FastQueuePacket(&outapp);
}
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_ReadBook)
@ -1963,6 +1998,44 @@ namespace SoD
FINISH_ENCODE();
}
ENCODE(OP_SpecialMesg)
{
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = &emu->message[strlen(emu->sayer)];
std::string new_message;
ServerToSoDTextLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = 25 + strlen(emu->sayer) + new_message.length();
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_Stun)
{
ENCODE_LENGTH_EXACT(Stun_Struct);
@ -2058,9 +2131,9 @@ namespace SoD
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
}
delete[] __emu_buffer;
@ -2729,6 +2802,25 @@ namespace SoD
FINISH_DIRECT_DECODE();
}
DECODE(OP_ChannelMessage)
{
unsigned char *__eq_buffer = __packet->pBuffer;
std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)];
std::string new_message;
SoDToServerTextLink(new_message, old_message);
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
__packet->pBuffer = new unsigned char[__packet->size];
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
memcpy(emu, __eq_buffer, sizeof(ChannelMessage_Struct));
strcpy(emu->message, new_message.c_str());
delete[] __eq_buffer;
}
DECODE(OP_CharacterCreate)
{
DECODE_LENGTH_EXACT(structs::CharCreate_Struct);
@ -3007,6 +3099,89 @@ namespace SoD
FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)
{
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
switch (eq->command)
{
case 0x04:
emu->command = 0x00; // /pet health
break;
case 0x10:
emu->command = 0x01; // /pet leader
break;
case 0x07:
emu->command = 0x02; // /pet attack or Pet Window
break;
case 0x03: // Case Guessed
emu->command = 0x03; // /pet qattack
case 0x08:
emu->command = 0x04; // /pet follow or Pet Window
break;
case 0x05:
emu->command = 0x05; // /pet guard or Pet Window
break;
case 0x09:
emu->command = 0x07; // /pet sit or Pet Window
break;
case 0x0a:
emu->command = 0x08; // /pet stand or Pet Window
break;
case 0x06:
emu->command = 0x1e; // /pet guard me
break;
case 0x0f: // Case Made Up
emu->command = 0x09; // /pet stop
break;
case 0x0b:
emu->command = 0x0d; // /pet taunt or Pet Window
break;
case 0x0e:
emu->command = 0x0e; // /pet notaunt or Pet Window
break;
case 0x0c:
emu->command = 0x0f; // /pet hold
break;
case 0x1b:
emu->command = 0x10; // /pet hold on
break;
case 0x1c:
emu->command = 0x11; // /pet hold off
break;
case 0x11:
emu->command = 0x12; // Slumber?
break;
case 0x12:
emu->command = 0x15; // /pet no cast
break;
case 0x0d: // Case Made Up
emu->command = 0x16; // Pet Window No Cast
break;
case 0x13:
emu->command = 0x18; // /pet focus
break;
case 0x19:
emu->command = 0x19; // /pet focus on
break;
case 0x1a:
emu->command = 0x1a; // /pet focus off
break;
case 0x01:
emu->command = 0x1c; // /pet back off
break;
case 0x02:
emu->command = 0x1d; // /pet get lost
break;
default:
emu->command = eq->command;
}
OUT(unknown);
FINISH_DIRECT_DECODE();
}
DECODE(OP_RaidInvite)
{
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
@ -3683,5 +3858,81 @@ namespace SoD
//uint32 ServerCorpse;
return (SoDCorpse - 1);
}
static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink)
{
const char delimiter = 0x12;
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
sodTextLink = serverTextLink;
return;
}
auto segments = SplitString(serverTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
// Diff: ^^^^^ ^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
if (segments[segment_iter].substr(41, 1) == "0")
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
else
new_segment.append("F");
new_segment.append(segments[segment_iter].substr(43).c_str());
sodTextLink.push_back(delimiter);
sodTextLink.append(new_segment.c_str());
sodTextLink.push_back(delimiter);
}
else {
sodTextLink.append(segments[segment_iter].c_str());
}
}
}
static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink)
{
const char delimiter = 0x12;
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sodTextLink.find(delimiter) == std::string::npos)) {
serverTextLink = sodTextLink;
return;
}
auto segments = SplitString(sodTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source)
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// Diff: ^^^^^ ^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append("00000");
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
new_segment.append("0");
new_segment.append(segments[segment_iter].substr(36).c_str());
serverTextLink.push_back(delimiter);
serverTextLink.append(new_segment.c_str());
serverTextLink.push_back(delimiter);
}
else {
serverTextLink.append(segments[segment_iter].c_str());
}
}
}
}
// end namespace SoD

View File

@ -177,6 +177,8 @@ namespace SoD {
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
static const uint32 POTION_BELT_SIZE = 5;
static const size_t TEXT_LINK_BODY_LENGTH = 50;
}
namespace limits {

View File

@ -8,6 +8,7 @@ E(OP_Barter)
E(OP_BazaarSearch)
E(OP_Buff)
E(OP_CancelTrade)
E(OP_ChannelMessage)
E(OP_CharInventory)
E(OP_ClientUpdate)
E(OP_Consider)
@ -57,6 +58,7 @@ E(OP_ShopPlayerBuy)
E(OP_ShopPlayerSell)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnDoor)
E(OP_SpecialMesg)
E(OP_Stun)
E(OP_TargetBuffs)
E(OP_Track)
@ -81,6 +83,7 @@ D(OP_BazaarSearch)
D(OP_Buff)
D(OP_Bug)
D(OP_CastSpell)
D(OP_ChannelMessage)
D(OP_CharacterCreate)
D(OP_ClientUpdate)
D(OP_Consider)
@ -101,6 +104,7 @@ D(OP_ItemVerifyRequest)
D(OP_LoadSpellSet)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_PetCommands)
D(OP_RaidInvite)
D(OP_ReadBook)
D(OP_Save)

View File

@ -4409,7 +4409,6 @@ struct MercenaryAssign_Struct {
/*0012*/
};
}; //end namespace structs
}; //end namespace SoD

View File

@ -31,6 +31,12 @@ namespace SoF
static inline uint32 SoFToServerSlot(uint32 SoFSlot);
static inline uint32 SoFToServerCorpseSlot(uint32 SoFCorpse);
// server to client text link converter
static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink);
// client to server text link converter
static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink);
void Register(EQStreamIdentifier &into)
{
//create our opcode manager if we havent already
@ -278,6 +284,35 @@ namespace SoF
FINISH_ENCODE();
}
ENCODE(OP_ChannelMessage)
{
EQApplicationPacket *in = *p;
*p = nullptr;
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = emu->message;
std::string new_message;
ServerToSoFTextLink(new_message, old_message);
in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
memcpy(OutBuffer, __emu_buffer, sizeof(ChannelMessage_Struct));
OutBuffer += sizeof(ChannelMessage_Struct);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_CharInventory)
{
//consume the packet
@ -1296,7 +1331,7 @@ namespace SoF
strn0cpy(general->player_name, raid_create->leader_name, 64);
dest->FastQueuePacket(&outapp_create);
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_RaidUpdate)
@ -1363,7 +1398,7 @@ namespace SoF
dest->FastQueuePacket(&outapp);
}
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_ReadBook)
@ -1609,6 +1644,44 @@ namespace SoF
FINISH_ENCODE();
}
ENCODE(OP_SpecialMesg)
{
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = &emu->message[strlen(emu->sayer)];
std::string new_message;
ServerToSoFTextLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = 25 + strlen(emu->sayer) + new_message.length();
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_Stun)
{
ENCODE_LENGTH_EXACT(Stun_Struct);
@ -1645,7 +1718,7 @@ namespace SoF
for (int i = 0; i < EntryCount; ++i, ++eq, ++emu)
{
OUT(entityid);
OUT(padding002);
//OUT(padding002);
OUT(distance);
}
@ -2129,6 +2202,25 @@ namespace SoF
FINISH_DIRECT_DECODE();
}
DECODE(OP_ChannelMessage)
{
unsigned char *__eq_buffer = __packet->pBuffer;
std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)];
std::string new_message;
SoFToServerTextLink(new_message, old_message);
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
__packet->pBuffer = new unsigned char[__packet->size];
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
memcpy(emu, __eq_buffer, sizeof(ChannelMessage_Struct));
strcpy(emu->message, new_message.c_str());
delete[] __eq_buffer;
}
DECODE(OP_CharacterCreate)
{
DECODE_LENGTH_EXACT(structs::CharCreate_Struct);
@ -2345,6 +2437,89 @@ namespace SoF
FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)
{
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
switch (eq->command)
{
case 0x04:
emu->command = 0x00; // /pet health
break;
case 0x10:
emu->command = 0x01; // /pet leader
break;
case 0x07:
emu->command = 0x02; // /pet attack or Pet Window
break;
case 0x03: // Case Guessed
emu->command = 0x03; // /pet qattack
case 0x08:
emu->command = 0x04; // /pet follow or Pet Window
break;
case 0x05:
emu->command = 0x05; // /pet guard or Pet Window
break;
case 0x09:
emu->command = 0x07; // /pet sit or Pet Window
break;
case 0x0a:
emu->command = 0x08; // /pet stand or Pet Window
break;
case 0x06:
emu->command = 0x1e; // /pet guard me
break;
case 0x0f: // Case Made Up
emu->command = 0x09; // Stop?
break;
case 0x0b:
emu->command = 0x0d; // /pet taunt or Pet Window
break;
case 0x0e:
emu->command = 0x0e; // /pet notaunt or Pet Window
break;
case 0x0c:
emu->command = 0x0f; // /pet hold
break;
case 0x1b:
emu->command = 0x10; // /pet hold on
break;
case 0x1c:
emu->command = 0x11; // /pet hold off
break;
case 0x11:
emu->command = 0x12; // Slumber?
break;
case 0x12:
emu->command = 0x15; // /pet no cast
break;
case 0x0d: // Case Made Up
emu->command = 0x16; // Pet Window No Cast
break;
case 0x13:
emu->command = 0x18; // /pet focus
break;
case 0x19:
emu->command = 0x19; // /pet focus on
break;
case 0x1a:
emu->command = 0x1a; // /pet focus off
break;
case 0x01:
emu->command = 0x1c; // /pet back off
break;
case 0x02:
emu->command = 0x1d; // /pet get lost
break;
default:
emu->command = eq->command;
}
OUT(unknown);
FINISH_DIRECT_DECODE();
}
DECODE(OP_RaidInvite)
{
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
@ -3005,5 +3180,81 @@ namespace SoF
//uint32 ServerCorpse;
return (SoFCorpse - 1);
}
static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink)
{
const char delimiter = 0x12;
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
sofTextLink = serverTextLink;
return;
}
auto segments = SplitString(serverTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
// Diff: ^^^^^ ^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
if (segments[segment_iter].substr(41, 1) == "0")
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
else
new_segment.append("F");
new_segment.append(segments[segment_iter].substr(43).c_str());
sofTextLink.push_back(delimiter);
sofTextLink.append(new_segment.c_str());
sofTextLink.push_back(delimiter);
}
else {
sofTextLink.append(segments[segment_iter].c_str());
}
}
}
static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink)
{
const char delimiter = 0x12;
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sofTextLink.find(delimiter) == std::string::npos)) {
serverTextLink = sofTextLink;
return;
}
auto segments = SplitString(sofTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source)
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// Diff: ^^^^^ ^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append("00000");
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
new_segment.append("0");
new_segment.append(segments[segment_iter].substr(36).c_str());
serverTextLink.push_back(delimiter);
serverTextLink.append(new_segment.c_str());
serverTextLink.push_back(delimiter);
}
else {
serverTextLink.append(segments[segment_iter].c_str());
}
}
}
}
// end namespace SoF

View File

@ -177,6 +177,8 @@ namespace SoF {
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
static const uint32 POTION_BELT_SIZE = 5;
static const size_t TEXT_LINK_BODY_LENGTH = 50;
}
namespace limits {

View File

@ -8,6 +8,7 @@ E(OP_BazaarSearch)
E(OP_BecomeTrader)
E(OP_Buff)
E(OP_CancelTrade)
E(OP_ChannelMessage)
E(OP_CharInventory)
E(OP_ClientUpdate)
E(OP_Consider)
@ -50,6 +51,7 @@ E(OP_SendZonepoints)
E(OP_ShopPlayerSell)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnDoor)
E(OP_SpecialMesg)
E(OP_Stun)
E(OP_Track)
E(OP_Trader)
@ -70,6 +72,7 @@ D(OP_AugmentInfo)
D(OP_AugmentItem)
D(OP_Buff)
D(OP_CastSpell)
D(OP_ChannelMessage)
D(OP_CharacterCreate)
D(OP_ClientUpdate)
D(OP_Consider)
@ -85,6 +88,7 @@ D(OP_ItemLinkClick)
D(OP_ItemVerifyRequest)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_PetCommands)
D(OP_RaidInvite)
D(OP_ReadBook)
D(OP_Save)

View File

@ -2624,8 +2624,8 @@ struct MobHealth
};
struct Track_Struct {
uint16 entityid;
uint16 padding002;
uint32 entityid;
//uint16 padding002;
float distance;
};
@ -4115,18 +4115,7 @@ struct AltCurrencySellItem_Struct {
/*010*/ uint32 cost;
};
}; //end namespace structs
}; //end namespace SoF
#endif /*SoF_STRUCTS_H_*/

View File

@ -7,6 +7,7 @@
#include "../races.h"
#include "../eq_packet_structs.h"
#include "../misc_functions.h"
#include "../string_util.h"
#include "../item.h"
#include "titanium_structs.h"
@ -28,6 +29,12 @@ namespace Titanium
static inline uint32 TitaniumToServerSlot(int16 TitaniumSlot);
static inline uint32 TitaniumToServerCorpseSlot(int16 TitaniumCorpse);
// server to client text link converter
static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink);
// client to server text link converter
static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink);
void Register(EQStreamIdentifier &into)
{
//create our opcode manager if we havent already
@ -220,6 +227,35 @@ namespace Titanium
FINISH_ENCODE();
}
ENCODE(OP_ChannelMessage)
{
EQApplicationPacket *in = *p;
*p = nullptr;
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = emu->message;
std::string new_message;
ServerToTitaniumTextLink(new_message, old_message);
in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
memcpy(OutBuffer, __emu_buffer, sizeof(ChannelMessage_Struct));
OutBuffer += sizeof(ChannelMessage_Struct);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_CharInventory)
{
//consume the packet
@ -1070,6 +1106,44 @@ namespace Titanium
FINISH_ENCODE();
}
ENCODE(OP_SpecialMesg)
{
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = &emu->message[strlen(emu->sayer)];
std::string new_message;
ServerToTitaniumTextLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = 25 + strlen(emu->sayer) + new_message.length();
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_Track)
{
EQApplicationPacket *in = *p;
@ -1094,7 +1168,7 @@ namespace Titanium
for (int i = 0; i < EntryCount; ++i, ++eq, ++emu)
{
OUT(entityid);
OUT(padding002);
//OUT(padding002);
OUT(distance);
}
@ -1371,6 +1445,25 @@ namespace Titanium
FINISH_DIRECT_DECODE();
}
DECODE(OP_ChannelMessage)
{
unsigned char *__eq_buffer = __packet->pBuffer;
std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)];
std::string new_message;
TitaniumToServerTextLink(new_message, old_message);
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
__packet->pBuffer = new unsigned char[__packet->size];
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
memcpy(emu, __eq_buffer, sizeof(ChannelMessage_Struct));
strcpy(emu->message, new_message.c_str());
delete[] __eq_buffer;
}
DECODE(OP_CharacterCreate)
{
DECODE_LENGTH_EXACT(structs::CharCreate_Struct);
@ -1538,6 +1631,89 @@ namespace Titanium
FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)
{
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
switch (eq->command)
{
case 0x04:
emu->command = 0x00; // /pet health
break;
case 0x10:
emu->command = 0x01; // /pet leader
break;
case 0x07:
emu->command = 0x02; // /pet attack or Pet Window
break;
case 0x03: // Case Guessed
emu->command = 0x03; // /pet qattack
case 0x08:
emu->command = 0x04; // /pet follow or Pet Window
break;
case 0x05:
emu->command = 0x05; // /pet guard or Pet Window
break;
case 0x09:
emu->command = 0x07; // /pet sit or Pet Window
break;
case 0x0a:
emu->command = 0x08; // /pet stand or Pet Window
break;
case 0x06:
emu->command = 0x1e; // /pet guard me
break;
case 0x0f: // Case Made Up
emu->command = 0x09; // Stop?
break;
case 0x0b:
emu->command = 0x0d; // /pet taunt or Pet Window
break;
case 0x0e:
emu->command = 0x0e; // /pet notaunt or Pet Window
break;
case 0x0c:
emu->command = 0x0f; // /pet hold
break;
case 0x1b:
emu->command = 0x10; // /pet hold on
break;
case 0x1c:
emu->command = 0x11; // /pet hold off
break;
case 0x11:
emu->command = 0x12; // Slumber?
break;
case 0x12:
emu->command = 0x15; // /pet no cast
break;
case 0x0d: // Case Made Up
emu->command = 0x16; // Pet Window No Cast
break;
case 0x13:
emu->command = 0x18; // /pet focus
break;
case 0x19:
emu->command = 0x19; // /pet focus on
break;
case 0x1a:
emu->command = 0x1a; // /pet focus off
break;
case 0x01:
emu->command = 0x1c; // /pet back off
break;
case 0x02:
emu->command = 0x1d; // /pet get lost
break;
default:
emu->command = eq->command;
}
OUT(unknown);
FINISH_DIRECT_DECODE();
}
DECODE(OP_ReadBook)
{
// no apparent slot translation needed -U
@ -1763,5 +1939,83 @@ namespace Titanium
//uint32 ServerCorpse;
return TitaniumCorpse;
}
static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink)
{
const char delimiter = 0x12;
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
titaniumTextLink = serverTextLink;
return;
}
auto segments = SplitString(serverTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45)
// Diff: ^^^^^ ^ ^^^^^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
if (segments[segment_iter].substr(41, 1) == "0")
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
else
new_segment.append("F");
new_segment.append(segments[segment_iter].substr(48).c_str());
titaniumTextLink.push_back(delimiter);
titaniumTextLink.append(new_segment.c_str());
titaniumTextLink.push_back(delimiter);
}
else {
titaniumTextLink.append(segments[segment_iter].c_str());
}
}
}
static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink)
{
const char delimiter = 0x12;
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (titaniumTextLink.find(delimiter) == std::string::npos)) {
serverTextLink = titaniumTextLink;
return;
}
auto segments = SplitString(titaniumTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 32 36 37 (Source)
// 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// Diff: ^^^^^ ^ ^^^^^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append("00000");
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
new_segment.append("0");
new_segment.append(segments[segment_iter].substr(36, 1).c_str());
new_segment.append("00000");
new_segment.append(segments[segment_iter].substr(37).c_str());
serverTextLink.push_back(delimiter);
serverTextLink.append(new_segment.c_str());
serverTextLink.push_back(delimiter);
}
else {
serverTextLink.append(segments[segment_iter].c_str());
}
}
}
}
// end namespace Titanium

View File

@ -176,6 +176,8 @@ namespace Titanium {
static const uint32 BANDOLIERS_COUNT = 4; // count = number of bandolier instances
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
static const uint32 POTION_BELT_SIZE = 4;
static const size_t TEXT_LINK_BODY_LENGTH = 45;
}
namespace limits {

View File

@ -4,6 +4,7 @@ E(OP_AdventureMerchantSell)
E(OP_ApplyPoison)
E(OP_BazaarSearch)
E(OP_BecomeTrader)
E(OP_ChannelMessage)
E(OP_CharInventory)
E(OP_DeleteCharge)
E(OP_DeleteItem)
@ -35,6 +36,7 @@ E(OP_RespondAA)
E(OP_SendCharInfo)
E(OP_SendAATable)
E(OP_ShopPlayerSell)
E(OP_SpecialMesg)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
@ -49,6 +51,7 @@ D(OP_AdventureMerchantSell)
D(OP_ApplyPoison)
D(OP_AugmentItem)
D(OP_CastSpell)
D(OP_ChannelMessage)
D(OP_CharacterCreate)
D(OP_Consume)
D(OP_DeleteItem)
@ -59,6 +62,7 @@ D(OP_ItemLinkClick)
D(OP_LFGuild)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_PetCommands)
D(OP_ReadBook)
D(OP_SetServerFilter)
D(OP_ShopPlayerSell)

View File

@ -2319,8 +2319,8 @@ struct MobHealth
};
struct Track_Struct {
uint16 entityid;
uint16 padding002;
uint32 entityid;
//uint16 padding002;
float distance;
};
@ -3332,16 +3332,4 @@ struct LFGuild_GuildToggle_Struct
}; //end namespace structs
}; //end namespace Titanium
#endif /*Titanium_STRUCTS_H_*/

View File

@ -31,6 +31,12 @@ namespace Underfoot
static inline uint32 UnderfootToServerSlot(uint32 UnderfootSlot);
static inline uint32 UnderfootToServerCorpseSlot(uint32 UnderfootCorpse);
// server to client text link converter
static inline void ServerToUnderfootTextLink(std::string& underfootTextLink, const std::string& serverTextLink);
// client to server text link converter
static inline void UnderfootToServerTextLink(std::string& serverTextLink, const std::string& underfootTextLink);
void Register(EQStreamIdentifier &into)
{
//create our opcode manager if we havent already
@ -432,7 +438,12 @@ namespace Underfoot
unsigned char *__emu_buffer = in->pBuffer;
in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
std::string old_message = emu->message;
std::string new_message;
ServerToUnderfootTextLink(new_message, old_message);
//in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39;
in->pBuffer = new unsigned char[in->size];
@ -446,7 +457,7 @@ namespace Underfoot
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->message);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
@ -1924,7 +1935,7 @@ namespace Underfoot
strn0cpy(general->player_name, raid_create->leader_name, 64);
dest->FastQueuePacket(&outapp_create);
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_RaidUpdate)
@ -1991,7 +2002,7 @@ namespace Underfoot
dest->FastQueuePacket(&outapp);
}
delete[] __emu_buffer;
safe_delete(inapp);
}
ENCODE(OP_ReadBook)
@ -2298,6 +2309,44 @@ namespace Underfoot
FINISH_ENCODE();
}
ENCODE(OP_SpecialMesg)
{
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
unsigned char *__emu_buffer = in->pBuffer;
std::string old_message = &emu->message[strlen(emu->sayer)];
std::string new_message;
ServerToUnderfootTextLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = 25 + strlen(emu->sayer) + new_message.length();
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_Stun)
{
ENCODE_LENGTH_EXACT(Stun_Struct);
@ -2348,9 +2397,9 @@ namespace Underfoot
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
}
delete[] __emu_buffer;
@ -3036,7 +3085,13 @@ namespace Underfoot
uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
std::string old_message = InBuffer;
std::string new_message;
UnderfootToServerTextLink(new_message, old_message);
//__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
__packet->pBuffer = new unsigned char[__packet->size];
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
@ -3045,7 +3100,7 @@ namespace Underfoot
emu->language = Language;
emu->chan_num = Channel;
emu->skill_in_language = Skill;
strcpy(emu->message, InBuffer);
strcpy(emu->message, new_message.c_str());
delete[] __eq_buffer;
}
@ -3364,57 +3419,8 @@ namespace Underfoot
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
switch (eq->command)
{
case 0x00:
emu->command = 0x04; // Health
break;
case 0x01:
emu->command = 0x10; // Leader
break;
case 0x02:
emu->command = 0x07; // Attack
break;
case 0x04:
emu->command = 0x08; // Follow
break;
case 0x05:
emu->command = 0x05; // Guard
break;
case 0x06:
emu->command = 0x09; // Sit. Needs work. This appears to be a toggle between Sit/Stand now.
break;
case 0x0c:
emu->command = 0x0b; // Taunt
break;
case 0x0f:
emu->command = 0x0c; // Hold
break;
case 0x10:
emu->command = 0x1b; // Hold on
break;
case 0x11:
emu->command = 0x1c; // Hold off
break;
case 0x1c:
emu->command = 0x01; // Back
break;
case 0x1d:
emu->command = 0x02; // Leave/Go Away
break;
case 0x15:
emu->command = 0x12; // No Cast - /command
break;
case 0x16:
emu->command = 0x12; // No Cast - Pet Window
break;
case 0x18:
emu->command = 0x13; // Focus - Pet Window
break;
default:
emu->command = eq->command;
}
OUT(unknown);
IN(command);
IN(unknown);
FINISH_DIRECT_DECODE();
}
@ -4155,5 +4161,81 @@ namespace Underfoot
//uint32 ServerCorpse;
return (UnderfootCorpse - 1);
}
static inline void ServerToUnderfootTextLink(std::string& underfootTextLink, const std::string& serverTextLink)
{
const char delimiter = 0x12;
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
underfootTextLink = serverTextLink;
return;
}
auto segments = SplitString(serverTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
// Diff: ^^^^^ ^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
if (segments[segment_iter].substr(41, 1) == "0")
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
else
new_segment.append("F");
new_segment.append(segments[segment_iter].substr(43).c_str());
underfootTextLink.push_back(delimiter);
underfootTextLink.append(new_segment.c_str());
underfootTextLink.push_back(delimiter);
}
else {
underfootTextLink.append(segments[segment_iter].c_str());
}
}
}
static inline void UnderfootToServerTextLink(std::string& serverTextLink, const std::string& underfootTextLink)
{
const char delimiter = 0x12;
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (underfootTextLink.find(delimiter) == std::string::npos)) {
serverTextLink = underfootTextLink;
return;
}
auto segments = SplitString(underfootTextLink, delimiter);
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
std::string new_segment;
// Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source)
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
// Diff: ^^^^^ ^
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
new_segment.append("00000");
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
new_segment.append("0");
new_segment.append(segments[segment_iter].substr(36).c_str());
serverTextLink.push_back(delimiter);
serverTextLink.append(new_segment.c_str());
serverTextLink.push_back(delimiter);
}
else {
serverTextLink.append(segments[segment_iter].c_str());
}
}
}
}
// end namespace Underfoot

View File

@ -177,6 +177,8 @@ namespace Underfoot {
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
static const uint32 POTION_BELT_SIZE = 5;
static const size_t TEXT_LINK_BODY_LENGTH = 50;
}
namespace limits {

View File

@ -65,6 +65,7 @@ E(OP_ShopPlayerSell)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnAppearance)
E(OP_SpawnDoor)
E(OP_SpecialMesg)
E(OP_Stun)
E(OP_TargetBuffs)
E(OP_Track)

View File

@ -135,7 +135,7 @@ bool PersistentTimer::Load(Database *db) {
auto results = db->QueryDatabase(query);
if (!results.Success()) {
#if EQDEBUG > 5
LogFile->write(EQEMuLog::Error, "Error in PersistentTimer::Load, error: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in PersistentTimer::Load, error: %s", results.ErrorMessage().c_str());
#endif
return false;
}
@ -168,7 +168,7 @@ bool PersistentTimer::Store(Database *db) {
auto results = db->QueryDatabase(query);
if (!results.Success()) {
#if EQDEBUG > 5
LogFile->write(EQEMuLog::Error, "Error in PersistentTimer::Store, error: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in PersistentTimer::Store, error: %s", results.ErrorMessage().c_str());
#endif
return false;
}
@ -188,7 +188,7 @@ bool PersistentTimer::Clear(Database *db) {
auto results = db->QueryDatabase(query);
if (!results.Success()) {
#if EQDEBUG > 5
LogFile->write(EQEMuLog::Error, "Error in PersistentTimer::Clear, error: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in PersistentTimer::Clear, error: %s", results.ErrorMessage().c_str());
#endif
return false;
}
@ -200,7 +200,7 @@ bool PersistentTimer::Clear(Database *db) {
/* This function checks if the timer triggered */
bool PersistentTimer::Expired(Database *db, bool iReset) {
if (this == nullptr) {
LogFile->write(EQEMuLog::Error, "Null timer during ->Check()!?\n");
LogFile->write(EQEmuLog::Error, "Null timer during ->Check()!?\n");
return(true);
}
uint32 current_time = get_current_time();
@ -292,7 +292,7 @@ bool PTimerList::Load(Database *db) {
auto results = db->QueryDatabase(query);
if (!results.Success()) {
#if EQDEBUG > 5
LogFile->write(EQEMuLog::Error, "Error in PersistentTimer::Load, error: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in PersistentTimer::Load, error: %s", results.ErrorMessage().c_str());
#endif
return false;
}
@ -351,7 +351,7 @@ bool PTimerList::Clear(Database *db) {
auto results = db->QueryDatabase(query);
if (!results.Success()) {
#if EQDEBUG > 5
LogFile->write(EQEMuLog::Error, "Error in PersistentTimer::Clear, error: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in PersistentTimer::Clear, error: %s", results.ErrorMessage().c_str());
#endif
return false;
}
@ -443,7 +443,7 @@ bool PTimerList::ClearOffline(Database *db, uint32 char_id, pTimerType type) {
auto results = db->QueryDatabase(query);
if (!results.Success()) {
#if EQDEBUG > 5
LogFile->write(EQEMuLog::Error, "Error in PTimerList::ClearOffline, error: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in PTimerList::ClearOffline, error: %s", results.ErrorMessage().c_str());
#endif
return false;
}

View File

@ -282,7 +282,7 @@ bool RuleManager::LoadRules(Database *db, const char *ruleset) {
auto results = db->QueryDatabase(query);
if (!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error in LoadRules query %s: %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in LoadRules query %s: %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -329,7 +329,7 @@ int RuleManager::GetRulesetID(Database *db, const char *rulesetname) {
safe_delete_array(rst);
auto results = db->QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadRules query %s: %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in LoadRules query %s: %s", query.c_str(), results.ErrorMessage().c_str());
return -1;
}
@ -369,7 +369,7 @@ std::string RuleManager::GetRulesetName(Database *db, int id) {
auto results = db->QueryDatabase(query);
if (!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error in LoadRules query %s: %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in LoadRules query %s: %s", query.c_str(), results.ErrorMessage().c_str());
return "";
}
@ -390,7 +390,7 @@ bool RuleManager::ListRulesets(Database *db, std::map<int, std::string> &into) {
auto results = db->QueryDatabase(query);
if (results.Success())
{
LogFile->write(EQEMuLog::Error, "Error in ListRulesets query %s: %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ListRulesets query %s: %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}

View File

@ -124,7 +124,7 @@ bool SharedDatabase::VerifyInventory(uint32 account_id, int16 slot_id, const Ite
account_id, slot_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error runing inventory verification query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error runing inventory verification query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
//returning true is less harmful in the face of a query error
return true;
}
@ -177,6 +177,7 @@ bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 s
}
bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, int16 slot_id) {
// need to check 'inst' argument for valid pointer
uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM };
if (inst->IsType(ItemClassCommon))
@ -213,7 +214,7 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i
}
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "UpdateInventorySlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "UpdateInventorySlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -221,6 +222,7 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i
}
bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst, int16 slot_id) {
// need to check 'inst' argument for valid pointer
uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM };
if (inst->IsType(ItemClassCommon))
@ -256,7 +258,7 @@ bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst,
}
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "UpdateSharedBankSlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "UpdateSharedBankSlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -269,7 +271,7 @@ bool SharedDatabase::DeleteInventorySlot(uint32 char_id, int16 slot_id) {
std::string query = StringFormat("DELETE FROM inventory WHERE charid = %i AND slotid = %i", char_id, slot_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "DeleteInventorySlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "DeleteInventorySlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -282,7 +284,7 @@ bool SharedDatabase::DeleteInventorySlot(uint32 char_id, int16 slot_id) {
char_id, base_slot_id, (base_slot_id+10));
results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "DeleteInventorySlot, bags query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "DeleteInventorySlot, bags query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -297,7 +299,7 @@ bool SharedDatabase::DeleteSharedBankSlot(uint32 char_id, int16 slot_id) {
std::string query = StringFormat("DELETE FROM sharedbank WHERE acctid=%i AND slotid=%i", account_id, slot_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "DeleteSharedBankSlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "DeleteSharedBankSlot query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -311,7 +313,7 @@ bool SharedDatabase::DeleteSharedBankSlot(uint32 char_id, int16 slot_id) {
account_id, base_slot_id, (base_slot_id+10));
results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "DeleteSharedBankSlot, bags query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "DeleteSharedBankSlot, bags query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -401,7 +403,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) {
"FROM sharedbank WHERE acctid=%i", id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Database::GetSharedBank(uint32 account_id): %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Database::GetSharedBank(uint32 account_id): %s", results.ErrorMessage().c_str());
return false;
}
@ -421,7 +423,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) {
const Item_Struct* item = GetItem(item_id);
if (!item) {
LogFile->write(EQEMuLog::Error,
LogFile->write(EQEmuLog::Error,
"Warning: %s %i has an invalid item_id %i in inventory slot %i",
((is_charid==true) ? "charid" : "acctid"), id, item_id, slot_id);
continue;
@ -430,7 +432,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) {
int16 put_slot_id = INVALID_INDEX;
ItemInst* inst = CreateBaseItem(item, charges);
if (item->ItemClass == ItemClassCommon) {
if (inst && item->ItemClass == ItemClassCommon) {
for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
if (aug[i]) {
inst->PutAugment(this, i, aug[i]);
@ -471,7 +473,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) {
if (put_slot_id != INVALID_INDEX)
continue;
LogFile->write(EQEMuLog::Error, "Warning: Invalid slot_id for item in shared bank inventory: %s=%i, item_id=%i, slot_id=%i",
LogFile->write(EQEmuLog::Error, "Warning: Invalid slot_id for item in shared bank inventory: %s=%i, item_id=%i, slot_id=%i",
((is_charid==true)? "charid": "acctid"), id, item_id, slot_id);
if (is_charid)
@ -490,8 +492,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) {
"FROM inventory WHERE charid = %i ORDER BY slotid", char_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "GetInventory query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEMuLog::Error, "If you got an error related to the 'instnodrop' field, run the following SQL Queries:\nalter table inventory add instnodrop tinyint(1) unsigned default 0 not null;\n");
LogFile->write(EQEmuLog::Error, "GetInventory query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "If you got an error related to the 'instnodrop' field, run the following SQL Queries:\nalter table inventory add instnodrop tinyint(1) unsigned default 0 not null;\n");
return false;
}
@ -519,7 +521,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) {
const Item_Struct* item = GetItem(item_id);
if (!item) {
LogFile->write(EQEMuLog::Error,"Warning: charid %i has an invalid item_id %i in inventory slot %i", char_id, item_id, slot_id);
LogFile->write(EQEmuLog::Error,"Warning: charid %i has an invalid item_id %i in inventory slot %i", char_id, item_id, slot_id);
continue;
}
@ -527,6 +529,9 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) {
ItemInst* inst = CreateBaseItem(item, charges);
if (inst == nullptr)
continue;
if(row[11]) {
std::string data_str(row[11]);
std::string idAsString;
@ -576,19 +581,25 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) {
inst->PutAugment(this, i, aug[i]);
if (slot_id >= 8000 && slot_id <= 8999)
{
put_slot_id = inv->PushCursor(*inst);
else if (slot_id >= 3111 && slot_id <= 3179) {
}
else if (slot_id >= 3111 && slot_id <= 3179)
{
// Admins: please report any occurrences of this error
LogFile->write(EQEMuLog::Error, "Warning: Defunct location for item in inventory: charid=%i, item_id=%i, slot_id=%i .. pushing to cursor...", char_id, item_id, slot_id);
LogFile->write(EQEmuLog::Error, "Warning: Defunct location for item in inventory: charid=%i, item_id=%i, slot_id=%i .. pushing to cursor...", char_id, item_id, slot_id);
put_slot_id = inv->PushCursor(*inst);
} else
put_slot_id = inv->PutItem(slot_id, *inst);
}
else
{
put_slot_id = inv->PutItem(slot_id, *inst);
}
safe_delete(inst);
// Save ptr to item in inventory
if (put_slot_id == INVALID_INDEX) {
LogFile->write(EQEMuLog::Error, "Warning: Invalid slot_id for item in inventory: charid=%i, item_id=%i, slot_id=%i",char_id, item_id, slot_id);
LogFile->write(EQEmuLog::Error, "Warning: Invalid slot_id for item in inventory: charid=%i, item_id=%i, slot_id=%i",char_id, item_id, slot_id);
}
}
@ -606,8 +617,8 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv)
name, account_id);
auto results = QueryDatabase(query);
if (!results.Success()){
LogFile->write(EQEMuLog::Error, "GetInventory query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEMuLog::Error, "If you got an error related to the 'instnodrop' field, run the following SQL Queries:\nalter table inventory add instnodrop tinyint(1) unsigned default 0 not null;\n");
LogFile->write(EQEmuLog::Error, "GetInventory query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "If you got an error related to the 'instnodrop' field, run the following SQL Queries:\nalter table inventory add instnodrop tinyint(1) unsigned default 0 not null;\n");
return false;
}
@ -637,6 +648,10 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv)
continue;
ItemInst* inst = CreateBaseItem(item, charges);
if (inst == nullptr)
continue;
inst->SetAttuned(instnodrop);
if(row[11]) {
@ -689,7 +704,7 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv)
// Save ptr to item in inventory
if (put_slot_id == INVALID_INDEX)
LogFile->write(EQEMuLog::Error, "Warning: Invalid slot_id for item in inventory: name=%s, acctid=%i, item_id=%i, slot_id=%i", name, account_id, item_id, slot_id);
LogFile->write(EQEmuLog::Error, "Warning: Invalid slot_id for item in inventory: name=%s, acctid=%i, item_id=%i, slot_id=%i", name, account_id, item_id, slot_id);
}
@ -705,7 +720,7 @@ void SharedDatabase::GetItemsCount(int32 &item_count, uint32 &max_id) {
const std::string query = "SELECT MAX(id), count(*) FROM items";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetItemsCount '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetItemsCount '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -745,7 +760,7 @@ bool SharedDatabase::LoadItems() {
items_hash = new EQEmu::FixedMemoryHashSet<Item_Struct>(reinterpret_cast<uint8*>(items_mmf->Get()), size);
mutex.Unlock();
} catch(std::exception& ex) {
LogFile->write(EQEMuLog::Error, "Error Loading Items: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Error Loading Items: %s", ex.what());
return false;
}
@ -790,7 +805,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
"updated FROM items ORDER BY id";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "LoadItems '%s', %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "LoadItems '%s', %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1003,7 +1018,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
try {
hash.insert(item.ID, item);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "Database::LoadItems: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Database::LoadItems: %s", ex.what());
break;
}
}
@ -1064,7 +1079,7 @@ std::string SharedDatabase::GetBook(const char *txtfile)
}
if (results.RowCount() == 0) {
LogFile->write(EQEMuLog::Error, "No book to send, (%s)", txtfile);
LogFile->write(EQEmuLog::Error, "No book to send, (%s)", txtfile);
txtout.assign(" ",1);
return txtout;
}
@ -1082,7 +1097,7 @@ void SharedDatabase::GetFactionListInfo(uint32 &list_count, uint32 &max_lists) {
const std::string query = "SELECT COUNT(*), MAX(id) FROM npc_faction";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error getting npc faction info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting npc faction info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1117,7 +1132,7 @@ void SharedDatabase::LoadNPCFactionLists(void *data, uint32 size, uint32 list_co
"ON npc_faction.id = npc_faction_entries.npc_faction_id ORDER BY npc_faction.id;";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error getting npc faction info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting npc faction info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1183,7 +1198,7 @@ bool SharedDatabase::LoadNPCFactionLists() {
faction_hash = new EQEmu::FixedMemoryHashSet<NPCFactionList>(reinterpret_cast<uint8*>(faction_mmf->Get()), size);
mutex.Unlock();
} catch(std::exception& ex) {
LogFile->write(EQEMuLog::Error, "Error Loading npc factions: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Error Loading npc factions: %s", ex.what());
return false;
}
@ -1195,9 +1210,17 @@ ItemInst* SharedDatabase::CreateItem(uint32 item_id, int16 charges, uint32 aug1,
{
const Item_Struct* item = nullptr;
ItemInst* inst = nullptr;
item = GetItem(item_id);
if (item) {
inst = CreateBaseItem(item, charges);
if (inst == nullptr) {
LogFile->write(EQEmuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateItem()");
LogFile->write(EQEmuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
return nullptr;
}
inst->PutAugment(this, 0, aug1);
inst->PutAugment(this, 1, aug2);
inst->PutAugment(this, 2, aug3);
@ -1217,6 +1240,13 @@ ItemInst* SharedDatabase::CreateItem(const Item_Struct* item, int16 charges, uin
ItemInst* inst = nullptr;
if (item) {
inst = CreateBaseItem(item, charges);
if (inst == nullptr) {
LogFile->write(EQEmuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateItem()");
LogFile->write(EQEmuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
return nullptr;
}
inst->PutAugment(this, 0, aug1);
inst->PutAugment(this, 1, aug2);
inst->PutAugment(this, 2, aug3);
@ -1242,6 +1272,12 @@ ItemInst* SharedDatabase::CreateBaseItem(const Item_Struct* item, int16 charges)
inst = new ItemInst(item, charges);
if (inst == nullptr) {
LogFile->write(EQEmuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateBaseItem()");
LogFile->write(EQEmuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
return nullptr;
}
if(item->CharmFileID != 0 || (item->LoreGroup >= 1000 && item->LoreGroup != -1)) {
inst->Initialize(this);
}
@ -1308,7 +1344,7 @@ bool SharedDatabase::LoadSkillCaps() {
mutex.Unlock();
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "Error loading skill caps: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Error loading skill caps: %s", ex.what());
return false;
}
@ -1324,7 +1360,7 @@ void SharedDatabase::LoadSkillCaps(void *data) {
const std::string query = "SELECT skillID, class, level, cap FROM skill_caps ORDER BY skillID, class, level";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error loading skill caps from database: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error loading skill caps from database: %s", results.ErrorMessage().c_str());
return;
}
@ -1426,7 +1462,7 @@ void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpe
"AND `spellid` <= %i", iMaxSpellID);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadDamageShieldTypes: %s %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in LoadDamageShieldTypes: %s %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1622,7 +1658,7 @@ int SharedDatabase::GetMaxBaseDataLevel() {
const std::string query = "SELECT MAX(level) FROM base_data";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetMaxBaseDataLevel query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetMaxBaseDataLevel query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
return -1;
}
@ -1655,7 +1691,7 @@ bool SharedDatabase::LoadBaseData() {
mutex.Unlock();
} catch(std::exception& ex) {
LogFile->write(EQEMuLog::Error, "Error Loading Base Data: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Error Loading Base Data: %s", ex.what());
return false;
}
@ -1668,7 +1704,7 @@ void SharedDatabase::LoadBaseData(void *data, int max_level) {
const std::string query = "SELECT * FROM base_data ORDER BY level, class ASC";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadBaseData query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in LoadBaseData query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1680,22 +1716,22 @@ void SharedDatabase::LoadBaseData(void *data, int max_level) {
cl = atoi(row[1]);
if(lvl <= 0) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.level <= 0, ignoring.");
LogFile->write(EQEmuLog::Error, "Non fatal error: base_data.level <= 0, ignoring.");
continue;
}
if(lvl >= max_level) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.level >= max_level, ignoring.");
LogFile->write(EQEmuLog::Error, "Non fatal error: base_data.level >= max_level, ignoring.");
continue;
}
if(cl <= 0) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.cl <= 0, ignoring.");
LogFile->write(EQEmuLog::Error, "Non fatal error: base_data.cl <= 0, ignoring.");
continue;
}
if(cl > 16) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.class > 16, ignoring.");
LogFile->write(EQEmuLog::Error, "Non fatal error: base_data.class > 16, ignoring.");
continue;
}
@ -1748,7 +1784,7 @@ void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot
const std::string query = "SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM loottable_entries) FROM loottable";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error getting loot table info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting loot table info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1770,7 +1806,7 @@ void SharedDatabase::GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_d
const std::string query = "SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM lootdrop_entries) FROM lootdrop";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error getting loot table info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting loot table info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1796,7 +1832,7 @@ void SharedDatabase::LoadLootTables(void *data, uint32 size) {
"ON loottable.id = loottable_entries.loottable_id ORDER BY id";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error getting loot table info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting loot table info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1850,7 +1886,7 @@ void SharedDatabase::LoadLootDrops(void *data, uint32 size) {
"ON lootdrop.id = lootdrop_entries.lootdrop_id ORDER BY lootdrop_id";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error getting loot drop info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting loot drop info from database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
}
uint32 current_id = 0;
@ -1904,7 +1940,7 @@ bool SharedDatabase::LoadLoot() {
loot_drop_mmf->Size());
mutex.Unlock();
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "Error loading loot: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Error loading loot: %s", ex.what());
return false;
}
@ -1920,7 +1956,7 @@ const LootTable_Struct* SharedDatabase::GetLootTable(uint32 loottable_id) {
return &loot_table_hash->at(loottable_id);
}
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "Could not get loot table: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Could not get loot table: %s", ex.what());
}
return nullptr;
}
@ -1934,7 +1970,7 @@ const LootDrop_Struct* SharedDatabase::GetLootDrop(uint32 lootdrop_id) {
return &loot_drop_hash->at(lootdrop_id);
}
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "Could not get loot drop: %s", ex.what());
LogFile->write(EQEmuLog::Error, "Could not get loot drop: %s", ex.what());
}
return nullptr;
}

View File

@ -43,7 +43,7 @@ void TimeoutManager::CheckTimeouts() {
Timeoutable *it = *cur;
if(it->next_check.Check()) {
#ifdef TIMEOUT_DEBUG
LogFile->write(EQEMuLog::Debug, "Checking timeout on 0x%x\n", it);
LogFile->write(EQEmuLog::Debug, "Checking timeout on 0x%x\n", it);
#endif
it->CheckTimeout();
}
@ -58,13 +58,13 @@ void TimeoutManager::AddMember(Timeoutable *who) {
DeleteMember(who); //just in case... prolly not needed.
members.push_back(who);
#ifdef TIMEOUT_DEBUG
LogFile->write(EQEMuLog::Debug, "Adding timeoutable 0x%x\n", who);
LogFile->write(EQEmuLog::Debug, "Adding timeoutable 0x%x\n", who);
#endif
}
void TimeoutManager::DeleteMember(Timeoutable *who) {
#ifdef TIMEOUT_DEBUG
LogFile->write(EQEMuLog::Debug, "Removing timeoutable 0x%x\n", who);
LogFile->write(EQEmuLog::Debug, "Removing timeoutable 0x%x\n", who);
#endif
std::vector<Timeoutable *>::iterator cur,end;
cur = members.begin();

View File

@ -141,11 +141,13 @@ uint32 Timer::GetRemainingTime() {
}
}
void Timer::SetAtTrigger(uint32 in_set_at_trigger, bool iEnableIfDisabled) {
void Timer::SetAtTrigger(uint32 in_set_at_trigger, bool iEnableIfDisabled, bool ChangeTimerTime) {
set_at_trigger = in_set_at_trigger;
if (!Enabled() && iEnableIfDisabled) {
Enable();
}
if (ChangeTimerTime)
timer_time = set_at_trigger;
}
void Timer::Trigger()

View File

@ -43,7 +43,7 @@ public:
inline const uint32& GetTimerTime() { return timer_time; }
inline const uint32& GetSetAtTrigger() { return set_at_trigger; }
void Trigger();
void SetAtTrigger(uint32 set_at_trigger, bool iEnableIfDisabled = false);
void SetAtTrigger(uint32 set_at_trigger, bool iEnableIfDisabled = false, bool ChangeTimerTime = false);
inline bool Enabled() { return enabled; }
inline uint32 GetStartTime() { return(start_time); }

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 9062
#define CURRENT_BINARY_DATABASE_VERSION 9066
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
#ifndef WIN32

View File

@ -537,6 +537,7 @@ namespace detail
};
// Needed because of some strange ADL issues.
#if BOOST_VERSION < 105700
#define LUABIND_OPERATOR_ADL_WKND(op) \
inline bool operator op( \
@ -557,7 +558,8 @@ namespace detail
LUABIND_OPERATOR_ADL_WKND(!=)
#undef LUABIND_OPERATOR_ADL_WKND
#endif
} // namespace detail
namespace adl

View File

@ -68,14 +68,14 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(host, user, passwd, database, port, &errnum, errbuf))
{
LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf);
LogFile->write(EQEmuLog::Error, "Failed to connect to database: Error: %s", errbuf);
HandleMysqlError(errnum);
return false;
}
else
{
LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port);
LogFile->write(EQEmuLog::Status, "Using database '%s' at %s:%d",database,host,port);
return true;
}
}

View File

@ -35,22 +35,22 @@ int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformSharedMemory);
set_exception_handler();
LogFile->write(EQEMuLog::Status, "Shared Memory Loader Program");
LogFile->write(EQEmuLog::Status, "Shared Memory Loader Program");
if(!EQEmuConfig::LoadConfig()) {
LogFile->write(EQEMuLog::Error, "Unable to load configuration file.");
LogFile->write(EQEmuLog::Error, "Unable to load configuration file.");
return 1;
}
const EQEmuConfig *config = EQEmuConfig::get();
if(!load_log_settings(config->LogSettingsFile.c_str())) {
LogFile->write(EQEMuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
LogFile->write(EQEmuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
}
SharedDatabase database;
LogFile->write(EQEMuLog::Status, "Connecting to database...");
LogFile->write(EQEmuLog::Status, "Connecting to database...");
if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(),
config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) {
LogFile->write(EQEMuLog::Error, "Unable to connect to the database, cannot continue without a "
LogFile->write(EQEmuLog::Error, "Unable to connect to the database, cannot continue without a "
"database connection");
return 1;
}
@ -109,61 +109,61 @@ int main(int argc, char **argv) {
}
if(load_all || load_items) {
LogFile->write(EQEMuLog::Status, "Loading items...");
LogFile->write(EQEmuLog::Status, "Loading items...");
try {
LoadItems(&database);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "%s", ex.what());
LogFile->write(EQEmuLog::Error, "%s", ex.what());
return 1;
}
}
if(load_all || load_factions) {
LogFile->write(EQEMuLog::Status, "Loading factions...");
LogFile->write(EQEmuLog::Status, "Loading factions...");
try {
LoadFactions(&database);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "%s", ex.what());
LogFile->write(EQEmuLog::Error, "%s", ex.what());
return 1;
}
}
if(load_all || load_loot) {
LogFile->write(EQEMuLog::Status, "Loading loot...");
LogFile->write(EQEmuLog::Status, "Loading loot...");
try {
LoadLoot(&database);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "%s", ex.what());
LogFile->write(EQEmuLog::Error, "%s", ex.what());
return 1;
}
}
if(load_all || load_skill_caps) {
LogFile->write(EQEMuLog::Status, "Loading skill caps...");
LogFile->write(EQEmuLog::Status, "Loading skill caps...");
try {
LoadSkillCaps(&database);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "%s", ex.what());
LogFile->write(EQEmuLog::Error, "%s", ex.what());
return 1;
}
}
if(load_all || load_spells) {
LogFile->write(EQEMuLog::Status, "Loading spells...");
LogFile->write(EQEmuLog::Status, "Loading spells...");
try {
LoadSpells(&database);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "%s", ex.what());
LogFile->write(EQEmuLog::Error, "%s", ex.what());
return 1;
}
}
if(load_all || load_bd) {
LogFile->write(EQEMuLog::Status, "Loading base data...");
LogFile->write(EQEmuLog::Status, "Loading base data...");
try {
LoadBaseData(&database);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "%s", ex.what());
LogFile->write(EQEmuLog::Error, "%s", ex.what());
return 1;
}
}

View File

@ -73,14 +73,14 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(host, user, passwd, database, port, &errnum, errbuf))
{
LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf);
LogFile->write(EQEmuLog::Error, "Failed to connect to database: Error: %s", errbuf);
HandleMysqlError(errnum);
return false;
}
else
{
LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port);
LogFile->write(EQEmuLog::Status, "Using database '%s' at %s:%d",database,host,port);
return true;
}
}

View File

@ -193,7 +193,7 @@ OP_Consent=0x1fd1
OP_ConsentDeny=0x7a45
OP_AutoFire=0x241e
OP_PetCommands=0x0159
OP_DeleteSpell=0x52e5
OP_DeleteSpell=0x3358
OP_Surname=0x0423
OP_ClearSurname=0x3fb0
OP_FaceChange=0x5578
@ -205,14 +205,14 @@ OP_CorpseDrag=0x0904
OP_CorpseDrop=0x7037
OP_Bug=0x73f4
OP_Feedback=0x5602
OP_Report=0x1414
OP_Report=0x6f14
OP_Damage=0x6f15
OP_ChannelMessage=0x2b2d
OP_Assist=0x4478
OP_AssistGroup=0x27f8
OP_MoveCoin=0x0bcf
OP_ZonePlayerToBind=0x08d8
OP_KeyRing=0x6857
OP_KeyRing=0x1219
OP_WhoAllRequest=0x674b
OP_WhoAllResponse=0x578c
OP_FriendsWho=0x3956
@ -249,7 +249,7 @@ OP_ItemLinkClick=0x4cef
OP_ItemPreview=0x6b5c
OP_NewSpawn=0x6097
OP_Track=0x17e5
OP_TrackTarget=0x0029
OP_TrackTarget=0x695e
OP_TrackUnknown=0x4577
OP_ClickDoor=0x3a8f
OP_MoveDoor=0x08e8
@ -263,7 +263,7 @@ OP_SafeFallSuccess=0x2219
OP_RezzComplete=0x760d
OP_RezzRequest=0x3c21
OP_RezzAnswer=0x701c
OP_Shielding=0x48c1
OP_Shielding=0x52e5
OP_RequestDuel=0x3af1
OP_MobRename=0x2c57
OP_AugmentItem=0x661b

View File

@ -155,6 +155,7 @@ sub ShowMenuPrompt {
2 => \&database_dump_compress,
3 => \&Run_Database_Check,
4 => \&AA_Fetch,
5 => \&OpCodes_Fetch,
0 => \&Exit,
);
@ -204,6 +205,7 @@ Database Management Menu (Please Select):
Ideal to perform before performing updates
3) $option[3]
4) AAs - Get Latest AA's from PEQ (This deletes AA's already in the database)
5) OPCodes - Download latest opcodes from repository
0) Exit
EO_MENU
@ -305,6 +307,36 @@ sub AA_Fetch{
print "\nDone...\n\n";
}
#::: Fetch Latest Opcodes
sub OpCodes_Fetch{
print "Pulling down latest opcodes...\n";
%opcodes = (
1 => ["opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/opcodes.conf"],
2 => ["mail_opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/mail_opcodes.conf"],
3 => ["Titanium", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Titanium.conf"],
4 => ["Secrets of Faydwer", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoF.conf"],
5 => ["Seeds of Destruction", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoD.conf"],
6 => ["Underfoot", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Underfoot.conf"],
7 => ["Rain of Fear", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF.conf"],
8 => ["Rain of Fear 2", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF2.conf"],
);
$loop = 1;
while($opcodes{$loop}[0]){
#::: Split the URL by the patches folder to get the file name from URL
@real_file = split("patches/", $opcodes{$loop}[1]);
$find = 0;
while($real_file[$find]){
$file_name = $real_file[$find];
$find++;
}
print "\nDownloading (" . $opcodes{$loop}[0] . ") File: '" . $file_name . "'...\n\n";
GetRemoteFile($opcodes{$loop}[1], $file_name);
$loop++;
}
print "\nDone...\n\n";
}
#::: Responsible for Database Upgrade Routines
sub Run_Database_Check{
#::: Run 2 - Running pending updates...

View File

@ -0,0 +1,39 @@
opendir my $dir, "logs" or die "Cannot open directory: $!";
my @files = readdir $dir;
closedir $dir;
$inc = 0;
foreach my $val (@files){
if($val=~/crash_zone/i){
$stl = 0;
$crash[$inc] = "";
my $file = "logs/" . $val;
open my $info, $file or die "Could not open $file: $!";
while( my $line = <$info>) {
if($line=~/CRTStartup/i){ $stl = 0; }
@data = split(']', $line);
if($stl == 1){ $crash[$inc] .= $data[1]; }
if($line=~/dbghelp.dll/i){ $stl = 1; }
}
close $info;
$inc++;
}
}
#::: Count Crash Occurrence first
$i = 0;
while($crash[$i]){
$crash_count[length($crash[$i])]++;
$unique_crash[length($crash[$i])] = $crash[$i];
$i++;
}
$i = 0;
while($crash[$i]){
if($unique_crash_tracker[length($crash[$i])] != 1){
print "Crash Occurrence " . $crash_count[length($crash[$i])] . " Time(s) Length (" . length($crash[$i]) . ") \n\n";
print $crash[$i] . "\n";
print "=========================================\n";
}
$unique_crash_tracker[length($crash[$i])] = 1;
$i++;
}

View File

@ -316,6 +316,10 @@
9060|2014_12_09_items_table_update.sql|SHOW COLUMNS FROM `items` LIKE 'herosforgemodel'|empty|
9061|2014_12_13_inventory_table_update.sql|SHOW COLUMNS FROM `inventory` LIKE 'ornament_hero_model'|empty|
9062|2014_12_15_multiple_table_updates.sql|SHOW COLUMNS FROM `items` LIKE 'augslot6type'|empty|
9063|2014_12_24_npc_types_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'd_melee_texture1'|empty|
9064|2014_12_24_npc_types_table_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'herosforgemodel'|empty|
9065|2014_12_26_merc_weaponinfo_table_update.sql|SHOW COLUMNS FROM `vwMercNpcTypes` LIKE 'd_melee_texture1'|empty|
9066|2014_12_31_npc_types_default_values_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'bodytype'|contains|YES
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1 @@
ALTER TABLE `npc_types` ADD `herosforgemodel` int( 11 ) NOT NULL DEFAULT '0' AFTER `helmtexture`;

View File

@ -0,0 +1,2 @@
ALTER TABLE `npc_types` CHANGE `d_meele_texture1` `d_melee_texture1` INT(11) DEFAULT NULL;
ALTER TABLE `npc_types` CHANGE `d_meele_texture2` `d_melee_texture2` INT(11) DEFAULT NULL;

View File

@ -0,0 +1,69 @@
/* Drop the current Merc View */
DROP VIEW vwMercNpcTypes;
/* Rename fields to match the source changes */
ALTER TABLE `merc_weaponinfo` CHANGE `d_meele_texture1` `d_melee_texture1` INT(11) NOT NULL DEFAULT 0;
ALTER TABLE `merc_weaponinfo` CHANGE `d_meele_texture2` `d_melee_texture2` INT(11) NOT NULL DEFAULT 0;
/* Re-Create the Merc View with new field names */
CREATE VIEW vwMercNpcTypes AS
SELECT
ms.merc_npc_type_id,
'' AS name,
ms.clientlevel,
ms.level,
mtyp.race_id,
mstyp.class_id,
ms.hp,
ms.mana,
0 AS gender,
mai.texture,
mai.helmtexture,
ms.attack_speed,
ms.STR,
ms.STA,
ms.DEX,
ms.AGI,
ms._INT,
ms.WIS,
ms.CHA,
ms.MR,
ms.CR,
ms.DR,
ms.FR,
ms.PR,
ms.Corrup,
ms.mindmg,
ms.maxdmg,
ms.attack_count,
ms.special_abilities AS special_abilities,
mwi.d_melee_texture1,
mwi.d_melee_texture2,
mwi.prim_melee_type,
mwi.sec_melee_type,
ms.runspeed,
ms.hp_regen_rate,
ms.mana_regen_rate,
1 AS bodytype,
mai.armortint_id,
mai.armortint_red,
mai.armortint_green,
mai.armortint_blue,
ms.AC,
ms.ATK,
ms.Accuracy,
ms.spellscale,
ms.healscale
FROM merc_stats ms
INNER JOIN merc_armorinfo mai
ON ms.merc_npc_type_id = mai.merc_npc_type_id
AND mai.minlevel <= ms.level AND mai.maxlevel >= ms.level
INNER JOIN merc_weaponinfo mwi
ON ms.merc_npc_type_id = mwi.merc_npc_type_id
AND mwi.minlevel <= ms.level AND mwi.maxlevel >= ms.level
INNER JOIN merc_templates mtem
ON mtem.merc_npc_type_id = ms.merc_npc_type_id
INNER JOIN merc_types mtyp
ON mtem.merc_type_id = mtyp.merc_type_id
INNER JOIN merc_subtypes mstyp
ON mtem.merc_subtype_id = mstyp.merc_subtype_id;

View File

@ -0,0 +1,3 @@
ALTER TABLE `npc_types` MODIFY `bodytype` INT(11) NOT NULL DEFAULT '1';
ALTER TABLE `npc_types` MODIFY `d_melee_texture1` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `npc_types` MODIFY `d_melee_texture2` INT(11) NOT NULL DEFAULT '0';

View File

@ -385,7 +385,7 @@ void Adventure::MoveCorpsesToGraveyard()
std::string query = StringFormat("SELECT id, charid FROM character_corpses WHERE instanceid=%d", GetInstanceID());
auto results = database.QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error in AdventureManager:::MoveCorpsesToGraveyard: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in AdventureManager:::MoveCorpsesToGraveyard: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
for(auto row = results.begin(); row != results.end(); ++row) {
dbid_list.push_back(atoi(row[0]));
@ -405,7 +405,7 @@ void Adventure::MoveCorpsesToGraveyard()
x, y, z, GetInstanceID());
auto results = database.QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error in AdventureManager:::MoveCorpsesToGraveyard: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in AdventureManager:::MoveCorpsesToGraveyard: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
}
auto c_iter = charid_list.begin();

View File

@ -649,7 +649,7 @@ bool AdventureManager::LoadAdventureTemplates()
"graveyard_radius FROM adventure_template";
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in AdventureManager:::LoadAdventures: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in AdventureManager:::LoadAdventures: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -699,7 +699,7 @@ bool AdventureManager::LoadAdventureEntries()
auto results = database.QueryDatabase(query);
if (!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error in AdventureManager:::LoadAdventureEntries: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in AdventureManager:::LoadAdventureEntries: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -1074,7 +1074,7 @@ void AdventureManager::LoadLeaderboardInfo()
"AS adv_stats LEFT JOIN `character_data` AS ch ON adv_stats.player_id = ch.id;";
auto results = database.QueryDatabase(query);
if(!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in AdventureManager:::GetLeaderboardInfo: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in AdventureManager:::GetLeaderboardInfo: %s (%s)", query.c_str(), results.ErrorMessage().c_str());
return;
}

View File

@ -42,7 +42,7 @@ void EQLConfig::LoadSettings() {
std::string query = StringFormat("SELECT dynamics FROM launcher WHERE name = '%s'", namebuf);
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "EQLConfig::LoadSettings: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "EQLConfig::LoadSettings: %s", results.ErrorMessage().c_str());
else {
auto row = results.begin();
m_dynamics = atoi(row[0]);
@ -51,7 +51,7 @@ void EQLConfig::LoadSettings() {
query = StringFormat("SELECT zone, port FROM launcher_zones WHERE launcher = '%s'", namebuf);
results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "EQLConfig::LoadSettings: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "EQLConfig::LoadSettings: %s", results.ErrorMessage().c_str());
return;
}
@ -73,7 +73,7 @@ EQLConfig *EQLConfig::CreateLauncher(const char *name, uint8 dynamic_count) {
std::string query = StringFormat("INSERT INTO launcher (name, dynamics) VALUES('%s', %d)", namebuf, dynamic_count);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in CreateLauncher query: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in CreateLauncher query: %s", results.ErrorMessage().c_str());
return nullptr;
}
@ -118,14 +118,14 @@ void EQLConfig::DeleteLauncher() {
std::string query = StringFormat("DELETE FROM launcher WHERE name = '%s'", namebuf);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in DeleteLauncher 1st query: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in DeleteLauncher 1st query: %s", results.ErrorMessage().c_str());
return;
}
query = StringFormat("DELETE FROM launcher_zones WHERE launcher = '%s'", namebuf);
results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in DeleteLauncher 2nd query: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in DeleteLauncher 2nd query: %s", results.ErrorMessage().c_str());
return;
}
}
@ -173,7 +173,7 @@ bool EQLConfig::BootStaticZone(Const_char *short_name, uint16 port) {
"VALUES('%s', '%s', %d)", namebuf, zonebuf, port);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in BootStaticZone query: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in BootStaticZone query: %s", results.ErrorMessage().c_str());
return false;
}
@ -202,7 +202,7 @@ bool EQLConfig::ChangeStaticZone(Const_char *short_name, uint16 port) {
res = m_zones.find(short_name);
if(res == m_zones.end()) {
//not found.
LogFile->write(EQEMuLog::Error, "Update for unknown zone %s", short_name);
LogFile->write(EQEmuLog::Error, "Update for unknown zone %s", short_name);
return false;
}
@ -217,7 +217,7 @@ bool EQLConfig::ChangeStaticZone(Const_char *short_name, uint16 port) {
"launcher = '%s' AND zone = '%s'",port, namebuf, zonebuf);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in ChangeStaticZone query: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ChangeStaticZone query: %s", results.ErrorMessage().c_str());
return false;
}
@ -239,7 +239,7 @@ bool EQLConfig::DeleteStaticZone(Const_char *short_name) {
res = m_zones.find(short_name);
if(res == m_zones.end()) {
//not found.
LogFile->write(EQEMuLog::Error, "Update for unknown zone %s", short_name);
LogFile->write(EQEmuLog::Error, "Update for unknown zone %s", short_name);
return false;
}
@ -254,7 +254,7 @@ bool EQLConfig::DeleteStaticZone(Const_char *short_name) {
"launcher = '%s' AND zone = '%s'", namebuf, zonebuf);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in DeleteStaticZone query: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in DeleteStaticZone query: %s", results.ErrorMessage().c_str());
return false;
}
@ -279,7 +279,7 @@ bool EQLConfig::SetDynamicCount(int count) {
std::string query = StringFormat("UPDATE launcher SET dynamics=%d WHERE name='%s'", count, namebuf);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in SetDynamicCount query: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in SetDynamicCount query: %s", results.ErrorMessage().c_str());
return false;
}

View File

@ -14,7 +14,7 @@ void log_message_clientVA(LogType type, Client *who, const char *fmt, va_list ar
std::string prefix_buffer = StringFormat("[%s] %s: ", log_type_info[type].name, who->GetAccountName());
LogFile->writePVA(EQEMuLog::Debug, prefix_buffer.c_str(), fmt, args);
LogFile->writePVA(EQEmuLog::Debug, prefix_buffer.c_str(), fmt, args);
}
void log_message_client(LogType type, Client *who, const char *fmt, ...) {
@ -36,7 +36,7 @@ void log_message_zoneVA(LogType type, ZoneServer *who, const char *fmt, va_list
prefix_buffer = StringFormat("[%s] %s ", log_type_info[type].name, zone_tag.c_str());
LogFile->writePVA(EQEMuLog::Debug, prefix_buffer.c_str(), fmt, args);
LogFile->writePVA(EQEmuLog::Debug, prefix_buffer.c_str(), fmt, args);
}
void log_message_zone(LogType type, ZoneServer *who, const char *fmt, ...) {

View File

@ -298,11 +298,11 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct*
in_cc->race);
auto results = QueryDatabase(query);
if(!results.Success()) {
LogFile->write(EQEMuLog::Error, "Start zone query failed: %s : %s\n", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Start zone query failed: %s : %s\n", query.c_str(), results.ErrorMessage().c_str());
return false;
}
LogFile->write(EQEMuLog::Status, "Start zone query: %s\n", query.c_str());
LogFile->write(EQEmuLog::Status, "Start zone query: %s\n", query.c_str());
if (results.RowCount() == 0) {
printf("No start_zones entry in database, using defaults\n");
@ -395,7 +395,7 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct*
}
}
else {
LogFile->write(EQEMuLog::Status, "Found starting location in start_zones");
LogFile->write(EQEmuLog::Status, "Found starting location in start_zones");
auto row = results.begin();
in_pp->x = atof(row[0]);
in_pp->y = atof(row[1]);
@ -434,11 +434,11 @@ bool WorldDatabase::GetStartZoneSoF(PlayerProfile_Struct* in_pp, CharCreate_Stru
in_cc->start_zone, in_cc->class_, in_cc->deity, in_cc->race);
auto results = QueryDatabase(query);
if(!results.Success()) {
LogFile->write(EQEMuLog::Status, "SoF Start zone query failed: %s : %s\n", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Status, "SoF Start zone query failed: %s : %s\n", query.c_str(), results.ErrorMessage().c_str());
return false;
}
LogFile->write(EQEMuLog::Status, "SoF Start zone query: %s\n", query.c_str());
LogFile->write(EQEmuLog::Status, "SoF Start zone query: %s\n", query.c_str());
if (results.RowCount() == 0) {
printf("No start_zones entry in database, using defaults\n");
@ -453,7 +453,7 @@ bool WorldDatabase::GetStartZoneSoF(PlayerProfile_Struct* in_pp, CharCreate_Stru
}
}
else {
LogFile->write(EQEMuLog::Status, "Found starting location in start_zones");
LogFile->write(EQEmuLog::Status, "Found starting location in start_zones");
auto row = results.begin();
in_pp->x = atof(row[0]);
in_pp->y = atof(row[1]);
@ -478,7 +478,7 @@ void WorldDatabase::GetLauncherList(std::vector<std::string> &rl) {
const std::string query = "SELECT name FROM launcher";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "WorldDatabase::GetLauncherList: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "WorldDatabase::GetLauncherList: %s", results.ErrorMessage().c_str());
return;
}
@ -500,7 +500,7 @@ void WorldDatabase::SetMailKey(int CharID, int IPAddress, int MailKey) {
MailKeyString, CharID);
auto results = QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "WorldDatabase::SetMailKey(%i, %s) : %s", CharID, MailKeyString, results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "WorldDatabase::SetMailKey(%i, %s) : %s", CharID, MailKeyString, results.ErrorMessage().c_str());
}
@ -509,7 +509,7 @@ bool WorldDatabase::GetCharacterLevel(const char *name, int &level)
std::string query = StringFormat("SELECT level FROM character_data WHERE name = '%s'", name);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "WorldDatabase::GetCharacterLevel: %s", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "WorldDatabase::GetCharacterLevel: %s", results.ErrorMessage().c_str());
return false;
}

View File

@ -444,7 +444,7 @@ void Client::HandleAAAction(aaID activate) {
break;
default:
LogFile->write(EQEMuLog::Error, "Unknown AA nonspell action type %d", caa->action);
LogFile->write(EQEmuLog::Error, "Unknown AA nonspell action type %d", caa->action);
return;
}
@ -500,7 +500,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
PetRecord record;
if(!database.GetPetEntry(spells[spell_id].teleport_zone, &record))
{
LogFile->write(EQEMuLog::Error, "Unknown swarm pet spell id: %d, check pets table", spell_id);
LogFile->write(EQEmuLog::Error, "Unknown swarm pet spell id: %d, check pets table", spell_id);
Message(13, "Unable to find data for pet %s", spells[spell_id].teleport_zone);
return;
}
@ -527,7 +527,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
const NPCType *npc_type = database.GetNPCType(pet.npc_id);
if(npc_type == nullptr) {
//log write
LogFile->write(EQEMuLog::Error, "Unknown npc type for swarm pet spell id: %d", spell_id);
LogFile->write(EQEmuLog::Error, "Unknown npc type for swarm pet spell id: %d", spell_id);
Message(0,"Unable to find pet!");
return;
}
@ -606,6 +606,9 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
//the target of these swarm pets will take offense to being cast on...
if(targ != nullptr)
targ->AddToHateList(this, 1, 0);
// The other pointers we make are handled elsewhere.
delete made_npc;
}
void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) {
@ -621,7 +624,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
const NPCType *npc_type = database.GetNPCType(typesid);
if(npc_type == nullptr) {
//log write
LogFile->write(EQEMuLog::Error, "Unknown npc type for swarm pet type id: %d", typesid);
LogFile->write(EQEmuLog::Error, "Unknown npc type for swarm pet type id: %d", typesid);
Message(0,"Unable to find pet!");
return;
}
@ -697,6 +700,9 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
entity_list.AddNPC(npca, true, true);
summon_count--;
}
// The other pointers we make are handled elsewhere.
delete made_npc;
}
void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
@ -843,8 +849,8 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
make_npc->loottable_id = 0;
make_npc->merchanttype = 0;
make_npc->d_meele_texture1 = 0;
make_npc->d_meele_texture2 = 0;
make_npc->d_melee_texture1 = 0;
make_npc->d_melee_texture2 = 0;
NPC* npca = new NPC(make_npc, 0, GetPosition(), FlyMode3);
@ -1421,10 +1427,10 @@ SendAA_Struct* Zone::FindAA(uint32 id) {
}
void Zone::LoadAAs() {
LogFile->write(EQEMuLog::Status, "Loading AA information...");
LogFile->write(EQEmuLog::Status, "Loading AA information...");
totalAAs = database.CountAAs();
if(totalAAs == 0) {
LogFile->write(EQEMuLog::Error, "Failed to load AAs!");
LogFile->write(EQEmuLog::Error, "Failed to load AAs!");
aas = nullptr;
return;
}
@ -1439,11 +1445,11 @@ void Zone::LoadAAs() {
}
//load AA Effects into aa_effects
LogFile->write(EQEMuLog::Status, "Loading AA Effects...");
LogFile->write(EQEmuLog::Status, "Loading AA Effects...");
if (database.LoadAAEffects2())
LogFile->write(EQEMuLog::Status, "Loaded %d AA Effects.", aa_effects.size());
LogFile->write(EQEmuLog::Status, "Loaded %d AA Effects.", aa_effects.size());
else
LogFile->write(EQEMuLog::Error, "Failed to load AA Effects!");
LogFile->write(EQEmuLog::Error, "Failed to load AA Effects!");
}
bool ZoneDatabase::LoadAAEffects2() {
@ -1452,12 +1458,12 @@ bool ZoneDatabase::LoadAAEffects2() {
const std::string query = "SELECT aaid, slot, effectid, base1, base2 FROM aa_effects ORDER BY aaid ASC, slot ASC";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAEffects2 query: '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ZoneDatabase::LoadAAEffects2 query: '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
if (!results.RowCount()) { //no results
LogFile->write(EQEMuLog::Error, "Error loading AA Effects, none found in the database.");
LogFile->write(EQEmuLog::Error, "Error loading AA Effects, none found in the database.");
return false;
}
@ -1794,7 +1800,7 @@ bool ZoneDatabase::LoadAAEffects() {
"redux_aa, redux_rate, redux_aa2, redux_rate2 FROM aa_actions";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadAAEffects query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in LoadAAEffects query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -1833,7 +1839,7 @@ uint8 ZoneDatabase::GetTotalAALevels(uint32 skill_id) {
std::string query = StringFormat("SELECT count(slot) FROM aa_effects WHERE aaid = %i", skill_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetTotalAALevels '%s: %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetTotalAALevels '%s: %s", query.c_str(), results.ErrorMessage().c_str());
return 0;
}
@ -1887,7 +1893,7 @@ uint32 ZoneDatabase::CountAAs(){
const std::string query = "SELECT count(title_sid) FROM altadv_vars";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::CountAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ZoneDatabase::CountAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return 0;
}
@ -1904,7 +1910,7 @@ uint32 ZoneDatabase::CountAAEffects() {
const std::string query = "SELECT count(id) FROM aa_effects";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::CountAALevels query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ZoneDatabase::CountAALevels query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return 0;
}
@ -1937,14 +1943,14 @@ void ZoneDatabase::LoadAAs(SendAA_Struct **load){
load[index]->seq = index+1;
}
} else {
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
}
AARequiredLevelAndCost.clear();
query = "SELECT skill_id, level, cost from aa_required_level_cost order by skill_id";
results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -1962,7 +1968,7 @@ SendAA_Struct* ZoneDatabase::GetAASkillVars(uint32 skill_id)
std::string query = "SET @row = 0"; //initialize "row" variable in database for next query
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetAASkillVars '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return nullptr;
}
@ -1982,7 +1988,7 @@ SendAA_Struct* ZoneDatabase::GetAASkillVars(uint32 skill_id)
"FROM altadv_vars a WHERE skill_id=%i", skill_id);
results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in GetAASkillVars '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return nullptr;
}

View File

@ -344,7 +344,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
// Aggro
#if EQDEBUG>=6
LogFile->write(EQEMuLog::Debug, "Check aggro for %s target %s.", GetName(), mob->GetName());
LogFile->write(EQEmuLog::Debug, "Check aggro for %s target %s.", GetName(), mob->GetName());
#endif
return( mod_will_aggro(mob, this) );
}
@ -469,7 +469,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
//Father Nitwit: make sure we can see them.
if(mob->CheckLosFN(sender)) {
#if (EQDEBUG>=5)
LogFile->write(EQEMuLog::Debug, "AIYellForHelp(\"%s\",\"%s\") %s attacking %s Dist %f Z %f",
LogFile->write(EQEmuLog::Debug, "AIYellForHelp(\"%s\",\"%s\") %s attacking %s Dist %f Z %f",
sender->GetName(), attacker->GetName(), mob->GetName(), attacker->GetName(), mob->DistNoRoot(*sender), fabs(sender->GetZ()+mob->GetZ()));
#endif
mob->AddToHateList(attacker, 1, 0, false);
@ -696,7 +696,7 @@ type', in which case, the answer is yes.
}
while( reverse++ == 0 );
LogFile->write(EQEMuLog::Debug, "Mob::IsAttackAllowed: don't have a rule for this - %s vs %s\n", this->GetName(), target->GetName());
LogFile->write(EQEmuLog::Debug, "Mob::IsAttackAllowed: don't have a rule for this - %s vs %s\n", this->GetName(), target->GetName());
return false;
}
@ -836,7 +836,7 @@ bool Mob::IsBeneficialAllowed(Mob *target)
}
while( reverse++ == 0 );
LogFile->write(EQEMuLog::Debug, "Mob::IsBeneficialAllowed: don't have a rule for this - %s to %s\n", this->GetName(), target->GetName());
LogFile->write(EQEmuLog::Debug, "Mob::IsBeneficialAllowed: don't have a rule for this - %s to %s\n", this->GetName(), target->GetName());
return false;
}
@ -948,7 +948,7 @@ bool Mob::CheckLosFN(float posX, float posY, float posZ, float mobSize) {
oloc.z = posZ + (mobSize==0.0?LOS_DEFAULT_HEIGHT:mobSize)/2 * SEE_POSITION;
#if LOSDEBUG>=5
LogFile->write(EQEMuLog::Debug, "LOS from (%.2f, %.2f, %.2f) to (%.2f, %.2f, %.2f) sizes: (%.2f, %.2f)", myloc.x, myloc.y, myloc.z, oloc.x, oloc.y, oloc.z, GetSize(), mobSize);
LogFile->write(EQEmuLog::Debug, "LOS from (%.2f, %.2f, %.2f) to (%.2f, %.2f, %.2f) sizes: (%.2f, %.2f)", myloc.x, myloc.y, myloc.z, oloc.x, oloc.y, oloc.z, GetSize(), mobSize);
#endif
return zone->zonemap->CheckLoS(myloc, oloc);
}
@ -1298,7 +1298,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
void Mob::RogueEvade(Mob *other)
{
int amount = other->GetHateAmount(this) - (GetLevel() * 13);
other->SetHate(this, std::max(1, amount));
other->SetHateAmountOnEnt(this, std::max(1, amount));
return;
}

View File

@ -61,7 +61,7 @@ bool Mob::AttackAnimation(SkillUseTypes &skillinuse, int Hand, const ItemInst* w
if (weapon && weapon->IsType(ItemClassCommon)) {
const Item_Struct* item = weapon->GetItem();
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Debug, "Weapon skill:%i", item->ItemType);
LogFile->write(EQEmuLog::Debug, "Weapon skill:%i", item->ItemType);
#endif
switch (item->ItemType)
{
@ -192,7 +192,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
chancetohit += RuleR(Combat, NPCBonusHitChance);
#if ATTACK_DEBUG>=11
LogFile->write(EQEMuLog::Debug, "CheckHitChance(%s) attacked by %s", defender->GetName(), attacker->GetName());
LogFile->write(EQEmuLog::Debug, "CheckHitChance(%s) attacked by %s", defender->GetName(), attacker->GetName());
#endif
mlog(COMBAT__TOHIT,"CheckHitChance(%s) attacked by %s", defender->GetName(), attacker->GetName());
@ -334,7 +334,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
//agains a garunteed riposte (for example) discipline... for now, garunteed hit wins
#if EQDEBUG>=11
LogFile->write(EQEMuLog::Debug, "3 FINAL calculated chance to hit is: %5.2f", chancetohit);
LogFile->write(EQEmuLog::Debug, "3 FINAL calculated chance to hit is: %5.2f", chancetohit);
#endif
//
@ -1135,7 +1135,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
{
if (!other) {
SetTarget(nullptr);
LogFile->write(EQEMuLog::Error, "A null Mob object was passed to Client::Attack() for evaluation!");
LogFile->write(EQEmuLog::Error, "A null Mob object was passed to Client::Attack() for evaluation!");
return false;
}
@ -1518,7 +1518,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
}
entity_list.RemoveFromTargets(this);
hate_list.RemoveEnt(this);
hate_list.RemoveEntFromHateList(this);
RemoveAutoXTargets();
//remove ourself from all proximities
@ -1699,7 +1699,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
if (!other) {
SetTarget(nullptr);
LogFile->write(EQEMuLog::Error, "A null Mob object was passed to NPC::Attack() for evaluation!");
LogFile->write(EQEmuLog::Error, "A null Mob object was passed to NPC::Attack() for evaluation!");
return false;
}
@ -2036,7 +2036,7 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
{
zone->DelAggroMob();
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Debug,"NPC::Death() Mobs currently Aggro %i", zone->MobsAggroCount());
LogFile->write(EQEmuLog::Debug,"NPC::Death() Mobs currently Aggro %i", zone->MobsAggroCount());
#endif
}
SetHP(0);
@ -2076,12 +2076,12 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
if (killerMob) {
if(GetClass() != LDON_TREASURE)
hate_list.Add(killerMob, damage);
hate_list.AddEntToHateList(killerMob, damage);
}
safe_delete(app);
Mob *give_exp = hate_list.GetDamageTop(this);
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
if(give_exp == nullptr)
give_exp = killer;
@ -2400,7 +2400,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
return true;
}
void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
{
assert(other != nullptr);
@ -2413,7 +2414,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
bool wasengaged = IsEngaged();
Mob* owner = other->GetOwner();
Mob* mypet = this->GetPet();
Mob* mypet = this->GetPet();
Mob* myowner = this->GetOwner();
Mob* targetmob = this->GetTarget();
@ -2488,7 +2489,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
&& other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID()))
hate = (hate*spellbonuses.ImprovedTaunt[1])/100;
hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic);
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
if(other->IsClient())
other->CastToClient()->AddAutoXTarget(this);
@ -2500,8 +2501,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
AddFeignMemory(other->CastToBot()->GetBotOwner()->CastToClient());
}
else {
if(!hate_list.IsOnHateList(other->CastToBot()->GetBotOwner()))
hate_list.Add(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
if(!hate_list.IsEntOnHateList(other->CastToBot()->GetBotOwner()))
hate_list.AddEntToHateList(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
}
}
#endif //BOTS
@ -2512,8 +2513,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
AddFeignMemory(other->CastToMerc()->GetMercOwner()->CastToClient());
}
else {
if(!hate_list.IsOnHateList(other->CastToMerc()->GetMercOwner()))
hate_list.Add(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
if(!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercOwner()))
hate_list.AddEntToHateList(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
}
} //MERC
@ -2528,7 +2529,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
// owner must get on list, but he's not actually gained any hate yet
if(!owner->GetSpecialAbility(IMMUNE_AGGRO))
{
hate_list.Add(owner, 0, 0, false, !iBuffTic);
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
if(owner->IsClient())
owner->CastToClient()->AddAutoXTarget(this);
}
@ -2537,10 +2538,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it
if(!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
mypet->hate_list.Add(other, 0, 0, bFrenzy);
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
} else if (myowner) { // I am a pet, add other to owner if it's NPC/LD
if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO))
myowner->hate_list.Add(other, 0, 0, bFrenzy);
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
if (other->GetTempPetCount())
@ -3890,11 +3891,12 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 h
return ProcChance;
}
// argument 'weapon' not used
void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) {
if (!on) {
SetTarget(nullptr);
LogFile->write(EQEMuLog::Error, "A null Mob object was passed to Mob::TryDefensiveProc for evaluation!");
LogFile->write(EQEmuLog::Error, "A null Mob object was passed to Mob::TryDefensiveProc for evaluation!");
return;
}
@ -3925,7 +3927,7 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) {
void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
if(!on) {
SetTarget(nullptr);
LogFile->write(EQEMuLog::Error, "A null Mob object was passed to Mob::TryWeaponProc for evaluation!");
LogFile->write(EQEmuLog::Error, "A null Mob object was passed to Mob::TryWeaponProc for evaluation!");
return;
}
@ -4474,7 +4476,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
if (!on) {
SetTarget(nullptr);
LogFile->write(EQEMuLog::Error, "A null Mob object was passed to Mob::TrySkillProc for evaluation!");
LogFile->write(EQEmuLog::Error, "A null Mob object was passed to Mob::TrySkillProc for evaluation!");
return;
}
@ -4932,7 +4934,7 @@ void Client::SetAttackTimer()
// this is probably wrong
if (quiver_haste > 0)
speed *= quiver_haste;
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
if (i == MainPrimary)
PrimaryWeapon = ItemToUse;
@ -4980,6 +4982,6 @@ void NPC::SetAttackTimer()
}
}
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -234,45 +234,28 @@ void Bot::SetBotSpellID(uint32 newSpellID) {
this->npc_spells_id = newSpellID;
}
uint32 Bot::GetBotArcheryRange() {
uint32 result = 0;
uint32 Bot::GetBotArcheryRange()
{
const ItemInst *range_inst = GetBotItem(MainRange);
const ItemInst *ammo_inst = GetBotItem(MainAmmo);
ItemInst* rangeItem = GetBotItem(MainRange);
if(!rangeItem)
// empty slots
if (!range_inst || !ammo_inst)
return 0;
const Item_Struct* botweapon = rangeItem->GetItem();
const Item_Struct *range_item = range_inst->GetItem();
const Item_Struct *ammo_item = ammo_inst->GetItem();
uint32 archeryMaterial;
uint32 archeryColor;
uint32 archeryBowID;
uint32 archeryAmmoID;
// no item struct for whatever reason
if (!range_item || !ammo_item)
return 0;
if(botweapon && botweapon->ItemType == ItemTypeBow) {
uint32 range = 0;
// bad item types
if (range_item->ItemType != ItemTypeBow || ammo_item->ItemType != ItemTypeArrow)
return 0;
archeryMaterial = atoi(botweapon->IDFile + 2);
archeryBowID = botweapon->ID;
archeryColor = botweapon->Color;
range =+ botweapon->Range;
rangeItem = GetBotItem(MainAmmo);
if(rangeItem)
botweapon = rangeItem->GetItem();
if(!botweapon || (botweapon->ItemType != ItemTypeArrow)) {
return 0;
}
range += botweapon->Range;
archeryAmmoID = botweapon->ID;
result = range;
}
return result;
// everything is good!
return range_item->Range + ammo_item->Range;
}
void Bot::ChangeBotArcherWeapons(bool isArcher) {
@ -386,8 +369,8 @@ NPCType Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::str
BotNPCType.npc_id = 0;
BotNPCType.texture = 0;
BotNPCType.d_meele_texture1 = 0;
BotNPCType.d_meele_texture2 = 0;
BotNPCType.d_melee_texture1 = 0;
BotNPCType.d_melee_texture2 = 0;
BotNPCType.qglobal = false;
BotNPCType.attack_speed = 0;
BotNPCType.runspeed = 1.25;
@ -431,8 +414,8 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b
Result.hp_regen = 1;
Result.mana_regen = 1;
Result.texture = 0;
Result.d_meele_texture1 = 0;
Result.d_meele_texture2 = 0;
Result.d_melee_texture1 = 0;
Result.d_melee_texture2 = 0;
Result.qglobal = false;
Result.npc_spells_id = 0;
Result.attack_speed = 0;
@ -1242,7 +1225,7 @@ int32 Bot::acmod()
return (65 + ((agility-300) / 21));
}
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Error, "Error in Bot::acmod(): Agility: %i, Level: %i",agility,level);
LogFile->write(EQEmuLog::Error, "Error in Bot::acmod(): Agility: %i, Level: %i",agility,level);
#endif
return 0;
}
@ -1479,7 +1462,7 @@ void Bot::LoadAAs() {
auto results = database.QueryDatabase(query);
if(!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Bot::LoadAAs()");
LogFile->write(EQEmuLog::Error, "Error in Bot::LoadAAs()");
return;
}
@ -2791,7 +2774,7 @@ void Bot::LoadStance() {
std::string query = StringFormat("SELECT StanceID FROM botstances WHERE BotID = %u;", GetBotID());
auto results = database.QueryDatabase(query);
if(!results.Success() || results.RowCount() == 0) {
LogFile->write(EQEMuLog::Error, "Error in Bot::LoadStance()");
LogFile->write(EQEmuLog::Error, "Error in Bot::LoadStance()");
SetDefaultBotStance();
return;
}
@ -2809,7 +2792,7 @@ void Bot::SaveStance() {
"VALUES(%u, %u);", GetBotID(), GetBotStance());
auto results = database.QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error in Bot::SaveStance()");
LogFile->write(EQEmuLog::Error, "Error in Bot::SaveStance()");
}
@ -2824,7 +2807,7 @@ void Bot::LoadTimers() {
GetBotID(), DisciplineReuseStart-1, DisciplineReuseStart-1, GetClass(), GetLevel());
auto results = database.QueryDatabase(query);
if(!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Bot::LoadTimers()");
LogFile->write(EQEmuLog::Error, "Error in Bot::LoadTimers()");
return;
}
@ -2864,7 +2847,7 @@ void Bot::SaveTimers() {
}
if(hadError)
LogFile->write(EQEMuLog::Error, "Error in Bot::SaveTimers()");
LogFile->write(EQEmuLog::Error, "Error in Bot::SaveTimers()");
}
@ -3439,9 +3422,9 @@ void Bot::AI_Process() {
rest_timer.Disable();
if(IsRooted())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.GetClosestEntOnHateList(this));
else
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.GetEntWithMostHateOnList(this));
if(!GetTarget())
return;
@ -3808,9 +3791,9 @@ void Bot::PetAIProcess() {
if (IsEngaged()) {
if (botPet->IsRooted())
botPet->SetTarget(hate_list.GetClosest(botPet));
botPet->SetTarget(hate_list.GetClosestEntOnHateList(botPet));
else
botPet->SetTarget(hate_list.GetTop(botPet));
botPet->SetTarget(hate_list.GetEntWithMostHateOnList(botPet));
// Let's check if we have a los with our target.
// If we don't, our hate_list is wiped.
@ -4228,7 +4211,7 @@ void Bot::GetBotItems(std::string* errorMessage, Inventory &inv) {
ItemInst* inst = database.CreateItem(item_id, charges, aug[0], aug[1], aug[2], aug[3], aug[4]);
if (!inst) {
LogFile->write(EQEMuLog::Error, "Warning: botid %i has an invalid item_id %i in inventory slot %i", this->GetBotID(), item_id, slot_id);
LogFile->write(EQEmuLog::Error, "Warning: botid %i has an invalid item_id %i in inventory slot %i", this->GetBotID(), item_id, slot_id);
continue;
}
@ -4252,7 +4235,7 @@ void Bot::GetBotItems(std::string* errorMessage, Inventory &inv) {
// Save ptr to item in inventory
if (put_slot_id == INVALID_INDEX)
LogFile->write(EQEMuLog::Error, "Warning: Invalid slot_id for item in inventory: botid=%i, item_id=%i, slot_id=%i",this->GetBotID(), item_id, slot_id);
LogFile->write(EQEmuLog::Error, "Warning: Invalid slot_id for item in inventory: botid=%i, item_id=%i, slot_id=%i",this->GetBotID(), item_id, slot_id);
}
@ -5871,7 +5854,7 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, SkillUseTypes att
Save();
Mob *give_exp = hate_list.GetDamageTop(this);
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
Client *give_exp_client = nullptr;
if(give_exp && give_exp->IsClient())
@ -6025,7 +6008,7 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_
}
}
void Bot::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic)
void Bot::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
{
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic);
}
@ -6034,7 +6017,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
{
if (!other) {
SetTarget(nullptr);
LogFile->write(EQEMuLog::Error, "A null Mob object was passed to Bot::Attack for evaluation!");
LogFile->write(EQEmuLog::Error, "A null Mob object was passed to Bot::Attack for evaluation!");
return false;
}
@ -7045,7 +7028,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
return 0;
break;
default:
LogFile->write(EQEMuLog::Normal, "CalcFocusEffect: unknown limit spelltype %d", focus_spell.base[i]);
LogFile->write(EQEmuLog::Normal, "CalcFocusEffect: unknown limit spelltype %d", focus_spell.base[i]);
}
break;
@ -7353,7 +7336,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
//this spits up a lot of garbage when calculating spell focuses
//since they have all kinds of extra effects on them.
default:
LogFile->write(EQEMuLog::Normal, "CalcFocusEffect: unknown effectid %d", focus_spell.effectid[i]);
LogFile->write(EQEmuLog::Normal, "CalcFocusEffect: unknown effectid %d", focus_spell.effectid[i]);
#endif
}
}
@ -8567,7 +8550,7 @@ int32 Bot::CalcMaxMana() {
}
default:
{
LogFile->write(EQEMuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
LogFile->write(EQEmuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
max_mana = 0;
break;
}
@ -11716,106 +11699,46 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
const char* equipped[EmuConstants::EQUIPMENT_SIZE] = {"Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back",
"Left Wrist", "Right Wrist", "Range", "Hands", "Primary Hand", "Secondary Hand",
"Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo" };
const ItemInst* item1 = nullptr;
const Item_Struct* item2 = nullptr;
const ItemInst* inst = nullptr;
const Item_Struct* item = nullptr;
bool is2Hweapon = false;
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i)
{
std::string item_link;
Client::TextLink linker;
linker.SetLinkType(linker.linkItemInst);
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) {
if((i == MainSecondary) && is2Hweapon) {
continue;
}
item1 = b->CastToBot()->GetBotItem(i);
if(item1)
item2 = item1->GetItem();
inst = b->CastToBot()->GetBotItem(i);
if (inst)
item = inst->GetItem();
else
item2 = nullptr;
item = nullptr;
if(!TempErrorMessage.empty()) {
c->Message(13, "Database Error: %s", TempErrorMessage.c_str());
return;
}
if(item2 == 0) {
if(item == nullptr) {
c->Message(15, "I need something for my %s (Item %i)", equipped[i], i);
continue;
}
if((i == MainPrimary) && ((item2->ItemType == ItemType2HSlash) || (item2->ItemType == ItemType2HBlunt) || (item2->ItemType == ItemType2HPiercing))) {
if((i == MainPrimary) && ((item->ItemType == ItemType2HSlash) || (item->ItemType == ItemType2HBlunt) || (item->ItemType == ItemType2HPiercing))) {
is2Hweapon = true;
}
char* itemLink = 0;
if((i == MainCharm) || (i == MainRange) || (i == MainPrimary) || (i == MainSecondary) || (i == MainAmmo)) {
if (c->GetClientVersion() >= EQClientSoF)
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0,
0
);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
else
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
}
else {
if (c->GetClientVersion() >= EQClientSoF)
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0,
0
);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
else
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
}
// I could not find a difference between the criteria positive code and the criteria negative code..
// ..so, I deleted the check (old criteria: i = { MainCharm, MainRange, MainPrimary, MainSecondary, MainAmmo })
linker.SetItemInst(inst);
item_link = linker.GenerateLink();
c->Message(15, "Using %s in my %s (Item %i)", item_link.c_str(), equipped[i], i);
}
}
else {
@ -14364,8 +14287,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
return;
}
std::list<BotGroup>::iterator botGroupItr = botGroup.begin();
for(botGroupItr; botGroupItr != botGroup.end(); ++botGroupItr) {
for(auto botGroupItr = botGroup.begin(); botGroupItr != botGroup.end(); ++botGroupItr) {
// Don't try to re-spawn the botgroup's leader.
if(botGroupItr->BotID == botGroupLeader->GetBotID()) { continue; }
@ -15474,7 +15396,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
else {
Mob *target = c->GetTarget();
if(target->IsBot() && (c == target->GetOwner()->CastToClient())) {
if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) {
const InspectMessage_Struct& playermessage = c->GetInspectMessage();
InspectMessage_Struct& botmessage = target->CastToBot()->GetInspectMessage();
@ -15504,7 +15426,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
Mob *target = c->GetTarget();
if(target->IsBot() && (c == target->GetOwner()->CastToClient())) {
if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) {
Bot* bardBot = target->CastToBot();
if(bardBot) {

View File

@ -208,7 +208,7 @@ public:
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
void Camp(bool databaseSave = true);
virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
virtual void SetTarget(Mob* mob);
virtual void Zone();
std::vector<AISpells_Struct> GetBotSpells() { return AIspells; }

View File

@ -327,7 +327,7 @@ Client::~Client() {
ToggleBuyerMode(false);
if(conn_state != ClientConnectFinished) {
LogFile->write(EQEMuLog::Debug, "Client '%s' was destroyed before reaching the connected state:", GetName());
LogFile->write(EQEmuLog::Debug, "Client '%s' was destroyed before reaching the connected state:", GetName());
ReportConnectingState();
}
@ -425,31 +425,31 @@ void Client::SendLogoutPackets() {
void Client::ReportConnectingState() {
switch(conn_state) {
case NoPacketsReceived: //havent gotten anything
LogFile->write(EQEMuLog::Debug, "Client has not sent us an initial zone entry packet.");
LogFile->write(EQEmuLog::Debug, "Client has not sent us an initial zone entry packet.");
break;
case ReceivedZoneEntry: //got the first packet, loading up PP
LogFile->write(EQEMuLog::Debug, "Client sent initial zone packet, but we never got their player info from the database.");
LogFile->write(EQEmuLog::Debug, "Client sent initial zone packet, but we never got their player info from the database.");
break;
case PlayerProfileLoaded: //our DB work is done, sending it
LogFile->write(EQEMuLog::Debug, "We were sending the player profile, tributes, tasks, spawns, time and weather, but never finished.");
LogFile->write(EQEmuLog::Debug, "We were sending the player profile, tributes, tasks, spawns, time and weather, but never finished.");
break;
case ZoneInfoSent: //includes PP, tributes, tasks, spawns, time and weather
LogFile->write(EQEMuLog::Debug, "We successfully sent player info and spawns, waiting for client to request new zone.");
LogFile->write(EQEmuLog::Debug, "We successfully sent player info and spawns, waiting for client to request new zone.");
break;
case NewZoneRequested: //received and sent new zone request
LogFile->write(EQEMuLog::Debug, "We received client's new zone request, waiting for client spawn request.");
LogFile->write(EQEmuLog::Debug, "We received client's new zone request, waiting for client spawn request.");
break;
case ClientSpawnRequested: //client sent ReqClientSpawn
LogFile->write(EQEMuLog::Debug, "We received the client spawn request, and were sending objects, doors, zone points and some other stuff, but never finished.");
LogFile->write(EQEmuLog::Debug, "We received the client spawn request, and were sending objects, doors, zone points and some other stuff, but never finished.");
break;
case ZoneContentsSent: //objects, doors, zone points
LogFile->write(EQEMuLog::Debug, "The rest of the zone contents were successfully sent, waiting for client ready notification.");
LogFile->write(EQEmuLog::Debug, "The rest of the zone contents were successfully sent, waiting for client ready notification.");
break;
case ClientReadyReceived: //client told us its ready, send them a bunch of crap like guild MOTD, etc
LogFile->write(EQEMuLog::Debug, "We received client ready notification, but never finished Client::CompleteConnect");
LogFile->write(EQEmuLog::Debug, "We received client ready notification, but never finished Client::CompleteConnect");
break;
case ClientConnectFinished: //client finally moved to finished state, were done here
LogFile->write(EQEMuLog::Debug, "Client is successfully connected.");
LogFile->write(EQEmuLog::Debug, "Client is successfully connected.");
break;
};
}
@ -640,7 +640,7 @@ bool Client::SendAllPackets() {
eqs->FastQueuePacket((EQApplicationPacket **)&cp->app, cp->ack_req);
iterator.RemoveCurrent();
#if EQDEBUG >= 6
LogFile->write(EQEMuLog::Normal, "Transmitting a packet");
LogFile->write(EQEmuLog::Normal, "Transmitting a packet");
#endif
}
return true;
@ -691,7 +691,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Debug,"Client::ChannelMessageReceived() Channel:%i message:'%s'", chan_num, message);
LogFile->write(EQEmuLog::Debug,"Client::ChannelMessageReceived() Channel:%i message:'%s'", chan_num, message);
#endif
if (targetname == nullptr) {
@ -1807,45 +1807,8 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
}
ns->spawn.size = 0; // Changing size works, but then movement stops! (wth?)
ns->spawn.runspeed = (gmspeed == 0) ? runspeed : 3.125f;
if (!m_pp.showhelm) ns->spawn.showhelm = 0;
ns->spawn.showhelm = m_pp.showhelm ? 1 : 0;
/*
// Equipment/Weapons already set from Mob::FillSpawnStruct
// Commenting this out for now
const Item_Struct* item = nullptr;
const ItemInst* inst = nullptr;
int16 invslot;
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++)
{
// Only Player Races Wear Armor
if (IsPlayerRace(race) || matslot > 6)
{
invslot = Inventory::CalcSlotFromMaterial(matslot);
if (invslot == INVALID_INDEX)
continue;
if ((inst = m_inv[invslot]) && inst->IsType(ItemClassCommon))
{
item = inst->GetItem();
if (matslot > 6)
{
// Weapon Models
ns->spawn.equipment[matslot].material = GetEquipmentMaterial(matslot);
}
else
{
// Armor Materials/Models
ns->spawn.equipment[matslot].material = item->Material;
ns->spawn.equipment[matslot].elitematerial = item->EliteMaterial;
ns->spawn.equipment[matslot].heroforgemodel = GetHerosForgeModel(matslot);
ns->spawn.colors[matslot].color = m_pp.item_tint[matslot].rgb.use_tint ? m_pp.item_tint[matslot].color : item->Color;
}
}
}
}
*/
}
bool Client::GMHideMe(Client* client) {
@ -1944,7 +1907,7 @@ void Client::ReadBook(BookRequest_Struct *book) {
if (booktxt2[0] != '\0') {
#if EQDEBUG >= 6
LogFile->write(EQEMuLog::Normal,"Client::ReadBook() textfile:%s Text:%s", txtfile, booktxt2.c_str());
LogFile->write(EQEmuLog::Normal,"Client::ReadBook() textfile:%s Text:%s", txtfile, booktxt2.c_str());
#endif
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ReadBook, length + sizeof(BookText_Struct));
@ -2138,7 +2101,7 @@ void Client::AddMoneyToPP(uint64 copper, bool updateclient){
SaveCurrency();
LogFile->write(EQEMuLog::Debug, "Client::AddMoneyToPP() %s should have: plat:%i gold:%i silver:%i copper:%i", GetName(), m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper);
LogFile->write(EQEmuLog::Debug, "Client::AddMoneyToPP() %s should have: plat:%i gold:%i silver:%i copper:%i", GetName(), m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper);
}
void Client::EVENT_ITEM_ScriptStopReturn(){
@ -2178,7 +2141,7 @@ void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 plat
SaveCurrency();
#if (EQDEBUG>=5)
LogFile->write(EQEMuLog::Debug, "Client::AddMoneyToPP() %s should have: plat:%i gold:%i silver:%i copper:%i",
LogFile->write(EQEmuLog::Debug, "Client::AddMoneyToPP() %s should have: plat:%i gold:%i silver:%i copper:%i",
GetName(), m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper);
#endif
}
@ -2397,7 +2360,7 @@ uint16 Client::GetMaxSkillAfterSpecializationRules(SkillUseTypes skillid, uint16
Save();
LogFile->write(EQEMuLog::Normal, "Reset %s's caster specialization skills to 1. "
LogFile->write(EQEmuLog::Normal, "Reset %s's caster specialization skills to 1. "
"Too many specializations skills were above 50.", GetCleanName());
}
@ -4577,14 +4540,14 @@ void Client::HandleLDoNOpen(NPC *target)
{
if(target->GetClass() != LDON_TREASURE)
{
LogFile->write(EQEMuLog::Debug, "%s tried to open %s but %s was not a treasure chest.",
LogFile->write(EQEmuLog::Debug, "%s tried to open %s but %s was not a treasure chest.",
GetName(), target->GetName(), target->GetName());
return;
}
if(DistNoRootNoZ(*target) > RuleI(Adventure, LDoNTrapDistanceUse))
{
LogFile->write(EQEMuLog::Debug, "%s tried to open %s but %s was out of range",
LogFile->write(EQEmuLog::Debug, "%s tried to open %s but %s was out of range",
GetName(), target->GetName(), target->GetName());
Message(13, "Treasure chest out of range.");
return;
@ -5319,7 +5282,7 @@ void Client::SendRewards()
"ORDER BY reward_id", AccountID());
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Client::SendRewards(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in Client::SendRewards(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
return;
}
@ -5387,7 +5350,7 @@ bool Client::TryReward(uint32 claim_id) {
AccountID(), claim_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -5414,7 +5377,7 @@ bool Client::TryReward(uint32 claim_id) {
AccountID(), claim_id);
auto results = database.QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
}
else {
query = StringFormat("UPDATE account_rewards SET amount = (amount-1) "
@ -5422,7 +5385,7 @@ bool Client::TryReward(uint32 claim_id) {
AccountID(), claim_id);
auto results = database.QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
}
InternalVeteranReward ivr = (*iter);
@ -6236,7 +6199,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
PetRecord record;
if(!database.GetPetEntry(spells[spell_id].teleport_zone, &record))
{
LogFile->write(EQEMuLog::Error, "Unknown doppelganger spell id: %d, check pets table", spell_id);
LogFile->write(EQEmuLog::Error, "Unknown doppelganger spell id: %d, check pets table", spell_id);
Message(13, "Unable to find data for pet %s", spells[spell_id].teleport_zone);
return;
}
@ -6250,7 +6213,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
const NPCType *npc_type = database.GetNPCType(pet.npc_id);
if(npc_type == nullptr) {
LogFile->write(EQEMuLog::Error, "Unknown npc type for doppelganger spell id: %d", spell_id);
LogFile->write(EQEmuLog::Error, "Unknown npc type for doppelganger spell id: %d", spell_id);
Message(0,"Unable to find pet!");
return;
}
@ -6274,6 +6237,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
made_npc->DR = GetDR();
made_npc->PR = GetPR();
made_npc->Corrup = GetCorrup();
made_npc->PhR = GetPhR();
// looks
made_npc->texture = GetEquipmentMaterial(MaterialChest);
made_npc->helmtexture = GetEquipmentMaterial(MaterialHead);
@ -6287,8 +6251,8 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
made_npc->drakkin_heritage = GetDrakkinHeritage();
made_npc->drakkin_tattoo = GetDrakkinTattoo();
made_npc->drakkin_details = GetDrakkinDetails();
made_npc->d_meele_texture1 = GetEquipmentMaterial(MaterialPrimary);
made_npc->d_meele_texture2 = GetEquipmentMaterial(MaterialSecondary);
made_npc->d_melee_texture1 = GetEquipmentMaterial(MaterialPrimary);
made_npc->d_melee_texture2 = GetEquipmentMaterial(MaterialSecondary);
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) {
made_npc->armor_tint[i] = GetEquipmentColor(i);
}
@ -6374,7 +6338,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
// Set Class
std::string class_Name = itoa(GetClass());
std::string class_List[] = { "WAR", "CLR", "PAL", "RNG", "SK", "DRU", "MNK", "BRD", "ROG", "SHM", "NEC", "WIZ", "MAG", "ENC", "BST", "BER" };
std::string class_List[] = { "WAR", "CLR", "PAL", "RNG", "SHD", "DRU", "MNK", "BRD", "ROG", "SHM", "NEC", "WIZ", "MAG", "ENC", "BST", "BER" };
if(GetClass() < 17 && GetClass() > 0) { class_Name = class_List[GetClass()-1]; }
@ -6462,7 +6426,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
/*===========================*/
std::string regen_row_header = "";
std::string regen_row_color = "";
std::string base_regen_field = "";
std::string base_regen_field = "";
std::string base_regen_spacing = "";
std::string item_regen_field = "";
std::string item_regen_spacing = "";
@ -6623,8 +6587,11 @@ void Client::SendStatsWindow(Client* client, bool use_window)
}
case 6: {
a_stat_name = " CHA: ";
a_resist_name = "PhR: "; // Not implemented for clients yet
a_stat = itoa(GetCHA());
h_stat = itoa(GetHeroicCHA());
a_resist = itoa(GetPhR());
h_resist_field = itoa(GetHeroicPhR());
break;
}
default: { break; }
@ -6639,8 +6606,9 @@ void Client::SendStatsWindow(Client* client, bool use_window)
for(int h = a_resist.size(); h < max_stat_value_len; h++) { a_resist_spacing += " . "; }
stat_field += indP + a_stat_name + a_stat_spacing + a_stat + heroic_color + h_stat + "</c>";
stat_field += h_stat_spacing + a_resist_name + a_resist_spacing + a_resist + heroic_color + h_resist_field + "</c>";
if(stat_row_counter < 6) {
stat_field += h_stat_spacing + a_resist_name + a_resist_spacing + a_resist + heroic_color + h_resist_field + "</c><br>";
stat_field += "<br>";
}
}
/*##########################################################
@ -6849,7 +6817,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
client->Message(0, " Haste: %i / %i (Item: %i + Spell: %i + Over: %i)", GetHaste(), RuleI(Character, HasteCap), itembonuses.haste, spellbonuses.haste + spellbonuses.hastetype2, spellbonuses.hastetype3 + ExtraHaste);
client->Message(0, " STR: %i STA: %i DEX: %i AGI: %i INT: %i WIS: %i CHA: %i", GetSTR(), GetSTA(), GetDEX(), GetAGI(), GetINT(), GetWIS(), GetCHA());
client->Message(0, " hSTR: %i hSTA: %i hDEX: %i hAGI: %i hINT: %i hWIS: %i hCHA: %i", GetHeroicSTR(), GetHeroicSTA(), GetHeroicDEX(), GetHeroicAGI(), GetHeroicINT(), GetHeroicWIS(), GetHeroicCHA());
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i Corruption: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR(), GetCorrup());
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i Corruption: %i PhR: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR(), GetCorrup(), GetPhR());
client->Message(0, " hMR: %i hPR: %i hFR: %i hCR: %i hDR: %i hCorruption: %i", GetHeroicMR(), GetHeroicPR(), GetHeroicFR(), GetHeroicCR(), GetHeroicDR(), GetHeroicCorrup());
client->Message(0, " Shielding: %i Spell Shield: %i DoT Shielding: %i Stun Resist: %i Strikethrough: %i Avoidance: %i Accuracy: %i Combat Effects: %i", GetShielding(), GetSpellShield(), GetDoTShield(), GetStunResist(), GetStrikeThrough(), GetAvoidance(), GetAccuracy(), GetCombatEffects());
client->Message(0, " Heal Amt.: %i Spell Dmg.: %i Clairvoyance: %i DS Mitigation: %i", GetHealAmt(), GetSpellDmg(), GetClair(), GetDSMit());
@ -7487,8 +7455,17 @@ void Client::GarbleMessage(char *message, uint8 variance)
{
// Garble message by variance%
const char alpha_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; // only change alpha characters for now
const char delimiter = 0x12;
int delimiter_count = 0;
for (size_t i = 0; i < strlen(message); i++) {
// Client expects hex values inside of a text link body
if (message[i] == delimiter) {
if (!(delimiter_count & 1)) { i += EmuConstants::TEXT_LINK_BODY_LENGTH; }
++delimiter_count;
continue;
}
uint8 chance = (uint8)zone->random.Int(0, 115); // variation just over worst possible scrambling
if (isalpha(message[i]) && (chance <= variance)) {
uint8 rand_char = (uint8)zone->random.Int(0,51); // choose a random character from the alpha list
@ -8163,7 +8140,7 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_
entity_list.MessageClose_StringID(this, true, 50, 0, EATING_MESSAGE, GetName(), item->Name);
#if EQDEBUG >= 5
LogFile->write(EQEMuLog::Debug, "Eating from slot:%i", (int)slot);
LogFile->write(EQEmuLog::Debug, "Eating from slot:%i", (int)slot);
#endif
}
else
@ -8180,7 +8157,7 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_
entity_list.MessageClose_StringID(this, true, 50, 0, DRINKING_MESSAGE, GetName(), item->Name);
#if EQDEBUG >= 5
LogFile->write(EQEMuLog::Debug, "Drinking from slot:%i", (int)slot);
LogFile->write(EQEmuLog::Debug, "Drinking from slot:%i", (int)slot);
#endif
}
}
@ -8280,3 +8257,216 @@ void Client::SendColoredText(uint32 color, std::string message)
safe_delete(outapp);
}
//
// class Client::TextLink
//
std::string Client::TextLink::GenerateLink()
{
m_Link.clear();
m_LinkBody.clear();
m_LinkText.clear();
generate_body();
generate_text();
if ((m_LinkBody.length() == EmuConstants::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) {
m_Link.push_back(0x12);
m_Link.append(m_LinkBody);
m_Link.append(m_LinkText);
m_Link.push_back(0x12);
}
if ((m_Link.length() == 0) || (m_Link.length() > 250)) {
m_Error = true;
m_Link = "<LINKER ERROR>";
_log(CHANNELS__ERROR, "TextLink::GenerateLink() failed to generate a useable text link (LinkType: %i, Lengths: {link: %u, body: %u, text: %u})",
m_LinkType, m_Link.length(), m_LinkBody.length(), m_LinkText.length());
#if EQDEBUG >= 5
_log(CHANNELS__ERROR, ">> LinkBody: %s", m_LinkBody.c_str());
_log(CHANNELS__ERROR, ">> LinkText: %s", m_LinkText.c_str());
#endif
}
return m_Link;
}
void Client::TextLink::Reset()
{
m_LinkType = linkBlank;
m_ItemData = nullptr;
m_LootData = nullptr;
m_ItemInst = nullptr;
m_ProxyItemID = NOT_USED;
m_ProxyText = nullptr;
m_TaskUse = false;
m_Link.clear();
m_LinkBody.clear();
m_LinkText.clear();
m_Error = false;
}
void Client::TextLink::generate_body()
{
/*
Current server mask: EQClientRoF2
RoF2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X" (56)
RoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (55)
SoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (50)
6.2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X" (45)
*/
memset(&m_LinkBodyStruct, 0, sizeof(TextLinkBody_Struct));
const Item_Struct* item_data = nullptr;
switch (m_LinkType) {
case linkBlank:
break;
case linkItemData:
if (m_ItemData == nullptr) { break; }
m_LinkBodyStruct.item_id = m_ItemData->ID;
m_LinkBodyStruct.evolve_group = m_ItemData->LoreGroup; // this probably won't work for all items
//m_LinkBodyStruct.evolve_level = m_ItemData->EvolvingLevel;
// TODO: add hash call
break;
case linkLootItem:
if (m_LootData == nullptr) { break; }
item_data = database.GetItem(m_LootData->item_id);
if (item_data == nullptr) { break; }
m_LinkBodyStruct.item_id = item_data->ID;
m_LinkBodyStruct.augment_1 = m_LootData->aug_1;
m_LinkBodyStruct.augment_2 = m_LootData->aug_2;
m_LinkBodyStruct.augment_3 = m_LootData->aug_3;
m_LinkBodyStruct.augment_4 = m_LootData->aug_4;
m_LinkBodyStruct.augment_5 = m_LootData->aug_5;
m_LinkBodyStruct.augment_6 = m_LootData->aug_6;
m_LinkBodyStruct.evolve_group = item_data->LoreGroup; // see note above
//m_LinkBodyStruct.evolve_level = item_data->EvolvingLevel;
// TODO: add hash call
break;
case linkItemInst:
if (m_ItemInst == nullptr) { break; }
if (m_ItemInst->GetItem() == nullptr) { break; }
m_LinkBodyStruct.item_id = m_ItemInst->GetItem()->ID;
m_LinkBodyStruct.augment_1 = m_ItemInst->GetAugmentItemID(0);
m_LinkBodyStruct.augment_2 = m_ItemInst->GetAugmentItemID(1);
m_LinkBodyStruct.augment_3 = m_ItemInst->GetAugmentItemID(2);
m_LinkBodyStruct.augment_4 = m_ItemInst->GetAugmentItemID(3);
m_LinkBodyStruct.augment_5 = m_ItemInst->GetAugmentItemID(4);
m_LinkBodyStruct.augment_6 = m_ItemInst->GetAugmentItemID(5);
m_LinkBodyStruct.is_evolving = (m_ItemInst->IsEvolving() ? 1 : 0);
m_LinkBodyStruct.evolve_group = m_ItemInst->GetItem()->LoreGroup; // see note above
m_LinkBodyStruct.evolve_level = m_ItemInst->GetEvolveLvl();
m_LinkBodyStruct.ornament_icon = m_ItemInst->GetOrnamentationIcon();
// TODO: add hash call
break;
default:
break;
}
if (m_ProxyItemID != NOT_USED) {
m_LinkBodyStruct.item_id = m_ProxyItemID;
}
if (m_TaskUse) {
m_LinkBodyStruct.hash = 0x14505DC2;
}
m_LinkBody = StringFormat(
"%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X",
(0x0F & m_LinkBodyStruct.unknown_1),
(0x000FFFFF & m_LinkBodyStruct.item_id),
(0x000FFFFF & m_LinkBodyStruct.augment_1),
(0x000FFFFF & m_LinkBodyStruct.augment_2),
(0x000FFFFF & m_LinkBodyStruct.augment_3),
(0x000FFFFF & m_LinkBodyStruct.augment_4),
(0x000FFFFF & m_LinkBodyStruct.augment_5),
(0x000FFFFF & m_LinkBodyStruct.augment_6),
(0x0F & m_LinkBodyStruct.is_evolving),
(0x0000FFFF & m_LinkBodyStruct.evolve_group),
(0xFF & m_LinkBodyStruct.evolve_level),
(0x000FFFFF & m_LinkBodyStruct.ornament_icon),
(0xFFFFFFFF & m_LinkBodyStruct.hash)
);
}
void Client::TextLink::generate_text()
{
if (m_ProxyText != nullptr) {
m_LinkText = m_ProxyText;
return;
}
const Item_Struct* item_data = nullptr;
switch (m_LinkType) {
case linkBlank:
break;
case linkItemData:
if (m_ItemData == nullptr) { break; }
m_LinkText = m_ItemData->Name;
return;
case linkLootItem:
if (m_LootData == nullptr) { break; }
item_data = database.GetItem(m_LootData->item_id);
if (item_data == nullptr) { break; }
m_LinkText = item_data->Name;
return;
case linkItemInst:
if (m_ItemInst == nullptr) { break; }
if (m_ItemInst->GetItem() == nullptr) { break; }
m_LinkText = m_ItemInst->GetItem()->Name;
return;
default:
break;
}
m_LinkText = "null";
}
bool Client::TextLink::DegenerateLinkBody(TextLinkBody_Struct& textLinkBodyStruct, const std::string& textLinkBody)
{
memset(&textLinkBodyStruct, 0, sizeof(TextLinkBody_Struct));
if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; }
textLinkBodyStruct.unknown_1 = (uint8)strtol(textLinkBody.substr(0, 1).c_str(), nullptr, 16);
textLinkBodyStruct.item_id = (uint32)strtol(textLinkBody.substr(1, 5).c_str(), nullptr, 16);
textLinkBodyStruct.augment_1 = (uint32)strtol(textLinkBody.substr(6, 5).c_str(), nullptr, 16);
textLinkBodyStruct.augment_2 = (uint32)strtol(textLinkBody.substr(11, 5).c_str(), nullptr, 16);
textLinkBodyStruct.augment_3 = (uint32)strtol(textLinkBody.substr(16, 5).c_str(), nullptr, 16);
textLinkBodyStruct.augment_4 = (uint32)strtol(textLinkBody.substr(21, 5).c_str(), nullptr, 16);
textLinkBodyStruct.augment_5 = (uint32)strtol(textLinkBody.substr(26, 5).c_str(), nullptr, 16);
textLinkBodyStruct.augment_6 = (uint32)strtol(textLinkBody.substr(31, 5).c_str(), nullptr, 16);
textLinkBodyStruct.is_evolving = (uint8)strtol(textLinkBody.substr(36, 1).c_str(), nullptr, 16);
textLinkBodyStruct.evolve_group = (uint32)strtol(textLinkBody.substr(37, 4).c_str(), nullptr, 16);
textLinkBodyStruct.evolve_level = (uint8)strtol(textLinkBody.substr(41, 2).c_str(), nullptr, 16);
textLinkBodyStruct.ornament_icon = (uint32)strtol(textLinkBody.substr(43, 5).c_str(), nullptr, 16);
textLinkBodyStruct.hash = (int)strtol(textLinkBody.substr(48, 8).c_str(), nullptr, 16);
return true;
}
bool Client::TextLink::GenerateLinkBody(std::string& textLinkBody, const TextLinkBody_Struct& textLinkBodyStruct)
{
textLinkBody = StringFormat(
"%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X",
(0x0F & textLinkBodyStruct.unknown_1),
(0x000FFFFF & textLinkBodyStruct.item_id),
(0x000FFFFF & textLinkBodyStruct.augment_1),
(0x000FFFFF & textLinkBodyStruct.augment_2),
(0x000FFFFF & textLinkBodyStruct.augment_3),
(0x000FFFFF & textLinkBodyStruct.augment_4),
(0x000FFFFF & textLinkBodyStruct.augment_5),
(0x000FFFFF & textLinkBodyStruct.augment_6),
(0x0F & textLinkBodyStruct.is_evolving),
(0x0000FFFF & textLinkBodyStruct.evolve_group),
(0xFF & textLinkBodyStruct.evolve_level),
(0x000FFFFF & textLinkBodyStruct.ornament_icon),
(0xFFFFFFFF & textLinkBodyStruct.hash)
);
if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; }
return true;
}

View File

@ -428,6 +428,7 @@ public:
inline virtual int32 GetPR() const { return PR; }
inline virtual int32 GetCR() const { return CR; }
inline virtual int32 GetCorrup() const { return Corrup; }
inline virtual int32 GetPhR() const { return PhR; }
int32 GetMaxStat() const;
int32 GetMaxResist() const;
@ -452,6 +453,7 @@ public:
inline uint8 GetBaseAGI() const { return m_pp.AGI; }
inline uint8 GetBaseWIS() const { return m_pp.WIS; }
inline uint8 GetBaseCorrup() const { return 15; } // Same for all
inline uint8 GetBasePhR() const { return 0; } // Guessing at 0 as base
inline virtual int32 GetHeroicSTR() const { return itembonuses.HeroicSTR; }
inline virtual int32 GetHeroicSTA() const { return itembonuses.HeroicSTA; }
@ -466,6 +468,7 @@ public:
inline virtual int32 GetHeroicPR() const { return itembonuses.HeroicPR; }
inline virtual int32 GetHeroicCR() const { return itembonuses.HeroicCR; }
inline virtual int32 GetHeroicCorrup() const { return itembonuses.HeroicCorrup; }
inline virtual int32 GetHeroicPhR() const { return 0; } // Heroic PhR not implemented yet
// Mod2
inline virtual int32 GetShielding() const { return itembonuses.MeleeMitigation; }
inline virtual int32 GetSpellShield() const { return itembonuses.SpellShield; }
@ -804,6 +807,7 @@ public:
int32 GetAugmentIDAt(int16 slot_id, uint8 augslot);
bool PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update = false);
bool PushItemOnCursor(const ItemInst& inst, bool client_update = false);
void SendCursorBuffer();
void DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true);
bool SwapItem(MoveItem_Struct* move_in);
void SwapItemResync(MoveItem_Struct* move_slots);
@ -814,8 +818,56 @@ public:
void SetStats(uint8 type,int16 set_val);
void IncStats(uint8 type,int16 increase_val);
void DropItem(int16 slot_id);
bool MakeItemLink(char* &ret_link, const ItemInst* inst);
int GetItemLinkHash(const ItemInst* inst);
//
// class Client::TextLink
//
class TextLink {
public:
enum LinkType { linkBlank = 0, linkItemData, linkLootItem, linkItemInst };
TextLink() { Reset(); }
void SetLinkType(LinkType linkType) { m_LinkType = linkType; }
void SetItemData(const Item_Struct* itemData) { m_ItemData = itemData; }
void SetLootData(const ServerLootItem_Struct* lootData) { m_LootData = lootData; }
void SetItemInst(const ItemInst* itemInst) { m_ItemInst = itemInst; }
void SetProxyItemID(uint32 proxyItemID) { m_ProxyItemID = proxyItemID; } // mainly for saylinks..but, not limited to
void SetProxyText(const char* proxyText) { m_ProxyText = proxyText; } // overrides standard text use
void SetTaskUse() { m_TaskUse = true; }
std::string GenerateLink();
bool LinkError() { return m_Error; }
std::string GetLink() { return m_Link; } // contains full string format: '/12x' '<LinkBody>' '<LinkText>' '/12x'
std::string GetLinkBody() { return m_LinkBody; } // contains string format: '<LinkBody>'
std::string GetLinkText() { return m_LinkText; } // contains string format: '<LinkText>'
void Reset();
static bool DegenerateLinkBody(TextLinkBody_Struct& textLinkBodyStruct, const std::string& textLinkBody);
static bool GenerateLinkBody(std::string& textLinkBody, const TextLinkBody_Struct& textLinkBodyStruct);
private:
void generate_body();
void generate_text();
int m_LinkType;
const Item_Struct* m_ItemData;
const ServerLootItem_Struct* m_LootData;
const ItemInst* m_ItemInst;
uint32 m_ProxyItemID;
const char* m_ProxyText;
bool m_TaskUse;
TextLinkBody_Struct m_LinkBodyStruct;
std::string m_Link;
std::string m_LinkBody;
std::string m_LinkText;
bool m_Error;
};
int GetItemLinkHash(const ItemInst* inst); // move to Item_Struct..or make use of the pre-calculated database field
void SendItemLink(const ItemInst* inst, bool sendtoall=false);
void SendLootItemInPacket(const ItemInst* inst, int16 slot_id);
void SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type);
@ -832,11 +884,11 @@ public:
bool Hungry() const {if (GetGM()) return false; return m_pp.hunger_level <= 3000;}
bool Thirsty() const {if (GetGM()) return false; return m_pp.thirst_level <= 3000;}
int32 GetHunger() const { return m_pp.hunger_level; }
int32 GetThirst() const { return m_pp.thirst_level; }
void SetHunger(int32 in_hunger);
void SetThirst(int32 in_thirst);
void SetConsumption(int32 in_hunger, int32 in_thirst);
int32 GetHunger() const { return m_pp.hunger_level; }
int32 GetThirst() const { return m_pp.thirst_level; }
void SetHunger(int32 in_hunger);
void SetThirst(int32 in_thirst);
void SetConsumption(int32 in_hunger, int32 in_thirst);
bool CheckTradeLoreConflict(Client* other);
void LinkDead();
@ -937,7 +989,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst);
inline bool IsTaskActive(int TaskID) { return (taskstate ? taskstate->IsTaskActive(TaskID) : false); }
inline bool IsTaskActivityActive(int TaskID, int ActivityID) { return (taskstate ? taskstate->IsTaskActivityActive(TaskID, ActivityID) : false); }
inline ActivityState GetTaskActivityState(int index, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityState(index, ActivityID) : ActivityHidden); }
inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count) { if(taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count); }
inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count, bool ignore_quest_update = false) { if (taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count, ignore_quest_update); }
inline void ResetTaskActivity(int TaskID, int ActivityID) { if(taskstate) taskstate->ResetTaskActivity(this, TaskID, ActivityID); }
inline void UpdateTasksOnKill(int NPCTypeID) { if(taskstate) taskstate->UpdateTasksOnKill(this, NPCTypeID); }
inline void UpdateTasksForItem(ActivityType Type, int ItemID, int Count=1) { if(taskstate) taskstate->UpdateTasksForItem(this, Type, ItemID, Count); }

View File

@ -27,8 +27,8 @@ ClientLogs client_logs;
char ClientLogs::_buffer[MAX_CLIENT_LOG_MESSAGE_LENGTH+1];
void ClientLogs::subscribe(EQEMuLog::LogIDs id, Client *c) {
if(id >= EQEMuLog::MaxLogID)
void ClientLogs::subscribe(EQEmuLog::LogIDs id, Client *c) {
if(id >= EQEmuLog::MaxLogID)
return;
if(c == nullptr)
return;
@ -47,8 +47,8 @@ void ClientLogs::subscribe(EQEMuLog::LogIDs id, Client *c) {
entries[id].push_back(c);
}
void ClientLogs::unsubscribe(EQEMuLog::LogIDs id, Client *c) {
if(id >= EQEMuLog::MaxLogID)
void ClientLogs::unsubscribe(EQEmuLog::LogIDs id, Client *c) {
if(id >= EQEmuLog::MaxLogID)
return;
if(c == nullptr)
return;
@ -68,8 +68,8 @@ void ClientLogs::subscribeAll(Client *c) {
if(c == nullptr)
return;
int r;
for(r = EQEMuLog::Status; r < EQEMuLog::MaxLogID; r++) {
subscribe((EQEMuLog::LogIDs)r, c);
for(r = EQEmuLog::Status; r < EQEmuLog::MaxLogID; r++) {
subscribe((EQEmuLog::LogIDs)r, c);
}
}
@ -77,20 +77,20 @@ void ClientLogs::unsubscribeAll(Client *c) {
if(c == nullptr)
return;
int r;
for(r = EQEMuLog::Status; r < EQEMuLog::MaxLogID; r++) {
unsubscribe((EQEMuLog::LogIDs)r, c);
for(r = EQEmuLog::Status; r < EQEmuLog::MaxLogID; r++) {
unsubscribe((EQEmuLog::LogIDs)r, c);
}
}
void ClientLogs::clear() {
int r;
for(r = EQEMuLog::Status; r < EQEMuLog::MaxLogID; r++) {
for(r = EQEmuLog::Status; r < EQEmuLog::MaxLogID; r++) {
entries[r].clear();
}
}
void ClientLogs::msg(EQEMuLog::LogIDs id, const char *buf) {
if(id >= EQEMuLog::MaxLogID)
void ClientLogs::msg(EQEmuLog::LogIDs id, const char *buf) {
if(id >= EQEmuLog::MaxLogID)
return;
std::vector<Client *>::iterator cur,end;
cur = entries[id].begin();
@ -103,7 +103,7 @@ void ClientLogs::msg(EQEMuLog::LogIDs id, const char *buf) {
}
}
void ClientLogs::EQEmuIO_buf(EQEMuLog::LogIDs id, const char *buf, uint8 size, uint32 count) {
void ClientLogs::EQEmuIO_buf(EQEmuLog::LogIDs id, const char *buf, uint8 size, uint32 count) {
if(size != 1)
return; //cannot print multibyte data
if(buf[0] == '\n' || buf[0] == '\r')
@ -115,7 +115,7 @@ void ClientLogs::EQEmuIO_buf(EQEMuLog::LogIDs id, const char *buf, uint8 size, u
client_logs.msg(id, _buffer);
}
void ClientLogs::EQEmuIO_fmt(EQEMuLog::LogIDs id, const char *fmt, va_list ap) {
void ClientLogs::EQEmuIO_fmt(EQEmuLog::LogIDs id, const char *fmt, va_list ap) {
if(fmt[0] == '\n' || fmt[0] == '\r')
return; //skip new lines...
vsnprintf(_buffer, MAX_CLIENT_LOG_MESSAGE_LENGTH, fmt, ap);
@ -123,7 +123,7 @@ void ClientLogs::EQEmuIO_fmt(EQEMuLog::LogIDs id, const char *fmt, va_list ap) {
client_logs.msg(id, _buffer);
}
void ClientLogs::EQEmuIO_pva(EQEMuLog::LogIDs id, const char *prefix, const char *fmt, va_list ap) {
void ClientLogs::EQEmuIO_pva(EQEmuLog::LogIDs id, const char *prefix, const char *fmt, va_list ap) {
if(fmt[0] == '\n' || fmt[0] == '\r')
return; //skip new lines...
char *buf = _buffer;

View File

@ -35,21 +35,21 @@ class Client;
class ClientLogs {
public:
static void EQEmuIO_buf(EQEMuLog::LogIDs id, const char *buf, uint8 size, uint32 count);
static void EQEmuIO_fmt(EQEMuLog::LogIDs id, const char *fmt, va_list ap);
static void EQEmuIO_pva(EQEMuLog::LogIDs id, const char *prefix, const char *fmt, va_list ap);
static void EQEmuIO_buf(EQEmuLog::LogIDs id, const char *buf, uint8 size, uint32 count);
static void EQEmuIO_fmt(EQEmuLog::LogIDs id, const char *fmt, va_list ap);
static void EQEmuIO_pva(EQEmuLog::LogIDs id, const char *prefix, const char *fmt, va_list ap);
void subscribe(EQEMuLog::LogIDs id, Client *c);
void unsubscribe(EQEMuLog::LogIDs id, Client *c);
void subscribe(EQEmuLog::LogIDs id, Client *c);
void unsubscribe(EQEmuLog::LogIDs id, Client *c);
void subscribeAll(Client *c);
void unsubscribeAll(Client *c);
void clear(); //unsubscribes everybody
void msg(EQEMuLog::LogIDs id, const char *buf);
void msg(EQEmuLog::LogIDs id, const char *buf);
protected:
std::vector<Client *> entries[EQEMuLog::MaxLogID];
std::vector<Client *> entries[EQEmuLog::MaxLogID];
static char _buffer[MAX_CLIENT_LOG_MESSAGE_LENGTH+1];
};

View File

@ -825,7 +825,7 @@ int32 Client::acmod() {
return (65 + ((agility-300) / 21));
}
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Error, "Error in Client::acmod(): Agility: %i, Level: %i",agility,level);
LogFile->write(EQEmuLog::Error, "Error in Client::acmod(): Agility: %i, Level: %i",agility,level);
#endif
return 0;
};
@ -934,7 +934,7 @@ int32 Client::CalcMaxMana()
break;
}
default: {
LogFile->write(EQEMuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
LogFile->write(EQEmuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
max_mana = 0;
break;
}
@ -955,7 +955,7 @@ int32 Client::CalcMaxMana()
}
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Debug, "Client::CalcMaxMana() called for %s - returning %d", GetName(), max_mana);
LogFile->write(EQEmuLog::Debug, "Client::CalcMaxMana() called for %s - returning %d", GetName(), max_mana);
#endif
return max_mana;
}
@ -1045,14 +1045,14 @@ int32 Client::CalcBaseMana()
break;
}
default: {
LogFile->write(EQEMuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
LogFile->write(EQEmuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
max_m = 0;
break;
}
}
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Debug, "Client::CalcBaseMana() called for %s - returning %d", GetName(), max_m);
LogFile->write(EQEmuLog::Debug, "Client::CalcBaseMana() called for %s - returning %d", GetName(), max_m);
#endif
return max_m;
}

File diff suppressed because it is too large Load Diff

View File

@ -1023,7 +1023,7 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
// Account for merchant lists with gaps.
if (ml.slot >= i) {
if (ml.slot > i)
LogFile->write(EQEMuLog::Debug, "(WARNING) Merchantlist contains gap at slot %d. Merchant: %d, NPC: %d", i, merchant_id, npcid);
LogFile->write(EQEmuLog::Debug, "(WARNING) Merchantlist contains gap at slot %d. Merchant: %d, NPC: %d", i, merchant_id, npcid);
i = ml.slot + 1;
}
}
@ -1187,7 +1187,7 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app)
{
if(app->size != sizeof(MemorizeSpell_Struct))
{
LogFile->write(EQEMuLog::Error,"Wrong size on OP_MemorizeSpell. Got: %i, Expected: %i", app->size, sizeof(MemorizeSpell_Struct));
LogFile->write(EQEmuLog::Error,"Wrong size on OP_MemorizeSpell. Got: %i, Expected: %i", app->size, sizeof(MemorizeSpell_Struct));
DumpPacket(app);
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -135,7 +135,8 @@ enum {
NPC_CHASE_DISTANCE = 40,
ALLOW_TO_TANK = 41,
IGNORE_ROOT_AGGRO_RULES = 42,
MAX_SPECIAL_ATTACK = 43
CASTING_RESIST_DIFF = 43,
MAX_SPECIAL_ATTACK = 44
};
typedef enum { //fear states

View File

@ -781,7 +781,7 @@ bool Corpse::Process() {
spc->zone_id = zone->graveyard_zoneid();
worldserver.SendPacket(pack);
safe_delete(pack);
LogFile->write(EQEMuLog::Debug, "Moved %s player corpse to the designated graveyard in zone %s.", this->GetName(), database.GetZoneName(zone->graveyard_zoneid()));
LogFile->write(EQEmuLog::Debug, "Moved %s player corpse to the designated graveyard in zone %s.", this->GetName(), database.GetZoneName(zone->graveyard_zoneid()));
corpse_db_id = 0;
}
@ -811,10 +811,10 @@ bool Corpse::Process() {
Save();
player_corpse_depop = true;
corpse_db_id = 0;
LogFile->write(EQEMuLog::Debug, "Tagged %s player corpse has burried.", this->GetName());
LogFile->write(EQEmuLog::Debug, "Tagged %s player corpse has burried.", this->GetName());
}
else {
LogFile->write(EQEMuLog::Error, "Unable to bury %s player corpse.", this->GetName());
LogFile->write(EQEmuLog::Error, "Unable to bury %s player corpse.", this->GetName());
return true;
}
}
@ -1017,7 +1017,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
for(; cur != end; ++cur) {
ServerLootItem_Struct* item_data = *cur;
item = database.GetItem(item_data->item_id);
LogFile->write(EQEMuLog::Debug, "Corpse Looting: %s was not sent to client loot window (corpse_dbid: %i, charname: %s(%s))", item->Name, GetCorpseDBID(), client->GetName(), client->GetGM() ? "GM" : "Owner");
LogFile->write(EQEmuLog::Debug, "Corpse Looting: %s was not sent to client loot window (corpse_dbid: %i, charname: %s(%s))", item->Name, GetCorpseDBID(), client->GetName(), client->GetGM() ? "GM" : "Owner");
client->Message(0, "Inaccessable Corpse Item: %s", item->Name);
}
}
@ -1142,7 +1142,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args);
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
if ((RuleB(Character, EnableDiscoveredItems))) {
if (!IsPlayerCorpse() && RuleB(Character, EnableDiscoveredItems)) {
if (client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID))
client->DiscoverItem(inst->GetItem()->ID);
}
@ -1189,33 +1189,31 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
}
}
if (GetPlayerKillItem() != -1){
if (GetPlayerKillItem() != -1) {
SetPlayerKillItemID(0);
}
/* Send message with item link to groups and such */
char *link = 0, *link2 = 0; //just like a db query :-)
client->MakeItemLink(link2, inst);
MakeAnyLenString(&link, "%c" "%s" "%s" "%c",
0x12,
link2,
item->Name,
0x12);
safe_delete_array(link2);
/* Send message with item link to groups and such */
Client::TextLink linker;
linker.SetLinkType(linker.linkItemInst);
linker.SetItemInst(inst);
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, link);
if(!IsPlayerCorpse()) {
auto item_link = linker.GenerateLink();
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
if (!IsPlayerCorpse()) {
Group *g = client->GetGroup();
if(g != nullptr) {
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
} else {
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
}
else {
Raid *r = client->GetRaid();
if(r != nullptr) {
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
}
}
}
safe_delete_array(link);
}
else {
SendEndLootErrorPacket(client);

View File

@ -290,7 +290,7 @@ void Doors::HandleClick(Client* sender, uint8 trigger)
sender->CheckIncreaseSkill(SkillPickLock, nullptr, 1);
#if EQDEBUG>=5
LogFile->write(EQEMuLog::Debug, "Client has lockpicks: skill=%f", modskill);
LogFile->write(EQEmuLog::Debug, "Client has lockpicks: skill=%f", modskill);
#endif
if(GetLockpick() <= modskill)
@ -547,13 +547,13 @@ void Doors::ToggleState(Mob *sender)
}
void Doors::DumpDoor(){
LogFile->write(EQEMuLog::Debug,
LogFile->write(EQEmuLog::Debug,
"db_id:%i door_id:%i zone_name:%s door_name:%s %s",
db_id, door_id, zone_name, door_name, to_string(m_Position).c_str());
LogFile->write(EQEMuLog::Debug,
LogFile->write(EQEmuLog::Debug,
"opentype:%i guild_id:%i lockpick:%i keyitem:%i nokeyring:%i trigger_door:%i trigger_type:%i door_param:%i open:%s",
opentype, guild_id, lockpick, keyitem, nokeyring, trigger_door, trigger_type, door_param, (isopen) ? "open":"closed");
LogFile->write(EQEMuLog::Debug,
LogFile->write(EQEmuLog::Debug,
"dest_zone:%s destination:%s ",
dest_zone, to_string(m_Destination).c_str());
}
@ -632,7 +632,7 @@ int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version)
}
bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version) {
LogFile->write(EQEMuLog::Status, "Loading Doors from database...");
LogFile->write(EQEmuLog::Status, "Loading Doors from database...");
// Door tmpDoor;

View File

@ -460,7 +460,7 @@ bool Client::TrainDiscipline(uint32 itemid) {
const Item_Struct *item = database.GetItem(itemid);
if(item == nullptr) {
Message(13, "Unable to find the tome you turned in!");
LogFile->write(EQEMuLog::Error, "Unable to find turned in tome id %lu\n", (unsigned long)itemid);
LogFile->write(EQEmuLog::Error, "Unable to find turned in tome id %lu\n", (unsigned long)itemid);
return(false);
}

View File

@ -140,7 +140,7 @@ void PerlembParser::ReloadQuests() {
perl = nullptr;
}
LogFile->write(EQEMuLog::Status, "Error re-initializing perlembed: %s", e.what());
LogFile->write(EQEmuLog::Status, "Error re-initializing perlembed: %s", e.what());
throw e.what();
}
@ -232,6 +232,7 @@ int PerlembParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::stri
int PerlembParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
// needs pointer validation on 'item' argument
return EventCommon(evt, item->GetID(), nullptr, nullptr, item, client, extra_data, false, extra_pointers);
}
@ -335,6 +336,9 @@ bool PerlembParser::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
if(!perl)
return false;
if (itm == nullptr)
return false;
if(evt >= _LargestEventID)
return false;
@ -449,6 +453,9 @@ void PerlembParser::LoadGlobalPlayerScript(std::string filename) {
}
void PerlembParser::LoadItemScript(std::string filename, ItemInst *item) {
if (item == nullptr)
return;
std::stringstream package_name;
package_name << "qst_item_" << item->GetID();
@ -855,6 +862,7 @@ void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlaye
}
}
else if(isItemQuest) {
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
const Item_Struct* item = iteminst->GetItem();
package_name = "qst_item_";
package_name += itoa(item->ID);
@ -1292,6 +1300,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
case EVENT_SCALE_CALC:
case EVENT_ITEM_ENTER_ZONE: {
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
ExportVar(package_name.c_str(), "itemid", objid);
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
break;
@ -1299,6 +1308,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
case EVENT_ITEM_CLICK_CAST:
case EVENT_ITEM_CLICK: {
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
ExportVar(package_name.c_str(), "itemid", objid);
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
ExportVar(package_name.c_str(), "slotid", extradata);

View File

@ -270,7 +270,6 @@ XS(XS__unique_spawn)
if(items == 7)
heading = (float)SvNV(ST(6));
Mob *r = quest_manager.unique_spawn(npc_type, grid, unused, xyz_heading(x, y, z, heading));
RETVAL = (r != nullptr) ? r->GetID() : 0;
@ -2267,18 +2266,22 @@ XS(XS__updatetaskactivity)
dXSARGS;
unsigned int task, activity;
int count = 1;
bool ignore_quest_update = false;
if(items == 2) {
task = (int)SvIV(ST(0));
activity = (int)SvIV(ST(1));
quest_manager.updatetaskactivity(task, activity, count);
quest_manager.updatetaskactivity(task, activity, count, false);
}
else if(items == 3) {
else if (items == 3 || items == 4) {
task = (int)SvIV(ST(0));
activity = (int)SvIV(ST(1));
count = (int)SvIV(ST(2));
quest_manager.updatetaskactivity(task, activity, count);
if (items == 4){
bool ignore_quest_update = (bool)SvTRUE(ST(3));
}
quest_manager.updatetaskactivity(task, activity, count, ignore_quest_update);
} else {
Perl_croak(aTHX_ "Usage: updatetaskactivity(task, activity [,count])");
Perl_croak(aTHX_ "Usage: updatetaskactivity(task, activity, [count], [ignore_quest_update])");
}
XSRETURN_EMPTY;
@ -3503,221 +3506,222 @@ EXTERN_C XS(boot_quest)
file[255] = '\0';
if(items != 1)
LogFile->write(EQEMuLog::Error, "boot_quest does not take any arguments.");
LogFile->write(EQEmuLog::Error, "boot_quest does not take any arguments.");
char buf[128]; //shouldent have any function names longer than this.
//add the strcpy stuff to get rid of const warnings....
XS_VERSION_BOOTCHECK ;
newXS(strcpy(buf, "echo"), XS__echo, file);
newXS(strcpy(buf, "say"), XS__say, file);
newXS(strcpy(buf, "me"), XS__me, file);
newXS(strcpy(buf, "summonitem"), XS__summonitem, file);
newXS(strcpy(buf, "write"), XS__write, file);
newXS(strcpy(buf, "spawn"), XS__spawn, file);
newXS(strcpy(buf, "spawn2"), XS__spawn2, file);
newXS(strcpy(buf, "unique_spawn"), XS__unique_spawn, file);
newXS(strcpy(buf, "spawn_from_spawn2"), XS__spawn_from_spawn2, file);
newXS(strcpy(buf, "enable_spawn2"), XS__enable_spawn2, file);
newXS(strcpy(buf, "disable_spawn2"), XS__disable_spawn2, file);
newXS(strcpy(buf, "setstat"), XS__setstat, file);
newXS(strcpy(buf, "incstat"), XS__incstat, file);
newXS(strcpy(buf, "castspell"), XS__castspell, file);
newXS(strcpy(buf, "selfcast"), XS__selfcast, file);
#ifdef BOTS
newXS(strcpy(buf, "botquest"), XS__botquest, file);
newXS(strcpy(buf, "spawnbotcount"), XS__spawnbotcount, file);
newXS(strcpy(buf, "createbotcount"), XS__createbotcount, file);
newXS(strcpy(buf, "createBot"), XS__createBot, file);
#endif //BOTS
newXS(strcpy(buf, "AssignGroupToInstance"), XS__AssignGroupToInstance, file);
newXS(strcpy(buf, "AssignRaidToInstance"), XS__AssignRaidToInstance, file);
newXS(strcpy(buf, "AssignToInstance"), XS__AssignToInstance, file);
newXS(strcpy(buf, "ChooseRandom"), XS__ChooseRandom, file);
newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file);
newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file);
newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file);
newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file);
newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file);
newXS(strcpy(buf, "GetCharactersInInstance"), XS__GetCharactersInInstance, file);
newXS(strcpy(buf, "GetInstanceID"), XS__GetInstanceID, file);
newXS(strcpy(buf, "GetSpellResistType"), XS__GetSpellResistType, file);
newXS(strcpy(buf, "GetSpellTargetType"), XS__GetSpellTargetType, file);
newXS(strcpy(buf, "GetTimeSeconds"), XS__GetTimeSeconds, file);
newXS(strcpy(buf, "GetZoneID"), XS__GetZoneID, file);
newXS(strcpy(buf, "GetZoneLongName"), XS__GetZoneLongName, file);
newXS(strcpy(buf, "IsBeneficialSpell"), XS__IsBeneficialSpell, file);
newXS(strcpy(buf, "IsEffectInSpell"), XS__IsEffectInSpell, file);
newXS(strcpy(buf, "IsRunning"), XS__IsRunning, file);
newXS(strcpy(buf, "LearnRecipe"), XS__LearnRecipe, file);
newXS(strcpy(buf, "MerchantCountItem"), XS__MerchantCountItem, file);
newXS(strcpy(buf, "MerchantSetItem"), XS__MerchantSetItem, file);
newXS(strcpy(buf, "MovePCInstance"), XS__MovePCInstance, file);
newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file);
newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, file);
newXS(strcpy(buf, "SendMail"), XS__SendMail, file);
newXS(strcpy(buf, "SetRunning"), XS__SetRunning, file);
newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file);
newXS(strcpy(buf, "activespeaktask"), XS__activespeaktask, file);
newXS(strcpy(buf, "activetasksinset"), XS__activetasksinset, file);
newXS(strcpy(buf, "addldonloss"), XS__addldonpoints, file);
newXS(strcpy(buf, "addldonpoints"), XS__addldonpoints, file);
newXS(strcpy(buf, "addldonwin"), XS__addldonpoints, file);
newXS(strcpy(buf, "addloot"), XS__addloot, file);
newXS(strcpy(buf, "zone"), XS__zone, file);
newXS(strcpy(buf, "settimer"), XS__settimer, file);
newXS(strcpy(buf, "settimerMS"), XS__settimerMS, file);
newXS(strcpy(buf, "stoptimer"), XS__stoptimer, file);
newXS(strcpy(buf, "stopalltimers"), XS__stopalltimers, file);
newXS(strcpy(buf, "emote"), XS__emote, file);
newXS(strcpy(buf, "shout"), XS__shout, file);
newXS(strcpy(buf, "shout2"), XS__shout2, file);
newXS(strcpy(buf, "gmsay"), XS__gmsay, file);
newXS(strcpy(buf, "depop"), XS__depop, file);
newXS(strcpy(buf, "depop_withtimer"), XS__depop_withtimer, file);
newXS(strcpy(buf, "settarget"), XS__settarget, file);
newXS(strcpy(buf, "follow"), XS__follow, file);
newXS(strcpy(buf, "sfollow"), XS__sfollow, file);
newXS(strcpy(buf, "changedeity"), XS__changedeity, file);
newXS(strcpy(buf, "exp"), XS__exp, file);
newXS(strcpy(buf, "level"), XS__level, file);
newXS(strcpy(buf, "traindisc"), XS__traindisc, file);
newXS(strcpy(buf, "isdisctome"), XS__isdisctome, file);
newXS(strcpy(buf, "safemove"), XS__safemove, file);
newXS(strcpy(buf, "rain"), XS__rain, file);
newXS(strcpy(buf, "snow"), XS__snow, file);
newXS(strcpy(buf, "surname"), XS__surname, file);
newXS(strcpy(buf, "permaclass"), XS__permaclass, file);
newXS(strcpy(buf, "permarace"), XS__permarace, file);
newXS(strcpy(buf, "permagender"), XS__permagender, file);
newXS(strcpy(buf, "scribespells"), XS__scribespells, file);
newXS(strcpy(buf, "traindiscs"), XS__traindiscs, file);
newXS(strcpy(buf, "unscribespells"), XS__unscribespells, file);
newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file);
newXS(strcpy(buf, "givecash"), XS__givecash, file);
newXS(strcpy(buf, "pvp"), XS__pvp, file);
newXS(strcpy(buf, "movepc"), XS__movepc, file);
newXS(strcpy(buf, "gmmove"), XS__gmmove, file);
newXS(strcpy(buf, "movegrp"), XS__movegrp, file);
newXS(strcpy(buf, "doanim"), XS__doanim, file);
newXS(strcpy(buf, "addskill"), XS__addskill, file);
newXS(strcpy(buf, "setlanguage"), XS__setlanguage, file);
newXS(strcpy(buf, "setskill"), XS__setskill, file);
newXS(strcpy(buf, "setallskill"), XS__setallskill, file);
newXS(strcpy(buf, "assigntask"), XS__assigntask, file);
newXS(strcpy(buf, "attack"), XS__attack, file);
newXS(strcpy(buf, "attacknpc"), XS__attacknpc, file);
newXS(strcpy(buf, "attacknpctype"), XS__attacknpctype, file);
newXS(strcpy(buf, "save"), XS__save, file);
newXS(strcpy(buf, "faction"), XS__faction, file);
newXS(strcpy(buf, "setsky"), XS__setsky, file);
newXS(strcpy(buf, "setguild"), XS__setguild, file);
newXS(strcpy(buf, "createguild"), XS__createguild, file);
newXS(strcpy(buf, "settime"), XS__settime, file);
newXS(strcpy(buf, "itemlink"), XS__itemlink, file);
newXS(strcpy(buf, "signal"), XS__signal, file);
newXS(strcpy(buf, "signalwith"), XS__signalwith, file);
newXS(strcpy(buf, "setglobal"), XS__setglobal, file);
newXS(strcpy(buf, "targlobal"), XS__targlobal, file);
newXS(strcpy(buf, "delglobal"), XS__delglobal, file);
newXS(strcpy(buf, "ding"), XS__ding, file);
newXS(strcpy(buf, "rebind"), XS__rebind, file);
newXS(strcpy(buf, "start"), XS__start, file);
newXS(strcpy(buf, "stop"), XS__stop, file);
newXS(strcpy(buf, "pause"), XS__pause, file);
newXS(strcpy(buf, "moveto"), XS__moveto, file);
newXS(strcpy(buf, "resume"), XS__resume, file);
newXS(strcpy(buf, "addldonpoints"), XS__addldonpoints, file);
newXS(strcpy(buf, "addldonwin"), XS__addldonpoints, file);
newXS(strcpy(buf, "addldonloss"), XS__addldonpoints, file);
newXS(strcpy(buf, "setnexthpevent"), XS__setnexthpevent, file);
newXS(strcpy(buf, "setnextinchpevent"), XS__setnextinchpevent, file);
newXS(strcpy(buf, "sethp"), XS__sethp, file);
newXS(strcpy(buf, "respawn"), XS__respawn, file);
newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file);
newXS(strcpy(buf, "ChooseRandom"), XS__ChooseRandom, file);
newXS(strcpy(buf, "set_proximity"), XS__set_proximity, file);
newXS(strcpy(buf, "clear_proximity"), XS__clear_proximity, file);
newXS(strcpy(buf, "enable_proximity_say"), XS__enable_proximity_say, file);
newXS(strcpy(buf, "disable_proximity_say"), XS__disable_proximity_say, file);
newXS(strcpy(buf, "setanim"), XS__setanim, file);
newXS(strcpy(buf, "showgrid"), XS__showgrid, file);
newXS(strcpy(buf, "spawn_condition"), XS__spawn_condition, file);
newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file);
newXS(strcpy(buf, "toggle_spawn_event"), XS__toggle_spawn_event, file);
newXS(strcpy(buf, "has_zone_flag"), XS__has_zone_flag, file);
newXS(strcpy(buf, "set_zone_flag"), XS__set_zone_flag, file);
newXS(strcpy(buf, "clear_zone_flag"), XS__clear_zone_flag, file);
newXS(strcpy(buf, "summonburriedplayercorpse"), XS__summonburriedplayercorpse, file);
newXS(strcpy(buf, "summonallplayercorpses"), XS__summonallplayercorpses, file);
newXS(strcpy(buf, "getplayerburriedcorpsecount"), XS__getplayerburriedcorpsecount, file);
newXS(strcpy(buf, "buryplayercorpse"), XS__buryplayercorpse, file);
newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file);
newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file);
newXS(strcpy(buf, "toggledoorstate"), XS__toggledoorstate, file);
newXS(strcpy(buf, "isdooropen"), XS__isdooropen, file);
newXS(strcpy(buf, "depopall"), XS__depopall, file);
newXS(strcpy(buf, "depopzone"), XS__depopzone, file);
newXS(strcpy(buf, "repopzone"), XS__repopzone, file);
newXS(strcpy(buf, "npcrace"), XS__npcrace, file);
newXS(strcpy(buf, "npcgender"), XS__npcgender, file);
newXS(strcpy(buf, "npcsize"), XS__npcsize, file);
newXS(strcpy(buf, "npctexture"), XS__npctexture, file);
newXS(strcpy(buf, "playerrace"), XS__playerrace, file);
newXS(strcpy(buf, "playergender"), XS__playergender, file);
newXS(strcpy(buf, "playersize"), XS__playersize, file);
newXS(strcpy(buf, "playertexture"), XS__playertexture, file);
newXS(strcpy(buf, "playerfeature"), XS__playerfeature, file);
newXS(strcpy(buf, "npcfeature"), XS__npcfeature, file);
#ifdef BOTS
newXS(strcpy(buf, "botquest"), XS__botquest, file);
newXS(strcpy(buf, "spawnbotcount"), XS__spawnbotcount, file);
newXS(strcpy(buf, "createbotcount"), XS__createbotcount, file);
newXS(strcpy(buf, "createBot"), XS__createBot, file);
#endif //BOTS
newXS(strcpy(buf, "taskselector"), XS__taskselector, file);
newXS(strcpy(buf, "tasksetselector"), XS__tasksetselector, file);
newXS(strcpy(buf, "enabletask"), XS__enabletask, file);
newXS(strcpy(buf, "disabletask"), XS__disabletask, file);
newXS(strcpy(buf, "istaskenabled"), XS__istaskenabled, file);
newXS(strcpy(buf, "istaskactive"), XS__istaskactive, file);
newXS(strcpy(buf, "istaskactivityactive"), XS__istaskactivityactive, file);
newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file);
newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file);
newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file);
newXS(strcpy(buf, "taskexploredarea"), XS__taskexploredarea, file);
newXS(strcpy(buf, "assigntask"), XS__assigntask, file);
newXS(strcpy(buf, "failtask"), XS__failtask, file);
newXS(strcpy(buf, "tasktimeleft"), XS__tasktimeleft, file);
newXS(strcpy(buf, "istaskcompleted"), XS__istaskcompleted, file);
newXS(strcpy(buf, "enabledtaskcount"), XS__enabledtaskcount, file);
newXS(strcpy(buf, "firsttaskinset"), XS__firsttaskinset, file);
newXS(strcpy(buf, "lasttaskinset"), XS__lasttaskinset, file);
newXS(strcpy(buf, "nexttaskinset"), XS__nexttaskinset, file);
newXS(strcpy(buf, "activespeaktask"), XS__activespeaktask, file);
newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file);
newXS(strcpy(buf, "activetasksinset"), XS__activetasksinset, file);
newXS(strcpy(buf, "completedtasksinset"), XS__completedtasksinset, file);
newXS(strcpy(buf, "istaskappropriate"), XS__istaskappropriate, file);
newXS(strcpy(buf, "popup"), XS__popup, file);
newXS(strcpy(buf, "castspell"), XS__castspell, file);
newXS(strcpy(buf, "changedeity"), XS__changedeity, file);
newXS(strcpy(buf, "checktitle"), XS__checktitle, file);
newXS(strcpy(buf, "clear_npctype_cache"), XS__clear_npctype_cache, file);
newXS(strcpy(buf, "clear_proximity"), XS__clear_proximity, file);
newXS(strcpy(buf, "clear_zone_flag"), XS__clear_zone_flag, file);
newXS(strcpy(buf, "clearspawntimers"), XS__clearspawntimers, file);
newXS(strcpy(buf, "ze"), XS__ze, file);
newXS(strcpy(buf, "we"), XS__we, file);
newXS(strcpy(buf, "getlevel"), XS__getlevel, file);
newXS(strcpy(buf, "collectitems"), XS__collectitems, file);
newXS(strcpy(buf, "completedtasksinset"), XS__completedtasksinset, file);
newXS(strcpy(buf, "createdoor"), XS__CreateDoor, file);
newXS(strcpy(buf, "creategroundobject"), XS__CreateGroundObject, file);
newXS(strcpy(buf, "creategroundobjectfrommodel"), XS__CreateGroundObjectFromModel, file);
newXS(strcpy(buf, "createdoor"), XS__CreateDoor, file);
newXS(strcpy(buf, "modifynpcstat"), XS__ModifyNPCStat, file);
newXS(strcpy(buf, "collectitems"), XS__collectitems, file);
newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file);
newXS(strcpy(buf, "MerchantSetItem"), XS__MerchantSetItem, file);
newXS(strcpy(buf, "MerchantCountItem"), XS__MerchantCountItem, file);
newXS(strcpy(buf, "varlink"), XS__varlink, file);
newXS(strcpy(buf, "saylink"), XS__saylink, file);
newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file);
newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file);
newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file);
newXS(strcpy(buf, "GetInstanceID"), XS__GetInstanceID, file);
newXS(strcpy(buf, "GetCharactersInInstance"), XS__GetCharactersInInstance, file);
newXS(strcpy(buf, "AssignToInstance"), XS__AssignToInstance, file);
newXS(strcpy(buf, "AssignGroupToInstance"), XS__AssignGroupToInstance, file);
newXS(strcpy(buf, "AssignRaidToInstance"), XS__AssignRaidToInstance, file);
newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, file);
newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file);
newXS(strcpy(buf, "MovePCInstance"), XS__MovePCInstance, file);
newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file);
newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file);
newXS(strcpy(buf, "SetRunning"), XS__SetRunning, file);
newXS(strcpy(buf, "IsRunning"), XS__IsRunning, file);
newXS(strcpy(buf, "IsEffectInSpell"), XS__IsEffectInSpell, file);
newXS(strcpy(buf, "IsBeneficialSpell"), XS__IsBeneficialSpell, file);
newXS(strcpy(buf, "GetSpellResistType"), XS__GetSpellResistType, file);
newXS(strcpy(buf, "GetSpellTargetType"), XS__GetSpellTargetType, file);
newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file);
newXS(strcpy(buf, "factionvalue"), XS_FactionValue, file);
newXS(strcpy(buf, "checktitle"), XS__checktitle, file);
newXS(strcpy(buf, "enabletitle"), XS__enabletitle, file);
newXS(strcpy(buf, "removetitle"), XS__removetitle, file);
newXS(strcpy(buf, "wearchange"), XS__wearchange, file);
newXS(strcpy(buf, "voicetell"), XS__voicetell, file);
newXS(strcpy(buf, "LearnRecipe"), XS__LearnRecipe, file);
newXS(strcpy(buf, "SendMail"), XS__SendMail, file);
newXS(strcpy(buf, "GetZoneID"), XS__GetZoneID, file);
newXS(strcpy(buf, "GetZoneLongName"), XS__GetZoneLongName, file);
newXS(strcpy(buf, "GetTimeSeconds"), XS__GetTimeSeconds, file);
newXS(strcpy(buf, "createguild"), XS__createguild, file);
newXS(strcpy(buf, "crosszonemessageplayerbyname"), XS__crosszonemessageplayerbyname, file);
newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file);
newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file);
newXS(strcpy(buf, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, file);
newXS(strcpy(buf, "crosszonemessageplayerbyname"), XS__crosszonemessageplayerbyname, file);
newXS(strcpy(buf, "enablerecipe"), XS__enablerecipe, file);
newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file);
newXS(strcpy(buf, "clear_npctype_cache"), XS__clear_npctype_cache, file);
newXS(strcpy(buf, "qs_send_query"), XS__qs_send_query, file);
newXS(strcpy(buf, "qs_player_event"), XS__qs_player_event, file);
newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file);
newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file);
newXS(strcpy(buf, "delglobal"), XS__delglobal, file);
newXS(strcpy(buf, "depop"), XS__depop, file);
newXS(strcpy(buf, "depop_withtimer"), XS__depop_withtimer, file);
newXS(strcpy(buf, "depopall"), XS__depopall, file);
newXS(strcpy(buf, "depopzone"), XS__depopzone, file);
newXS(strcpy(buf, "ding"), XS__ding, file);
newXS(strcpy(buf, "disable_proximity_say"), XS__disable_proximity_say, file);
newXS(strcpy(buf, "disable_spawn2"), XS__disable_spawn2, file);
newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file);
newXS(strcpy(buf, "disabletask"), XS__disabletask, file);
newXS(strcpy(buf, "doanim"), XS__doanim, file);
newXS(strcpy(buf, "echo"), XS__echo, file);
newXS(strcpy(buf, "emote"), XS__emote, file);
newXS(strcpy(buf, "enable_proximity_say"), XS__enable_proximity_say, file);
newXS(strcpy(buf, "enable_spawn2"), XS__enable_spawn2, file);
newXS(strcpy(buf, "enabledtaskcount"), XS__enabledtaskcount, file);
newXS(strcpy(buf, "enablerecipe"), XS__enablerecipe, file);
newXS(strcpy(buf, "enabletask"), XS__enabletask, file);
newXS(strcpy(buf, "enabletitle"), XS__enabletitle, file);
newXS(strcpy(buf, "exp"), XS__exp, file);
newXS(strcpy(buf, "faction"), XS__faction, file);
newXS(strcpy(buf, "factionvalue"), XS_FactionValue, file);
newXS(strcpy(buf, "failtask"), XS__failtask, file);
newXS(strcpy(buf, "firsttaskinset"), XS__firsttaskinset, file);
newXS(strcpy(buf, "follow"), XS__follow, file);
newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file);
newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file);
newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file);
newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file);
newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file);
newXS(strcpy(buf, "getlevel"), XS__getlevel, file);
newXS(strcpy(buf, "getplayerburriedcorpsecount"), XS__getplayerburriedcorpsecount, file);
newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file);
newXS(strcpy(buf, "givecash"), XS__givecash, file);
newXS(strcpy(buf, "gmmove"), XS__gmmove, file);
newXS(strcpy(buf, "gmsay"), XS__gmsay, file);
newXS(strcpy(buf, "has_zone_flag"), XS__has_zone_flag, file);
newXS(strcpy(buf, "incstat"), XS__incstat, file);
newXS(strcpy(buf, "isdisctome"), XS__isdisctome, file);
newXS(strcpy(buf, "isdooropen"), XS__isdooropen, file);
newXS(strcpy(buf, "istaskactive"), XS__istaskactive, file);
newXS(strcpy(buf, "istaskactivityactive"), XS__istaskactivityactive, file);
newXS(strcpy(buf, "istaskappropriate"), XS__istaskappropriate, file);
newXS(strcpy(buf, "istaskcompleted"), XS__istaskcompleted, file);
newXS(strcpy(buf, "istaskenabled"), XS__istaskenabled, file);
newXS(strcpy(buf, "itemlink"), XS__itemlink, file);
newXS(strcpy(buf, "lasttaskinset"), XS__lasttaskinset, file);
newXS(strcpy(buf, "level"), XS__level, file);
newXS(strcpy(buf, "me"), XS__me, file);
newXS(strcpy(buf, "modifynpcstat"), XS__ModifyNPCStat, file);
newXS(strcpy(buf, "movegrp"), XS__movegrp, file);
newXS(strcpy(buf, "movepc"), XS__movepc, file);
newXS(strcpy(buf, "moveto"), XS__moveto, file);
newXS(strcpy(buf, "nexttaskinset"), XS__nexttaskinset, file);
newXS(strcpy(buf, "npcfeature"), XS__npcfeature, file);
newXS(strcpy(buf, "npcgender"), XS__npcgender, file);
newXS(strcpy(buf, "npcrace"), XS__npcrace, file);
newXS(strcpy(buf, "npcsize"), XS__npcsize, file);
newXS(strcpy(buf, "npctexture"), XS__npctexture, file);
newXS(strcpy(buf, "pause"), XS__pause, file);
newXS(strcpy(buf, "permaclass"), XS__permaclass, file);
newXS(strcpy(buf, "permagender"), XS__permagender, file);
newXS(strcpy(buf, "permarace"), XS__permarace, file);
newXS(strcpy(buf, "playerfeature"), XS__playerfeature, file);
newXS(strcpy(buf, "playergender"), XS__playergender, file);
newXS(strcpy(buf, "playerrace"), XS__playerrace, file);
newXS(strcpy(buf, "playersize"), XS__playersize, file);
newXS(strcpy(buf, "playertexture"), XS__playertexture, file);
newXS(strcpy(buf, "popup"), XS__popup, file);
newXS(strcpy(buf, "pvp"), XS__pvp, file);
newXS(strcpy(buf, "qs_player_event"), XS__qs_player_event, file);
newXS(strcpy(buf, "qs_send_query"), XS__qs_send_query, file);
newXS(strcpy(buf, "rain"), XS__rain, file);
newXS(strcpy(buf, "rebind"), XS__rebind, file);
newXS(strcpy(buf, "removetitle"), XS__removetitle, file);
newXS(strcpy(buf, "repopzone"), XS__repopzone, file);
newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file);
newXS(strcpy(buf, "respawn"), XS__respawn, file);
newXS(strcpy(buf, "resume"), XS__resume, file);
newXS(strcpy(buf, "safemove"), XS__safemove, file);
newXS(strcpy(buf, "save"), XS__save, file);
newXS(strcpy(buf, "say"), XS__say, file);
newXS(strcpy(buf, "saylink"), XS__saylink, file);
newXS(strcpy(buf, "scribespells"), XS__scribespells, file);
newXS(strcpy(buf, "selfcast"), XS__selfcast, file);
newXS(strcpy(buf, "set_proximity"), XS__set_proximity, file);
newXS(strcpy(buf, "set_zone_flag"), XS__set_zone_flag, file);
newXS(strcpy(buf, "setallskill"), XS__setallskill, file);
newXS(strcpy(buf, "setanim"), XS__setanim, file);
newXS(strcpy(buf, "setglobal"), XS__setglobal, file);
newXS(strcpy(buf, "setguild"), XS__setguild, file);
newXS(strcpy(buf, "sethp"), XS__sethp, file);
newXS(strcpy(buf, "setlanguage"), XS__setlanguage, file);
newXS(strcpy(buf, "setnexthpevent"), XS__setnexthpevent, file);
newXS(strcpy(buf, "setnextinchpevent"), XS__setnextinchpevent, file);
newXS(strcpy(buf, "setskill"), XS__setskill, file);
newXS(strcpy(buf, "setsky"), XS__setsky, file);
newXS(strcpy(buf, "setstat"), XS__setstat, file);
newXS(strcpy(buf, "settarget"), XS__settarget, file);
newXS(strcpy(buf, "settime"), XS__settime, file);
newXS(strcpy(buf, "settimer"), XS__settimer, file);
newXS(strcpy(buf, "settimerMS"), XS__settimerMS, file);
newXS(strcpy(buf, "sfollow"), XS__sfollow, file);
newXS(strcpy(buf, "shout"), XS__shout, file);
newXS(strcpy(buf, "shout2"), XS__shout2, file);
newXS(strcpy(buf, "showgrid"), XS__showgrid, file);
newXS(strcpy(buf, "signal"), XS__signal, file);
newXS(strcpy(buf, "signalwith"), XS__signalwith, file);
newXS(strcpy(buf, "snow"), XS__snow, file);
newXS(strcpy(buf, "spawn"), XS__spawn, file);
newXS(strcpy(buf, "spawn2"), XS__spawn2, file);
newXS(strcpy(buf, "spawn_condition"), XS__spawn_condition, file);
newXS(strcpy(buf, "spawn_from_spawn2"), XS__spawn_from_spawn2, file);
newXS(strcpy(buf, "start"), XS__start, file);
newXS(strcpy(buf, "stop"), XS__stop, file);
newXS(strcpy(buf, "stopalltimers"), XS__stopalltimers, file);
newXS(strcpy(buf, "stoptimer"), XS__stoptimer, file);
newXS(strcpy(buf, "summonallplayercorpses"), XS__summonallplayercorpses, file);
newXS(strcpy(buf, "summonburriedplayercorpse"), XS__summonburriedplayercorpse, file);
newXS(strcpy(buf, "summonitem"), XS__summonitem, file);
newXS(strcpy(buf, "surname"), XS__surname, file);
newXS(strcpy(buf, "targlobal"), XS__targlobal, file);
newXS(strcpy(buf, "taskexploredarea"), XS__taskexploredarea, file);
newXS(strcpy(buf, "taskselector"), XS__taskselector, file);
newXS(strcpy(buf, "tasksetselector"), XS__tasksetselector, file);
newXS(strcpy(buf, "tasktimeleft"), XS__tasktimeleft, file);
newXS(strcpy(buf, "toggle_spawn_event"), XS__toggle_spawn_event, file);
newXS(strcpy(buf, "toggledoorstate"), XS__toggledoorstate, file);
newXS(strcpy(buf, "traindisc"), XS__traindisc, file);
newXS(strcpy(buf, "traindiscs"), XS__traindiscs, file);
newXS(strcpy(buf, "unique_spawn"), XS__unique_spawn, file);
newXS(strcpy(buf, "unscribespells"), XS__unscribespells, file);
newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file);
newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file);
newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file);
newXS(strcpy(buf, "varlink"), XS__varlink, file);
newXS(strcpy(buf, "voicetell"), XS__voicetell, file);
newXS(strcpy(buf, "we"), XS__we, file);
newXS(strcpy(buf, "wearchange"), XS__wearchange, file);
newXS(strcpy(buf, "write"), XS__write, file);
newXS(strcpy(buf, "ze"), XS__ze, file);
newXS(strcpy(buf, "zone"), XS__zone, file);
XSRETURN_YES;
}

View File

@ -139,12 +139,12 @@ void Embperl::DoInit() {
catch(const char *err)
{
//remember... lasterr() is no good if we crap out here, in construction
LogFile->write(EQEMuLog::Quest, "perl error: %s", err);
LogFile->write(EQEmuLog::Quest, "perl error: %s", err);
throw "failed to install eval_file hook";
}
#ifdef EMBPERL_IO_CAPTURE
LogFile->write(EQEMuLog::Quest, "Tying perl output to eqemu logs");
LogFile->write(EQEmuLog::Quest, "Tying perl output to eqemu logs");
//make a tieable class to capture IO and pass it into EQEMuLog
eval_pv(
"package EQEmuIO; "
@ -169,14 +169,14 @@ void Embperl::DoInit() {
,FALSE
);
LogFile->write(EQEMuLog::Quest, "Loading perlemb plugins.");
LogFile->write(EQEmuLog::Quest, "Loading perlemb plugins.");
try
{
eval_pv("main::eval_file('plugin', 'plugin.pl');", FALSE);
}
catch(const char *err)
{
LogFile->write(EQEMuLog::Quest, "Warning - plugin.pl: %s", err);
LogFile->write(EQEmuLog::Quest, "Warning - plugin.pl: %s", err);
}
try
{
@ -194,7 +194,7 @@ void Embperl::DoInit() {
}
catch(const char *err)
{
LogFile->write(EQEMuLog::Quest, "Perl warning: %s", err);
LogFile->write(EQEmuLog::Quest, "Perl warning: %s", err);
}
#endif //EMBPERL_PLUGIN
in_use = false;
@ -210,6 +210,8 @@ Embperl::~Embperl()
" if(tied *STDERR) { untie(*STDERR); }"
,FALSE);
#endif
PL_perl_destruct_level = 1;
perl_destruct(my_perl);
perl_free(my_perl);
PERL_SYS_TERM();
my_perl = NULL;

View File

@ -63,7 +63,7 @@ EXTERN_C XS(boot_qc)
file[255] = '\0';
if(items != 1)
LogFile->write(EQEMuLog::Error, "boot_qc does not take any arguments.");
LogFile->write(EQEmuLog::Error, "boot_qc does not take any arguments.");
char buf[128]; //shouldent have any function names longer than this.
@ -96,7 +96,7 @@ XS(XS_EQEmuIO_PRINT)
int len = 0;
for(i = 0; *cur != '\0'; i++, cur++) {
if(*cur == '\n') {
LogFile->writebuf(EQEMuLog::Quest, str + pos, 1, len);
LogFile->writebuf(EQEmuLog::Quest, str + pos, 1, len);
len = 0;
pos = i+1;
} else {
@ -104,7 +104,7 @@ XS(XS_EQEmuIO_PRINT)
}
}
if(len > 0) {
LogFile->writebuf(EQEMuLog::Quest, str + pos, 1, len);
LogFile->writebuf(EQEmuLog::Quest, str + pos, 1, len);
}
}

View File

@ -371,7 +371,7 @@ void EntityList::CheckGroupList (const char *fname, const int fline)
{
if (*it == nullptr)
{
LogFile->write(EQEMuLog::Error, "nullptr group, %s:%i", fname, fline);
LogFile->write(EQEmuLog::Error, "nullptr group, %s:%i", fname, fline);
}
}
}
@ -529,12 +529,12 @@ void EntityList::MobProcess()
zone->StartShutdownTimer();
Group *g = GetGroupByMob(mob);
if(g) {
LogFile->write(EQEMuLog::Error, "About to delete a client still in a group.");
LogFile->write(EQEmuLog::Error, "About to delete a client still in a group.");
g->DelMember(mob);
}
Raid *r = entity_list.GetRaidByClient(mob->CastToClient());
if(r) {
LogFile->write(EQEMuLog::Error, "About to delete a client still in a raid.");
LogFile->write(EQEmuLog::Error, "About to delete a client still in a raid.");
r->MemberZoned(mob->CastToClient());
}
entity_list.RemoveClient(id);
@ -566,7 +566,7 @@ void EntityList::AddGroup(Group *group)
uint32 gid = worldserver.NextGroupID();
if (gid == 0) {
LogFile->write(EQEMuLog::Error,
LogFile->write(EQEmuLog::Error,
"Unable to get new group ID from world server. group is going to be broken.");
return;
}
@ -595,7 +595,7 @@ void EntityList::AddRaid(Raid *raid)
uint32 gid = worldserver.NextGroupID();
if (gid == 0) {
LogFile->write(EQEMuLog::Error,
LogFile->write(EQEmuLog::Error,
"Unable to get new group ID from world server. group is going to be broken.");
return;
}
@ -2025,13 +2025,16 @@ void EntityList::RemoveAllNPCs()
void EntityList::RemoveAllMercs()
{
// doesn't clear the data
merc_list.clear();
}
void EntityList::RemoveAllGroups()
{
while (group_list.size())
while (group_list.size()) {
safe_delete(group_list.front());
group_list.pop_front();
}
#if EQDEBUG >= 5
CheckGroupList (__FILE__, __LINE__);
#endif
@ -2039,8 +2042,10 @@ void EntityList::RemoveAllGroups()
void EntityList::RemoveAllRaids()
{
while (raid_list.size())
while (raid_list.size()) {
safe_delete(raid_list.front());
raid_list.pop_front();
}
}
void EntityList::RemoveAllDoors()
@ -2250,7 +2255,8 @@ bool EntityList::RemoveGroup(uint32 delete_id)
while(iterator != group_list.end())
{
if((*iterator)->GetID() == delete_id) {
group_list.remove (*iterator);
safe_delete(*iterator);
group_list.remove(*iterator);
#if EQDEBUG >= 5
CheckGroupList (__FILE__, __LINE__);
#endif
@ -2273,7 +2279,8 @@ bool EntityList::RemoveRaid(uint32 delete_id)
while(iterator != raid_list.end())
{
if((*iterator)->GetID() == delete_id) {
raid_list.remove (*iterator);
safe_delete(*iterator);
raid_list.remove(*iterator);
return true;
}
++iterator;
@ -2433,7 +2440,7 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone)
if (!settoone)
it->second->RemoveFromHateList(mob);
else
it->second->SetHate(mob, 1);
it->second->SetHateAmountOnEnt(mob, 1);
}
++it;
}
@ -2522,7 +2529,7 @@ char *EntityList::MakeNameUnique(char *name)
return name;
}
}
LogFile->write(EQEMuLog::Error, "Fatal error in EntityList::MakeNameUnique: Unable to find unique name for '%s'", name);
LogFile->write(EQEmuLog::Error, "Fatal error in EntityList::MakeNameUnique: Unable to find unique name for '%s'", name);
char tmp[64] = "!";
strn0cpy(&tmp[1], name, sizeof(tmp) - 1);
strcpy(name, tmp);
@ -2817,7 +2824,7 @@ void EntityList::DoubleAggro(Mob *who)
auto it = npc_list.begin();
while (it != npc_list.end()) {
if (it->second->CheckAggro(who))
it->second->SetHate(who, it->second->CastToNPC()->GetHateAmount(who),
it->second->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who),
it->second->CastToNPC()->GetHateAmount(who) * 2);
++it;
}
@ -2828,7 +2835,7 @@ void EntityList::HalveAggro(Mob *who)
auto it = npc_list.begin();
while (it != npc_list.end()) {
if (it->second->CastToNPC()->CheckAggro(who))
it->second->CastToNPC()->SetHate(who, it->second->CastToNPC()->GetHateAmount(who) / 2);
it->second->CastToNPC()->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who) / 2);
++it;
}
}
@ -2843,9 +2850,9 @@ void EntityList::Evade(Mob *who)
amt = it->second->CastToNPC()->GetHateAmount(who);
amt -= flatval;
if (amt > 0)
it->second->CastToNPC()->SetHate(who, amt);
it->second->CastToNPC()->SetHateAmountOnEnt(who, amt);
else
it->second->CastToNPC()->SetHate(who, 0);
it->second->CastToNPC()->SetHateAmountOnEnt(who, 0);
}
++it;
}
@ -2913,7 +2920,7 @@ void EntityList::ClearZoneFeignAggro(Client *targ)
}
}
void EntityList::AggroZone(Mob *who, int hate)
void EntityList::AggroZone(Mob *who, uint32 hate)
{
auto it = npc_list.begin();
while (it != npc_list.end()) {
@ -2934,11 +2941,6 @@ void EntityList::SignalMobsByNPCID(uint32 snpc, int signal_id)
}
}
bool tracking_compare(const std::pair<Mob *, float> &a, const std::pair<Mob *, float> &b)
{
return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp();
}
bool EntityList::MakeTrackPacket(Client *client)
{
std::list<std::pair<Mob *, float> > tracking_list;
@ -2956,8 +2958,6 @@ bool EntityList::MakeTrackPacket(Client *client)
if (distance < 300)
distance = 300;
Group *g = client->GetGroup();
for (auto it = mob_list.cbegin(); it != mob_list.cend(); ++it) {
if (!it->second || it->second == client || !it->second->IsTrackable() ||
it->second->IsInvisible(client))
@ -2970,7 +2970,10 @@ bool EntityList::MakeTrackPacket(Client *client)
tracking_list.push_back(std::make_pair(it->second, MobDistance));
}
tracking_list.sort(tracking_compare);
tracking_list.sort(
[](const std::pair<Mob *, float> &a, const std::pair<Mob *, float> &b) {
return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp();
});
EQApplicationPacket *outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size());
Tracking_Struct *outtrack = (Tracking_Struct *)outapp->pBuffer;
outapp->priority = 6;
@ -2978,15 +2981,13 @@ bool EntityList::MakeTrackPacket(Client *client)
int index = 0;
for (auto it = tracking_list.cbegin(); it != tracking_list.cend(); ++it, ++index) {
Mob *cur_entity = it->first;
outtrack->Entrys[index].entityid = cur_entity->GetID();
outtrack->Entrys[index].entityid = (uint32)cur_entity->GetID();
outtrack->Entrys[index].distance = it->second;
outtrack->Entrys[index].level = cur_entity->GetLevel();
outtrack->Entrys[index].NPC = !cur_entity->IsClient();
if (g && cur_entity->IsClient() && g->IsGroupMember(cur_entity->CastToMob()))
outtrack->Entrys[index].GroupMember = 1;
else
outtrack->Entrys[index].GroupMember = 0;
outtrack->Entrys[index].is_npc = !cur_entity->IsClient();
strn0cpy(outtrack->Entrys[index].name, cur_entity->GetName(), sizeof(outtrack->Entrys[index].name));
outtrack->Entrys[index].is_pet = cur_entity->IsPet();
outtrack->Entrys[index].is_merc = cur_entity->IsMerc();
}
client->QueuePacket(outapp);
@ -3641,7 +3642,7 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
if (n->GetSwarmInfo()) {
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
if (!n->GetSpecialAbility(IMMUNE_AGGRO))
n->hate_list.Add(other, 0, 0, bFrenzy);
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
}
++it;

View File

@ -356,7 +356,7 @@ public:
void ClearAggro(Mob* targ);
void ClearFeignAggro(Mob* targ);
void ClearZoneFeignAggro(Client* targ);
void AggroZone(Mob* who, int hate = 0);
void AggroZone(Mob* who, uint32 hate = 0);
bool Fighting(Mob* targ);
void RemoveFromHateLists(Mob* mob, bool settoone = false);

View File

@ -430,7 +430,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
void Client::SetLevel(uint8 set_level, bool command)
{
if (GetEXPForLevel(set_level) == 0xFFFFFFFF) {
LogFile->write(EQEMuLog::Error,"Client::SetLevel() GetEXPForLevel(%i) = 0xFFFFFFFF", set_level);
LogFile->write(EQEmuLog::Error,"Client::SetLevel() GetEXPForLevel(%i) = 0xFFFFFFFF", set_level);
return;
}
@ -488,7 +488,7 @@ void Client::SetLevel(uint8 set_level, bool command)
safe_delete(outapp);
this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change
LogFile->write(EQEMuLog::Normal,"Setting Level for %s to %i", GetName(), set_level);
LogFile->write(EQEmuLog::Normal,"Setting Level for %s to %i", GetName(), set_level);
CalcBonuses();

View File

@ -58,7 +58,7 @@ uint32 ZoneDatabase::GetZoneForage(uint32 ZoneID, uint8 skill) {
"LIMIT %i", ZoneID, skill, FORAGE_ITEM_LIMIT);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Forage query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in Forage query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return 0;
}
@ -69,7 +69,7 @@ uint32 ZoneDatabase::GetZoneForage(uint32 ZoneID, uint8 skill) {
item[index] = atoi(row[0]);
chance[index] = atoi(row[1]) + chancepool;
LogFile->write(EQEMuLog::Error, "Possible Forage: %d with a %d chance", item[index], chance[index]);
LogFile->write(EQEmuLog::Error, "Possible Forage: %d with a %d chance", item[index], chance[index]);
chancepool = chance[index];
}
@ -250,7 +250,7 @@ void Client::GoFish()
Bait = m_inv.GetItem(bslot);
//if the bait isnt equipped, need to add its skill bonus
if(bslot >= EmuConstants::GENERAL_BEGIN && Bait->GetItem()->SkillModType == SkillFishing) {
if(bslot >= EmuConstants::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == SkillFishing) {
fishing_skill += Bait->GetItem()->SkillModValue;
}
@ -391,7 +391,7 @@ void Client::ForageItem(bool guarantee) {
const Item_Struct* food_item = database.GetItem(foragedfood);
if(!food_item) {
LogFile->write(EQEMuLog::Error, "nullptr returned from database.GetItem in ClientForageItem");
LogFile->write(EQEmuLog::Error, "nullptr returned from database.GetItem in ClientForageItem");
return;
}

View File

@ -26,23 +26,16 @@
extern EntityList entity_list;
extern WorldServer worldserver;
//
// Xorlac: This will need proper synchronization to make it work correctly.
// Also, should investigate client ack for packet to ensure proper synch.
//
/*
note about how groups work:
A group contains 2 list, a list of pointers to members and a
list of member names. All members of a group should have their
name in the membername array, wether they are in the zone or not.
name in the membername array, whether they are in the zone or not.
Only members in this zone will have non-null pointers in the
members array.
*/
//create a group which should allready exist in the database
//create a group which should already exist in the database
Group::Group(uint32 gid)
: GroupIDConsumer(gid)
{
@ -112,8 +105,7 @@ Group::~Group()
}
}
//Cofruben:Split money used in OP_Split.
//Rewritten by Father Nitwit
//Split money used in OP_Split (/split and /autosplit).
void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter) {
//avoid unneeded work
if(copper == 0 && silver == 0 && gold == 0 && platinum == 0)
@ -122,7 +114,8 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
uint32 i;
uint8 membercount = 0;
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (members[i] != nullptr) {
// Don't split with Mercs or Bots
if (members[i] != nullptr && members[i]->IsClient()) {
membercount++;
}
}
@ -196,7 +189,7 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (members[i] != nullptr && members[i]->IsClient()) { // If Group Member is Client
Client *c = members[i]->CastToClient();
Client *c = members[i]->CastToClient();
//I could not get MoneyOnCorpse to work, so we use this
c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
c->Message(2, msg.c_str());
@ -367,7 +360,6 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
void Group::AddMember(const char *NewMemberName)
{
// This method should be called when both the new member and the group leader are in a different zone to this one.
//
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i)
if(!strcasecmp(membername[i], NewMemberName))
{
@ -394,9 +386,8 @@ void Group::QueuePacket(const EQApplicationPacket *app, bool ack_req)
members[i]->CastToClient()->QueuePacket(app, ack_req);
}
// solar: sends the rest of the group's hps to member. this is useful when
// someone first joins a group, but otherwise there shouldn't be a need to
// call it
// Sends the rest of the group's hps to member. this is useful when someone
// first joins a group, but otherwise there shouldn't be a need to call it
void Group::SendHPPacketsTo(Mob *member)
{
if(member && member->IsClient())
@ -458,9 +449,11 @@ void Group::SendHPPacketsFrom(Mob *member)
}
//updates a group member's client pointer when they zone in
//if the group was in the zone allready
//if the group was in the zone already
bool Group::UpdatePlayer(Mob* update){
bool updateSuccess = false;
VerifyGroup();
uint32 i=0;
@ -486,7 +479,8 @@ bool Group::UpdatePlayer(Mob* update){
{
members[i] = update;
members[i]->SetGrouped(true);
return true;
updateSuccess = true;
break;
}
}
@ -494,7 +488,7 @@ bool Group::UpdatePlayer(Mob* update){
if (update->IsClient() && !mentoree && mentoree_name.length() && !mentoree_name.compare(update->GetName()))
mentoree = update->CastToClient();
return false;
return updateSuccess;
}
@ -519,6 +513,7 @@ void Group::MemberZoned(Mob* removemob) {
}
#endif //BOTS
}
if(removemob->IsClient() && HasRole(removemob, RoleAssist))
SetGroupAssistTarget(0);
@ -591,7 +586,7 @@ bool Group::DelMemberOOZ(const char *Name) {
return false;
}
bool Group::DelMember(Mob* oldmember,bool ignoresender)
bool Group::DelMember(Mob* oldmember, bool ignoresender)
{
if (oldmember == nullptr)
{
@ -688,6 +683,8 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender)
if(oldmember->IsClient())
oldmember->CastToClient()->QueuePacket(outapp);
}
safe_delete(outapp);
if(oldmember->IsClient())
{
@ -706,8 +703,6 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender)
oldmember->SetGrouped(false);
disbandcheck = true;
safe_delete(outapp);
if(HasRole(oldmember, RoleTank))
{
SetGroupTankTarget(0);
@ -997,24 +992,21 @@ void Group::SendLeadershipAAUpdate()
// aware of it until they are next in the same zone as the leader.
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct));
GroupJoin_Struct* gu = (GroupJoin_Struct*)outapp->pBuffer;
gu->action = groupActAAUpdate;
uint32 i = 0;
gu->leader_aas = LeaderAbilities;
gu->NPCMarkerID = GetNPCMarkerID();
uint32 i = 0;
for (i = 0;i < MAX_GROUP_MEMBERS; ++i)
{
if(members[i] && members[i]->IsClient())
{
strcpy(gu->yourname, members[i]->GetName());
strcpy(gu->membername, members[i]->GetName());
members[i]->CastToClient()->QueuePacket(outapp);
}
}
safe_delete(outapp);
}
@ -1036,8 +1028,8 @@ uint8 Group::GroupCount() {
uint32 Group::GetHighestLevel()
{
uint32 level = 1;
uint32 i;
uint32 level = 1;
uint32 i;
for (i = 0; i < MAX_GROUP_MEMBERS; i++)
{
if (members[i])
@ -1048,10 +1040,11 @@ uint32 i;
}
return level;
}
uint32 Group::GetLowestLevel()
{
uint32 level = 255;
uint32 i;
uint32 level = 255;
uint32 i;
for (i = 0; i < MAX_GROUP_MEMBERS; i++)
{
if (members[i])
@ -1082,7 +1075,7 @@ bool Group::LearnMembers() {
return false;
if (results.RowCount() == 0) {
LogFile->write(EQEMuLog::Error, "Error getting group members for group %lu: %s", (unsigned long)GetID(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error getting group members for group %lu: %s", (unsigned long)GetID(), results.ErrorMessage().c_str());
return false;
}
@ -1111,18 +1104,16 @@ void Group::VerifyGroup() {
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (membername[i][0] == '\0') {
#if EQDEBUG >= 7
LogFile->write(EQEMuLog::Debug, "Group %lu: Verify %d: Empty.\n", (unsigned long)GetID(), i);
LogFile->write(EQEmuLog::Debug, "Group %lu: Verify %d: Empty.\n", (unsigned long)GetID(), i);
#endif
members[i] = nullptr;
continue;
}
//it should be safe to use GetClientByName, but Group is trying
//to be generic, so we'll go for general Mob
Mob *them = entity_list.GetMob(membername[i]);
if(them == nullptr && members[i] != nullptr) { //they arnt here anymore....
if(them == nullptr && members[i] != nullptr) { //they aren't in zone
#if EQDEBUG >= 6
LogFile->write(EQEMuLog::Debug, "Member of group %lu named '%s' has disappeared!!", (unsigned long)GetID(), membername[i]);
LogFile->write(EQEmuLog::Debug, "Member of group %lu named '%s' has disappeared!!", (unsigned long)GetID(), membername[i]);
#endif
membername[i][0] = '\0';
members[i] = nullptr;
@ -1131,18 +1122,17 @@ LogFile->write(EQEMuLog::Debug, "Group %lu: Verify %d: Empty.\n", (unsigned long
if(them != nullptr && members[i] != them) { //our pointer is out of date... not so good.
#if EQDEBUG >= 5
LogFile->write(EQEMuLog::Debug, "Member of group %lu named '%s' had an out of date pointer!!", (unsigned long)GetID(), membername[i]);
LogFile->write(EQEmuLog::Debug, "Member of group %lu named '%s' had an out of date pointer!!", (unsigned long)GetID(), membername[i]);
#endif
members[i] = them;
continue;
}
#if EQDEBUG >= 8
LogFile->write(EQEMuLog::Debug, "Member of group %lu named '%s' is valid.", (unsigned long)GetID(), membername[i]);
LogFile->write(EQEmuLog::Debug, "Member of group %lu named '%s' is valid.", (unsigned long)GetID(), membername[i]);
#endif
}
}
void Group::GroupMessage_StringID(Mob* sender, uint32 type, uint32 string_id, const char* message,const char* message2,const char* message3,const char* message4,const char* message5,const char* message6,const char* message7,const char* message8,const char* message9, uint32 distance) {
uint32 i;
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
@ -1151,13 +1141,14 @@ void Group::GroupMessage_StringID(Mob* sender, uint32 type, uint32 string_id, co
if(members[i] == sender)
continue;
if(!members[i]->IsClient())
continue;
members[i]->Message_StringID(type, string_id, message, message2, message3, message4, message5, message6, message7, message8, message9, 0);
}
}
void Client::LeaveGroup() {
Group *g = GetGroup();
@ -1177,7 +1168,7 @@ void Client::LeaveGroup() {
else
{
g->DelMember(this);
if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g)
if (GetMerc() != nullptr && g == GetMerc()->GetGroup() )
{
GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup());
}
@ -1362,7 +1353,7 @@ void Group::MarkNPC(Mob* Target, int Number)
// Send a packet to all group members in this zone causing the client to prefix the Target mob's name
// with the specified Number.
//
if(!Target || Target->IsClient())
if(!Target || Target->IsClient() || Target->IsMerc())
return;
if((Number < 1) || (Number > MAX_MARKED_NPCS))
@ -1472,7 +1463,7 @@ void Group::DelegateMainTank(const char *NewMainTankName, uint8 toggle)
MainTankName.c_str(), GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group main tank: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to set group main tank: %s\n", results.ErrorMessage().c_str());
}
}
@ -1518,7 +1509,7 @@ void Group::DelegateMainAssist(const char *NewMainAssistName, uint8 toggle)
MainAssistName.c_str(), GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group main assist: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to set group main assist: %s\n", results.ErrorMessage().c_str());
}
}
@ -1565,7 +1556,7 @@ void Group::DelegatePuller(const char *NewPullerName, uint8 toggle)
PullerName.c_str(), GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group main puller: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to set group main puller: %s\n", results.ErrorMessage().c_str());
}
@ -1716,7 +1707,7 @@ void Group::UnDelegateMainTank(const char *OldMainTankName, uint8 toggle)
std::string query = StringFormat("UPDATE group_leaders SET maintank = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group main tank: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to clear group main tank: %s\n", results.ErrorMessage().c_str());
if(!toggle) {
for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
@ -1765,7 +1756,7 @@ void Group::UnDelegateMainAssist(const char *OldMainAssistName, uint8 toggle)
std::string query = StringFormat("UPDATE group_leaders SET assist = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group main assist: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to clear group main assist: %s\n", results.ErrorMessage().c_str());
if(!toggle)
{
@ -1793,7 +1784,7 @@ void Group::UnDelegatePuller(const char *OldPullerName, uint8 toggle)
std::string query = StringFormat("UPDATE group_leaders SET puller = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group main puller: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to clear group main puller: %s\n", results.ErrorMessage().c_str());
if(!toggle) {
for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
@ -1876,7 +1867,7 @@ void Group::SetGroupMentor(int percent, char *name)
mentoree_name.c_str(), mentor_percent, GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group mentor: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to set group mentor: %s\n", results.ErrorMessage().c_str());
}
void Group::ClearGroupMentor()
@ -1887,7 +1878,7 @@ void Group::ClearGroupMentor()
std::string query = StringFormat("UPDATE group_leaders SET mentoree = '', mentor_percent = 0 WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group mentor: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to clear group mentor: %s\n", results.ErrorMessage().c_str());
}
void Group::NotifyAssistTarget(Client *c)
@ -1957,7 +1948,7 @@ void Group::DelegateMarkNPC(const char *NewNPCMarkerName)
NewNPCMarkerName, GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group mark npc: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to set group mark npc: %s\n", results.ErrorMessage().c_str());
}
void Group::NotifyMarkNPC(Client *c)
@ -2038,7 +2029,7 @@ void Group::UnDelegateMarkNPC(const char *OldNPCMarkerName)
std::string query = StringFormat("UPDATE group_leaders SET marknpc = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group marknpc: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to clear group marknpc: %s\n", results.ErrorMessage().c_str());
}
@ -2055,7 +2046,7 @@ void Group::SaveGroupLeaderAA()
safe_delete_array(queryBuffer);
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to store LeadershipAA: %s\n", results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Unable to store LeadershipAA: %s\n", results.ErrorMessage().c_str());
}
@ -2165,7 +2156,6 @@ int8 Group::GetNumberNeedingHealedInGroup(int8 hpr, bool includePets) {
}
}
return needHealed;
}
@ -2227,7 +2217,7 @@ void Group::ChangeLeader(Mob* newleader)
// this changes the current group leader, notifies other members, and updates leadship AA
// if the new leader is invalid, do nothing
if (!newleader)
if (!newleader || !newleader->IsClient())
return;
Mob* oldleader = GetLeader();

View File

@ -413,7 +413,7 @@ bool ZoneDatabase::CheckGuildDoor(uint8 doorid, uint16 guild_id, const char* zon
doorid-128, zone);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in CheckGuildDoor query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in CheckGuildDoor query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
@ -433,7 +433,7 @@ bool ZoneDatabase::SetGuildDoor(uint8 doorid,uint16 guild_id, const char* zone)
guild_id, doorid, zone);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in SetGuildDoor query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in SetGuildDoor query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}

View File

@ -1,19 +1,19 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "client.h"
@ -36,7 +36,7 @@ extern Zone *zone;
HateList::HateList()
{
owner = nullptr;
hate_owner = nullptr;
}
HateList::~HateList()
@ -45,29 +45,29 @@ HateList::~HateList()
// added for frenzy support
// checks if target still is in frenzy mode
void HateList::CheckFrenzyHate()
void HateList::IsEntityInFrenzyMode()
{
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
if ((*iterator)->ent->GetHPRatio() >= 20)
(*iterator)->bFrenzy = false;
if ((*iterator)->entity_on_hatelist->GetHPRatio() >= 20)
(*iterator)->is_entity_frenzy = false;
++iterator;
}
}
void HateList::Wipe()
void HateList::WipeHateList()
{
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
Mob* m = (*iterator)->ent;
if(m)
Mob* m = (*iterator)->entity_on_hatelist;
if (m)
{
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), m, "0", 0);
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0);
if(m->IsClient())
if (m->IsClient())
m->CastToClient()->DecrementAggroCount();
}
delete (*iterator);
@ -76,38 +76,38 @@ void HateList::Wipe()
}
}
bool HateList::IsOnHateList(Mob *mob)
bool HateList::IsEntOnHateList(Mob *mob)
{
if(Find(mob))
if (Find(mob))
return true;
return false;
}
tHateEntry *HateList::Find(Mob *ent)
struct_HateList *HateList::Find(Mob *in_entity)
{
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
if((*iterator)->ent == ent)
if ((*iterator)->entity_on_hatelist == in_entity)
return (*iterator);
++iterator;
}
return nullptr;
}
void HateList::Set(Mob* other, uint32 in_hate, uint32 in_dam)
void HateList::SetHateAmountOnEnt(Mob* other, uint32 in_hate, uint32 in_damage)
{
tHateEntry *p = Find(other);
if(p)
struct_HateList *entity = Find(other);
if (entity)
{
if(in_dam > 0)
p->damage = in_dam;
if(in_hate > 0)
p->hate = in_hate;
if (in_damage > 0)
entity->hatelist_damage = in_damage;
if (in_hate > 0)
entity->stored_hate_amount = in_hate;
}
}
Mob* HateList::GetDamageTop(Mob* hater)
Mob* HateList::GetDamageTopOnHateList(Mob* hater)
{
Mob* current = nullptr;
Group* grp = nullptr;
@ -115,119 +115,117 @@ Mob* HateList::GetDamageTop(Mob* hater)
uint32 dmg_amt = 0;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
grp = nullptr;
r = nullptr;
if((*iterator)->ent && (*iterator)->ent->IsClient()){
r = entity_list.GetRaidByClient((*iterator)->ent->CastToClient());
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient()){
r = entity_list.GetRaidByClient((*iterator)->entity_on_hatelist->CastToClient());
}
grp = entity_list.GetGroupByMob((*iterator)->ent);
grp = entity_list.GetGroupByMob((*iterator)->entity_on_hatelist);
if((*iterator)->ent && r){
if(r->GetTotalRaidDamage(hater) >= dmg_amt)
if ((*iterator)->entity_on_hatelist && r){
if (r->GetTotalRaidDamage(hater) >= dmg_amt)
{
current = (*iterator)->ent;
current = (*iterator)->entity_on_hatelist;
dmg_amt = r->GetTotalRaidDamage(hater);
}
}
else if ((*iterator)->ent != nullptr && grp != nullptr)
else if ((*iterator)->entity_on_hatelist != nullptr && grp != nullptr)
{
if (grp->GetTotalGroupDamage(hater) >= dmg_amt)
{
current = (*iterator)->ent;
current = (*iterator)->entity_on_hatelist;
dmg_amt = grp->GetTotalGroupDamage(hater);
}
}
else if ((*iterator)->ent != nullptr && (uint32)(*iterator)->damage >= dmg_amt)
else if ((*iterator)->entity_on_hatelist != nullptr && (uint32)(*iterator)->hatelist_damage >= dmg_amt)
{
current = (*iterator)->ent;
dmg_amt = (*iterator)->damage;
current = (*iterator)->entity_on_hatelist;
dmg_amt = (*iterator)->hatelist_damage;
}
++iterator;
}
return current;
}
Mob* HateList::GetClosest(Mob *hater) {
Mob* close = nullptr;
float closedist = 99999.9f;
float thisdist;
Mob* HateList::GetClosestEntOnHateList(Mob *hater) {
Mob* close_entity = nullptr;
float close_distance = 99999.9f;
float this_distance;
auto iterator = list.begin();
while(iterator != list.end()) {
thisdist = (*iterator)->ent->DistNoRootNoZ(*hater);
if((*iterator)->ent != nullptr && thisdist <= closedist) {
closedist = thisdist;
close = (*iterator)->ent;
while (iterator != list.end()) {
this_distance = (*iterator)->entity_on_hatelist->DistNoRootNoZ(*hater);
if ((*iterator)->entity_on_hatelist != nullptr && this_distance <= close_distance) {
close_distance = this_distance;
close_entity = (*iterator)->entity_on_hatelist;
}
++iterator;
}
if ((!close && hater->IsNPC()) || (close && close->DivineAura()))
close = hater->CastToNPC()->GetHateTop();
if ((!close_entity && hater->IsNPC()) || (close_entity && close_entity->DivineAura()))
close_entity = hater->CastToNPC()->GetHateTop();
return close;
return close_entity;
}
// a few comments added, rearranged code for readability
void HateList::Add(Mob *ent, int32 in_hate, int32 in_dam, bool bFrenzy, bool iAddIfNotExist)
void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, bool in_is_entity_frenzied, bool iAddIfNotExist)
{
if(!ent)
if (!in_entity)
return;
if(ent->IsCorpse())
if (in_entity->IsCorpse())
return;
if(ent->IsClient() && ent->CastToClient()->IsDead())
if (in_entity->IsClient() && in_entity->CastToClient()->IsDead())
return;
tHateEntry *p = Find(ent);
if (p)
struct_HateList *entity = Find(in_entity);
if (entity)
{
p->damage+=(in_dam>=0)?in_dam:0;
p->hate+=in_hate;
p->bFrenzy = bFrenzy;
entity->hatelist_damage += (in_damage >= 0) ? in_damage : 0;
entity->stored_hate_amount += in_hate;
entity->is_entity_frenzy = in_is_entity_frenzied;
}
else if (iAddIfNotExist) {
p = new tHateEntry;
p->ent = ent;
p->damage = (in_dam>=0)?in_dam:0;
p->hate = in_hate;
p->bFrenzy = bFrenzy;
list.push_back(p);
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "1", 0);
entity = new struct_HateList;
entity->entity_on_hatelist = in_entity;
entity->hatelist_damage = (in_damage >= 0) ? in_damage : 0;
entity->stored_hate_amount = in_hate;
entity->is_entity_frenzy = in_is_entity_frenzied;
list.push_back(entity);
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "1", 0);
if (ent->IsClient()) {
if (owner->CastToNPC()->IsRaidTarget())
ent->CastToClient()->SetEngagedRaidTarget(true);
ent->CastToClient()->IncrementAggroCount();
if (in_entity->IsClient()) {
if (hate_owner->CastToNPC()->IsRaidTarget())
in_entity->CastToClient()->SetEngagedRaidTarget(true);
in_entity->CastToClient()->IncrementAggroCount();
}
}
}
bool HateList::RemoveEnt(Mob *ent)
bool HateList::RemoveEntFromHateList(Mob *in_entity)
{
if (!ent)
if (!in_entity)
return false;
bool found = false;
bool is_found = false;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
if((*iterator)->ent == ent)
if ((*iterator)->entity_on_hatelist == in_entity)
{
if(ent)
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "0", 0);
found = true;
if (in_entity)
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0);
is_found = true;
if(ent && ent->IsClient())
ent->CastToClient()->DecrementAggroCount();
if (in_entity && in_entity->IsClient())
in_entity->CastToClient()->DecrementAggroCount();
delete (*iterator);
iterator = list.erase(iterator);
@ -236,124 +234,128 @@ bool HateList::RemoveEnt(Mob *ent)
else
++iterator;
}
return found;
return is_found;
}
void HateList::DoFactionHits(int32 nfl_id) {
if (nfl_id <= 0)
void HateList::DoFactionHits(int32 npc_faction_level_id) {
if (npc_faction_level_id <= 0)
return;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
Client *p;
Client *client;
if ((*iterator)->ent && (*iterator)->ent->IsClient())
p = (*iterator)->ent->CastToClient();
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient())
client = (*iterator)->entity_on_hatelist->CastToClient();
else
p = nullptr;
client = nullptr;
if (p)
p->SetFactionLevel(p->CharacterID(), nfl_id, p->GetBaseClass(), p->GetBaseRace(), p->GetDeity());
if (client)
client->SetFactionLevel(client->CharacterID(), npc_faction_level_id, client->GetBaseClass(), client->GetBaseRace(), client->GetDeity());
++iterator;
}
}
int HateList::SummonedPetCount(Mob *hater) {
int HateList::GetSummonedPetCountOnHateList(Mob *hater) {
//Function to get number of 'Summoned' pets on a targets hate list to allow calculations for certian spell effects.
//Unclear from description that pets are required to be 'summoned body type'. Will not require at this time.
int petcount = 0;
int pet_count = 0;
auto iterator = list.begin();
while(iterator != list.end()) {
while (iterator != list.end()) {
if((*iterator)->ent != nullptr && (*iterator)->ent->IsNPC() && ((*iterator)->ent->CastToNPC()->IsPet() || ((*iterator)->ent->CastToNPC()->GetSwarmOwner() > 0)))
if ((*iterator)->entity_on_hatelist != nullptr && (*iterator)->entity_on_hatelist->IsNPC() && ((*iterator)->entity_on_hatelist->CastToNPC()->IsPet() || ((*iterator)->entity_on_hatelist->CastToNPC()->GetSwarmOwner() > 0)))
{
++petcount;
++pet_count;
}
++iterator;
}
return petcount;
return pet_count;
}
Mob *HateList::GetTop(Mob *center)
Mob *HateList::GetEntWithMostHateOnList(Mob *center)
{
Mob* top = nullptr;
int32 hate = -1;
if(center == nullptr)
// hack fix for zone shutdown crashes on some servers
if (!zone->IsLoaded())
return nullptr;
if (RuleB(Aggro,SmartAggroList)){
Mob* topClientTypeInRange = nullptr;
int32 hateClientTypeInRange = -1;
Mob* top_hate = nullptr;
int32 hate = -1;
if (center == nullptr)
return nullptr;
if (RuleB(Aggro, SmartAggroList)){
Mob* top_client_type_in_range = nullptr;
int32 hate_client_type_in_range = -1;
int skipped_count = 0;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
tHateEntry *cur = (*iterator);
int16 aggroMod = 0;
struct_HateList *cur = (*iterator);
int16 aggro_mod = 0;
if(!cur){
if (!cur){
++iterator;
continue;
}
if(!cur->ent){
if (!cur->entity_on_hatelist){
++iterator;
continue;
}
auto hateEntryPosition = xyz_location(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ());
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(hateEntryPosition)) {
auto hateEntryPosition = xyz_location(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ());
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if (!zone->watermap->InLiquid(hateEntryPosition)) {
skipped_count++;
++iterator;
continue;
}
}
if (cur->ent->Sanctuary()) {
if(hate == -1)
if (cur->entity_on_hatelist->Sanctuary()) {
if (hate == -1)
{
top = cur->ent;
top_hate = cur->entity_on_hatelist;
hate = 1;
}
++iterator;
continue;
}
if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){
if(hate == -1)
if (cur->entity_on_hatelist->DivineAura() || cur->entity_on_hatelist->IsMezzed() || cur->entity_on_hatelist->IsFeared()){
if (hate == -1)
{
top = cur->ent;
top_hate = cur->entity_on_hatelist;
hate = 0;
}
++iterator;
continue;
}
int32 currentHate = cur->hate;
int32 current_hate = cur->stored_hate_amount;
if(cur->ent->IsClient()){
if (cur->entity_on_hatelist->IsClient()){
if(cur->ent->CastToClient()->IsSitting()){
aggroMod += RuleI(Aggro, SittingAggroMod);
if (cur->entity_on_hatelist->CastToClient()->IsSitting()){
aggro_mod += RuleI(Aggro, SittingAggroMod);
}
if(center){
if(center->GetTarget() == cur->ent)
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if(center->CombatRange(cur->ent)){
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
if (center->CombatRange(cur->entity_on_hatelist)){
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
if(currentHate > hateClientTypeInRange || cur->bFrenzy){
hateClientTypeInRange = currentHate;
topClientTypeInRange = cur->ent;
if (current_hate > hate_client_type_in_range || cur->is_entity_frenzy){
hate_client_type_in_range = current_hate;
top_client_type_in_range = cur->entity_on_hatelist;
}
}
}
@ -361,113 +363,112 @@ Mob *HateList::GetTop(Mob *center)
}
else{
if(center){
if(center->GetTarget() == cur->ent)
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if(center->CombatRange(cur->ent)){
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
if (center->CombatRange(cur->entity_on_hatelist)){
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
}
}
}
}
if(cur->ent->GetMaxHP() != 0 && ((cur->ent->GetHP()*100/cur->ent->GetMaxHP()) < 20)){
aggroMod += RuleI(Aggro, CriticallyWoundedAggroMod);
if (cur->entity_on_hatelist->GetMaxHP() != 0 && ((cur->entity_on_hatelist->GetHP() * 100 / cur->entity_on_hatelist->GetMaxHP()) < 20)){
aggro_mod += RuleI(Aggro, CriticallyWoundedAggroMod);
}
if(aggroMod){
currentHate += (currentHate * aggroMod / 100);
if (aggro_mod){
current_hate += (current_hate * aggro_mod / 100);
}
if(currentHate > hate || cur->bFrenzy){
hate = currentHate;
top = cur->ent;
if (current_hate > hate || cur->is_entity_frenzy){
hate = current_hate;
top_hate = cur->entity_on_hatelist;
}
++iterator;
}
if(topClientTypeInRange != nullptr && top != nullptr) {
bool isTopClientType = top->IsClient();
if (top_client_type_in_range != nullptr && top_hate != nullptr) {
bool isTopClientType = top_hate->IsClient();
#ifdef BOTS
if(!isTopClientType) {
if(top->IsBot()) {
if (!isTopClientType) {
if (top_hate->IsBot()) {
isTopClientType = true;
topClientTypeInRange = top;
top_client_type_in_range = top_hate;
}
}
#endif //BOTS
if(!isTopClientType) {
if(top->IsMerc()) {
if (!isTopClientType) {
if (top_hate->IsMerc()) {
isTopClientType = true;
topClientTypeInRange = top;
top_client_type_in_range = top_hate;
}
}
if (!isTopClientType) {
if (top->GetSpecialAbility(ALLOW_TO_TANK)){
if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)){
isTopClientType = true;
topClientTypeInRange = top;
top_client_type_in_range = top_hate;
}
}
if(!isTopClientType)
return topClientTypeInRange ? topClientTypeInRange : nullptr;
if (!isTopClientType)
return top_client_type_in_range ? top_client_type_in_range : nullptr;
return top ? top : nullptr;
return top_hate ? top_hate : nullptr;
}
else {
if(top == nullptr && skipped_count > 0) {
if (top_hate == nullptr && skipped_count > 0) {
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top ? top : nullptr;
return top_hate ? top_hate : nullptr;
}
}
else{
auto iterator = list.begin();
int skipped_count = 0;
while(iterator != list.end())
while (iterator != list.end())
{
tHateEntry *cur = (*iterator);
auto hateEntryPosition = xyz_location(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ());
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(hateEntryPosition)) {
struct_HateList *cur = (*iterator);
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if (!zone->watermap->InLiquid(cur->entity_on_hatelist->GetPosition())) {
skipped_count++;
++iterator;
continue;
}
}
if(cur->ent != nullptr && ((cur->hate > hate) || cur->bFrenzy ))
if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy))
{
top = cur->ent;
hate = cur->hate;
top_hate = cur->entity_on_hatelist;
hate = cur->stored_hate_amount;
}
++iterator;
}
if(top == nullptr && skipped_count > 0) {
if (top_hate == nullptr && skipped_count > 0) {
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top ? top : nullptr;
return top_hate ? top_hate : nullptr;
}
return nullptr;
}
Mob *HateList::GetMostHate(){
Mob *HateList::GetEntWithMostHateOnList(){
Mob* top = nullptr;
int32 hate = -1;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
tHateEntry *cur = (*iterator);
if(cur->ent != nullptr && (cur->hate > hate))
struct_HateList *cur = (*iterator);
if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
{
top = cur->ent;
hate = cur->hate;
top = cur->entity_on_hatelist;
hate = cur->stored_hate_amount;
}
++iterator;
}
@ -475,16 +476,16 @@ Mob *HateList::GetMostHate(){
}
Mob *HateList::GetRandom()
Mob *HateList::GetRandomEntOnHateList()
{
int count = list.size();
if(count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
if (count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
return NULL;
if(count == 1) //No need to do all that extra work if we only have one hate entry
if (count == 1) //No need to do all that extra work if we only have one hate entry
{
if(*list.begin()) // Just in case tHateEntry is invalidated somehow...
return (*list.begin())->ent;
if (*list.begin()) // Just in case tHateEntry is invalidated somehow...
return (*list.begin())->entity_on_hatelist;
return NULL;
}
@ -494,38 +495,36 @@ Mob *HateList::GetRandom()
for (int i = 0; i < random; i++)
++iterator;
return (*iterator)->ent;
return (*iterator)->entity_on_hatelist;
}
int32 HateList::GetEntHate(Mob *ent, bool damage)
int32 HateList::GetEntHateAmount(Mob *in_entity, bool damage)
{
tHateEntry *p;
struct_HateList *entity;
p = Find(ent);
entity = Find(in_entity);
if ( p && damage)
return p->damage;
else if (p)
return p->hate;
if (entity && damage)
return entity->hatelist_damage;
else if (entity)
return entity->stored_hate_amount;
else
return 0;
}
//looking for any mob with hate > -1
bool HateList::IsEmpty() {
bool HateList::IsHateListEmpty() {
return(list.size() == 0);
}
// Prints hate list to a client
void HateList::PrintToClient(Client *c)
void HateList::PrintHateListToClient(Client *c)
{
auto iterator = list.begin();
while (iterator != list.end())
{
tHateEntry *e = (*iterator);
struct_HateList *e = (*iterator);
c->Message(0, "- name: %s, damage: %d, hate: %d",
(e->ent && e->ent->GetName()) ? e->ent->GetName() : "(null)",
e->damage, e->hate);
(e->entity_on_hatelist && e->entity_on_hatelist->GetName()) ? e->entity_on_hatelist->GetName() : "(null)",
e->hatelist_damage, e->stored_hate_amount);
++iterator;
}
@ -533,7 +532,7 @@ void HateList::PrintToClient(Client *c)
int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts)
{
if(!target || !caster)
if (!target || !caster)
return 0;
int ret = 0;
@ -541,25 +540,25 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
auto iterator = list.begin();
while (iterator != list.end())
{
tHateEntry *h = (*iterator);
struct_HateList *h = (*iterator);
++iterator;
if(h && h->ent && h->ent != caster)
if (h && h->entity_on_hatelist && h->entity_on_hatelist != caster)
{
if(caster->CombatRange(h->ent))
if (caster->CombatRange(h->entity_on_hatelist))
{
id_list.push_back(h->ent->GetID());
id_list.push_back(h->entity_on_hatelist->GetID());
++ret;
}
}
}
std::list<uint32>::iterator iter = id_list.begin();
while(iter != id_list.end())
while (iter != id_list.end())
{
Mob *cur = entity_list.GetMobID((*iter));
if(cur)
if (cur)
{
for(int i = 0; i < count; ++i) {
for (int i = 0; i < count; ++i) {
caster->Attack(cur, MainPrimary, false, false, false, opts);
}
}
@ -571,7 +570,7 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_center)
{
if(!caster)
if (!caster)
return;
Mob* center = caster;
@ -590,33 +589,32 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent
auto iterator = list.begin();
while (iterator != list.end())
{
tHateEntry *h = (*iterator);
if(range > 0)
struct_HateList *h = (*iterator);
if (range > 0)
{
dist_targ = center->DistNoRoot(*h->ent);
if(dist_targ <= range && dist_targ >= min_range2)
dist_targ = center->DistNoRoot(*h->entity_on_hatelist);
if (dist_targ <= range && dist_targ >= min_range2)
{
id_list.push_back(h->ent->GetID());
h->ent->CalcSpellPowerDistanceMod(spell_id, dist_targ);
id_list.push_back(h->entity_on_hatelist->GetID());
h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, dist_targ);
}
}
else
{
id_list.push_back(h->ent->GetID());
h->ent->CalcSpellPowerDistanceMod(spell_id, 0, caster);
id_list.push_back(h->entity_on_hatelist->GetID());
h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, 0, caster);
}
++iterator;
}
std::list<uint32>::iterator iter = id_list.begin();
while(iter != id_list.end())
while (iter != id_list.end())
{
Mob *cur = entity_list.GetMobID((*iter));
if(cur)
if (cur)
{
caster->SpellOnTarget(spell_id, cur);
}
iter++;
}
}

View File

@ -1,19 +1,19 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef HATELIST_H
@ -25,11 +25,12 @@ class Mob;
class Raid;
struct ExtraAttackOptions;
struct tHateEntry
struct struct_HateList
{
Mob *ent;
int32 damage, hate;
bool bFrenzy;
Mob *entity_on_hatelist;
int32 hatelist_damage;
uint32 stored_hate_amount;
bool is_entity_frenzy;
};
class HateList
@ -38,53 +39,38 @@ public:
HateList();
~HateList();
// adds a mob to the hatelist
void Add(Mob *ent, int32 in_hate=0, int32 in_dam=0, bool bFrenzy = false, bool iAddIfNotExist = true);
// sets existing hate
void Set(Mob *other, uint32 in_hate, uint32 in_dam);
// removes mobs from hatelist
bool RemoveEnt(Mob *ent);
// Remove all
void Wipe();
// ???
void DoFactionHits(int32 nfl_id);
// Gets Hate amount for mob
int32 GetEntHate(Mob *ent, bool damage = false);
// gets top hated mob
Mob *GetTop(Mob *center);
// gets any on the list
Mob *GetRandom();
// get closest mob or nullptr if list empty
Mob *GetClosest(Mob *hater);
// gets top mob or nullptr if hate list empty
Mob *GetDamageTop(Mob *hater);
// used to check if mob is on hatelist
bool IsOnHateList(Mob *);
// used to remove or add frenzy hate
void CheckFrenzyHate();
//Gets the target with the most hate regardless of things like frenzy etc.
Mob* GetMostHate();
// Count 'Summoned' pets on hatelist
int SummonedPetCount(Mob *hater);
Mob *GetClosestEntOnHateList(Mob *hater);
Mob *GetDamageTopOnHateList(Mob *hater);
Mob *GetEntWithMostHateOnList(Mob *center);
Mob *GetRandomEntOnHateList();
Mob* GetEntWithMostHateOnList();
bool IsEntOnHateList(Mob *mob);
bool IsHateListEmpty();
bool RemoveEntFromHateList(Mob *ent);
int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts);
int GetSummonedPetCountOnHateList(Mob *hater);
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
int32 GetEntHateAmount(Mob *ent, bool in_damage = false);
bool IsEmpty();
void PrintToClient(Client *c);
std::list<struct_HateList*>& GetHateList() { return list; }
//For accessing the hate list via perl; don't use for anything else
std::list<tHateEntry*>& GetHateList() { return list; }
void AddEntToHateList(Mob *ent, int32 in_hate = 0, int32 in_damage = 0, bool in_is_frenzied = false, bool add_to_hate_list_if_not_exist = true);
void DoFactionHits(int32 npc_faction_level_id);
void IsEntityInFrenzyMode();
void PrintHateListToClient(Client *c);
void SetHateAmountOnEnt(Mob *other, uint32 in_hate, uint32 in_damage);
void SetHateOwner(Mob *new_hate_owner) { hate_owner = new_hate_owner; }
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
void WipeHateList();
//setting owner
void SetOwner(Mob *newOwner) { owner = newOwner; }
protected:
tHateEntry* Find(Mob *ent);
struct_HateList* Find(Mob *ent);
private:
std::list<tHateEntry*> list;
Mob *owner;
std::list<struct_HateList*> list;
Mob *hate_owner;
};
#endif
#endif

View File

@ -72,12 +72,12 @@ const NPCType *Horse::BuildHorseType(uint16 spell_id) {
std::string query = StringFormat("SELECT race, gender, texture, mountspeed FROM horses WHERE filename = '%s'", fileName);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Mount query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
LogFile->write(EQEmuLog::Error, "Error in Mount query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return nullptr;
}
if (results.RowCount() != 1) {
LogFile->write(EQEMuLog::Error, "No Database entry for mount: %s, check the horses table", fileName);
LogFile->write(EQEmuLog::Error, "No Database entry for mount: %s, check the horses table", fileName);
return nullptr;
}
@ -120,7 +120,7 @@ void Client::SummonHorse(uint16 spell_id) {
return;
}
if(!Horse::IsHorseSpell(spell_id)) {
LogFile->write(EQEMuLog::Error, "%s tried to summon an unknown horse, spell id %d", GetName(), spell_id);
LogFile->write(EQEmuLog::Error, "%s tried to summon an unknown horse, spell id %d", GetName(), spell_id);
return;
}

View File

@ -532,7 +532,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
if(inst == nullptr) {
Message(13, "An unknown server error has occurred and your item was not created.");
// this goes to logfile since this is a major error
LogFile->write(EQEMuLog::Error, "Player %s on account %s encountered an unknown item creation error.\n(Item: %u, Aug1: %u, Aug2: %u, Aug3: %u, Aug4: %u, Aug5: %u, Aug6: %u)\n",
LogFile->write(EQEmuLog::Error, "Player %s on account %s encountered an unknown item creation error.\n(Item: %u, Aug1: %u, Aug2: %u, Aug3: %u, Aug4: %u, Aug5: %u, Aug6: %u)\n",
GetName(), account_name, item->ID, aug1, aug2, aug3, aug4, aug5, aug6);
return false;
@ -617,6 +617,7 @@ void Client::DropItem(int16 slot_id)
// Save client inventory change to database
if (slot_id == MainCursor) {
SendCursorBuffer();
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
database.SaveCursor(CharacterID(), s, e);
} else {
@ -678,10 +679,27 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
return INVALID_ID;
}
void Client::SendCursorBuffer() {
// Temporary work-around for the RoF+ Client Buffer
// Instead of dealing with client moving items in cursor buffer,
// we can just send the next item in the cursor buffer to the cursor.
if (GetClientVersion() >= EQClientRoF)
{
if (!GetInv().CursorEmpty())
{
const ItemInst* inst = GetInv().GetCursorItem();
if (inst)
{
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
}
}
}
}
// Remove item from inventory
void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_update, bool update_db) {
#if (EQDEBUG >= 5)
LogFile->write(EQEMuLog::Debug, "DeleteItemInInventory(%i, %i, %s)", slot_id, quantity, (client_update) ? "true":"false");
LogFile->write(EQEmuLog::Debug, "DeleteItemInInventory(%i, %i, %s)", slot_id, quantity, (client_update) ? "true":"false");
#endif
// Added 'IsSlotValid(slot_id)' check to both segments of client packet processing.
@ -794,10 +812,6 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
}
}
// Puts an item into the person's inventory
// Any items already there will be removed from user's inventory
// (Also saves changes back to the database: this may be optimized in the future)
// client_update: Sends packet to client
bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
{
mlog(INVENTORY__SLOTS, "Putting item %s (%d) on the cursor", inst.GetItem()->Name, inst.GetItem()->ID);
@ -811,6 +825,10 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
return database.SaveCursor(CharacterID(), s, e);
}
// Puts an item into the person's inventory
// Any items already there will be removed from user's inventory
// (Also saves changes back to the database: this may be optimized in the future)
// client_update: Sends packet to client
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) {
mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
@ -908,7 +926,7 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur
bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_cursor, ServerLootItem_Struct** bag_item_data)
{
// #1: Try to auto equip
if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && !inst.GetItem()->Attuneable && inst.GetItem()->ItemType != ItemTypeAugmentation)
if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && (!inst.GetItem()->Attuneable || inst.IsAttuned()) && inst.GetItem()->ItemType != ItemTypeAugmentation)
{
// too messy as-is... <watch>
for (int16 i = EmuConstants::EQUIPMENT_BEGIN; i < MainPowerSource; i++) // originally (i < 22)
@ -1009,105 +1027,113 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
}
}
bool Client::MakeItemLink(char* &ret_link, const ItemInst *inst) {
// TODO: needs clean-up to save references
bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint8 evolving, uint8 evolvedlevel) {
//we're sending back the entire "link", minus the null characters & item name
//that way, we can use it for regular links & Task links
//note: initiator needs to pass us ret_link
/*
/*
--- Usage ---
Chat: "%c" "%s" "%s" "%c", 0x12, ret_link, inst->GetItem()->name, 0x12
Task: "<a WndNotify=\"27," "%s" "\">" "%s" "</a>", ret_link, inst->GetItem()->name
<a WndNotify="27,00960F000000000000000000000000000000000000000">Master's Book of Wood Elven Culture</a>
http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510
*/
<a WndNotify="27,00960F000000000000000000000000000000000000000">Master's Book of Wood Elven Culture</a>
http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510
*/
if (!inst) //have to have an item to make the link
if (!item) //have to have an item to make the link
return false;
const Item_Struct* item = inst->GetItem();
//format:
//0 itemid aug1 aug2 aug3 aug4 aug5 evolving? loregroup evolved level hash
//0 00000 00000 00000 00000 00000 00000 0 0000 0 00000000
//length:
//1 5 5 5 5 5 5 1 4 1 8 = 45
//evolving item info: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=145#558
uint8 evolving = 0;
uint16 loregroup = 0;
uint8 evolvedlevel = 0;
int hash = 0;
//int hash = GetItemLinkHash(inst); //eventually this will work (currently crashes zone), but for now we'll skip the extra overhead
if (GetClientVersion() >= EQClientRoF2)
{
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%01X" "%1X" "%04X" "%1X" "%05X" "%08X",
int hash = NOT_USED;
// Tested with UF and RoF..there appears to be a problem with using non-augment arguments below...
// Currently, enabling them causes misalignments in what the client expects. I haven't looked
// into it further to determine the cause..but, the function is setup to accept the parameters.
// Note: some links appear with '00000' in front of the name..so, it's likely we need to send
// some additional information when certain parameters are true -U
//switch (GetClientVersion()) {
switch (0) {
case EQClientRoF2:
// This operator contains 14 parameter masks..but, only 13 parameter values.
// Even so, the client link appears ok... Need to figure out the discrepancy -U
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
inst->GetAugmentItemID(5),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
aug5,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
0,
hash
);
}
else if (GetClientVersion() >= EQClientRoF)
{
return true;
case EQClientRoF:
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
inst->GetAugmentItemID(5),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
aug5,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
0,
hash
);
}
else if (GetClientVersion() >= EQClientSoF)
{
);
return true;
case EQClientUnderfoot:
case EQClientSoD:
case EQClientSoF:
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
0,
hash
);
}
else
{
);
return true;
case EQClientTitanium:
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
hash
);
);
return true;
case EQClient62:
default:
return false;
}
return true;
}
int Client::GetItemLinkHash(const ItemInst* inst) {
@ -1198,6 +1224,7 @@ int Client::GetItemLinkHash(const ItemInst* inst) {
return hash;
}
// This appears to still be in use... The core of this should be incorporated into class Client::TextLink
void Client::SendItemLink(const ItemInst* inst, bool send_to_all)
{
/*
@ -1299,7 +1326,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// This could be expounded upon at some point to let the server know that
// the client has moved a buffered cursor item onto the active cursor -U
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further proccessing needed
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
return true;
}
@ -1315,13 +1342,15 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
DeleteItemInInventory(move_in->from_slot);
SendCursorBuffer();
return true; // Item destroyed by client
}
else {
mlog(INVENTORY__SLOTS, "Deleted item from slot %d as a result of an inventory container tradeskill combine.", move_in->from_slot);
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
DeleteItemInInventory(move_in->from_slot);
return true; // Item deletetion
return true; // Item deletion
}
}
if(auto_attack && (move_in->from_slot == MainPrimary || move_in->from_slot == MainSecondary || move_in->from_slot == MainRange))
@ -1363,7 +1392,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
//SetTint(dst_slot_id,src_inst->GetColor());
if (src_inst->GetCharges() > 0 && (src_inst->GetCharges() < (int16)move_in->number_in_stack || move_in->number_in_stack > src_inst->GetItem()->StackSize))
{
Message(13,"Error: Insufficent number in stack.");
Message(13,"Error: Insufficient number in stack.");
return false;
}
}
@ -1413,7 +1442,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
//verify shared bank transactions in the database
if(src_inst && src_slot_id >= EmuConstants::SHARED_BANK_BEGIN && src_slot_id <= EmuConstants::SHARED_BANK_BAGS_END) {
if(!database.VerifyInventory(account_id, src_slot_id, src_inst)) {
LogFile->write(EQEMuLog::Error, "Player %s on account %s was found exploiting the shared bank.\n", GetName(), account_name);
LogFile->write(EQEmuLog::Error, "Player %s on account %s was found exploiting the shared bank.\n", GetName(), account_name);
DeleteItemInInventory(dst_slot_id,0,true);
return(false);
}
@ -1428,7 +1457,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
if(dst_inst && dst_slot_id >= EmuConstants::SHARED_BANK_BEGIN && dst_slot_id <= EmuConstants::SHARED_BANK_BAGS_END) {
if(!database.VerifyInventory(account_id, dst_slot_id, dst_inst)) {
LogFile->write(EQEMuLog::Error, "Player %s on account %s was found exploting the shared bank.\n", GetName(), account_name);
LogFile->write(EQEmuLog::Error, "Player %s on account %s was found exploting the shared bank.\n", GetName(), account_name);
DeleteItemInInventory(src_slot_id,0,true);
return(false);
}
@ -1520,11 +1549,19 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
safe_delete(world_inst);
if (src_slot_id == MainCursor) {
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
if (src_slot_id == MainCursor)
{
if (dstitemid == 0)
{
SendCursorBuffer();
}
std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
database.SaveCursor(character_id, s, e);
} else
}
else
{
database.SaveInventory(character_id, m_inv[src_slot_id], src_slot_id);
}
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in, true); } // QS Audit
@ -1551,6 +1588,10 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
trade->AddEntity(dst_slot_id, move_in->number_in_stack);
if (dstitemid == 0)
{
SendCursorBuffer();
}
return true;
} else {
@ -1563,6 +1604,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
}
bool all_to_stack = false;
// Step 5: Swap (or stack) items
if (move_in->number_in_stack > 0) {
// Determine if charged items can stack
@ -1593,6 +1635,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) was entirely consumed. (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, usedcharges);
database.SaveInventory(CharacterID(),nullptr,src_slot_id);
m_inv.DeleteItem(src_slot_id);
all_to_stack = true;
} else {
mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) has %d (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, src_inst->GetCharges(), usedcharges);
}
@ -1666,6 +1709,11 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Step 7: Save change to the database
if (src_slot_id == MainCursor){
// If not swapping another item to cursor and stacking items were depleted
if (dstitemid == 0 || all_to_stack == true)
{
SendCursorBuffer();
}
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
database.SaveCursor(character_id, s, e);
} else
@ -1968,7 +2016,7 @@ void Client::DyeArmor(DyeStruct* dye){
bool Client::DecreaseByID(uint32 type, uint8 amt) {
const Item_Struct* TempItem = 0;
ItemInst* ins;
ItemInst* ins = nullptr;
int x;
int num = 0;
for(x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++)
@ -2104,6 +2152,7 @@ void Client::RemoveNoRent(bool client_update) {
std::list<ItemInst*>::iterator iter = local.begin();
while (iter != local.end()) {
inst = *iter;
// should probably put a check here for valid pointer..but, that was checked when the item was put into inventory -U
if (!inst->GetItem()->NoRent)
mlog(INVENTORY__SLOTS, "NoRent Timer Lapse: Deleting %s from `Limbo`", inst->GetItem()->Name);
else
@ -2229,6 +2278,7 @@ void Client::RemoveDuplicateLore(bool client_update) {
std::list<ItemInst*>::iterator iter = local.begin();
while (iter != local.end()) {
inst = *iter;
// probably needs a valid pointer check -U
if (CheckLoreConflict(inst->GetItem())) {
mlog(INVENTORY__ERROR, "Lore Duplication Error: Deleting %s from `Limbo`", inst->GetItem()->Name);
safe_delete(*iter);
@ -2431,8 +2481,8 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
_log(INVENTORY__BANDOLIER, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name);
strcpy(m_pp.bandoliers[bs->number].name, bs->name);
const ItemInst* InvItem;
const Item_Struct *BaseItem;
const ItemInst* InvItem = nullptr;
const Item_Struct *BaseItem = nullptr;
int16 WeaponSlot;
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {

View File

@ -145,7 +145,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml
drop_chance = zone->random.Real(0.0, 100.0);
#if EQDEBUG>=11
LogFile->write(EQEMuLog::Debug, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance);
LogFile->write(EQEmuLog::Debug, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance);
#endif
if (thischance == 100.0 || drop_chance < thischance)
{
@ -187,7 +187,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
ServerLootItem_Struct* item = new ServerLootItem_Struct;
#if EQDEBUG>=11
LogFile->write(EQEMuLog::Debug, "Adding drop to npc: %s, Item: %i", GetName(), item2->ID);
LogFile->write(EQEmuLog::Debug, "Adding drop to npc: %s, Item: %i", GetName(), item2->ID);
#endif
EQApplicationPacket* outapp = nullptr;
@ -324,7 +324,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
what was this about???
if (((npc->GetRace()==127) && (npc->CastToMob()->GetOwnerID()!=0)) && (item2->Slots==24576) || (item2->Slots==8192) || (item2->Slots==16384)){
npc->d_meele_texture2=atoi(newid);
npc->d_melee_texture2=atoi(newid);
wc->wear_slot_id=8;
if (item2->Material >0)
wc->material=item2->Material;

View File

@ -1354,8 +1354,8 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
LuaCreateNPCParse(max_dmg, uint32, 4);
LuaCreateNPCParse(attack_count, int16, 0);
LuaCreateNPCParseString(special_abilities, 512, "");
LuaCreateNPCParse(d_meele_texture1, uint16, 0);
LuaCreateNPCParse(d_meele_texture2, uint16, 0);
LuaCreateNPCParse(d_melee_texture1, uint16, 0);
LuaCreateNPCParse(d_melee_texture2, uint16, 0);
LuaCreateNPCParseString(ammo_idfile, 32, "");
LuaCreateNPCParse(prim_melee_type, uint8, 0);
LuaCreateNPCParse(sec_melee_type, uint8, 0);

View File

@ -12,42 +12,42 @@
Lua_Mob Lua_HateEntry::GetEnt() {
Lua_Safe_Call_Class(Lua_Mob);
return Lua_Mob(self->ent);
return Lua_Mob(self->entity_on_hatelist);
}
void Lua_HateEntry::SetEnt(Lua_Mob e) {
Lua_Safe_Call_Void();
self->ent = e;
self->entity_on_hatelist = e;
}
int Lua_HateEntry::GetDamage() {
Lua_Safe_Call_Int();
return self->damage;
return self->hatelist_damage;
}
void Lua_HateEntry::SetDamage(int value) {
Lua_Safe_Call_Void();
self->damage = value;
self->hatelist_damage = value;
}
int Lua_HateEntry::GetHate() {
Lua_Safe_Call_Int();
return self->hate;
return self->stored_hate_amount;
}
void Lua_HateEntry::SetHate(int value) {
Lua_Safe_Call_Void();
self->hate = value;
self->stored_hate_amount = value;
}
int Lua_HateEntry::GetFrenzy() {
Lua_Safe_Call_Int();
return self->bFrenzy;
return self->is_entity_frenzy;
}
void Lua_HateEntry::SetFrenzy(bool value) {
Lua_Safe_Call_Void();
self->bFrenzy = value;
self->is_entity_frenzy = value;
}
luabind::scope lua_register_hate_entry() {

View File

@ -5,17 +5,17 @@
#include "lua_ptr.h"
class Lua_Mob;
struct tHateEntry;
struct struct_HateList;
luabind::scope lua_register_hate_entry();
luabind::scope lua_register_hate_list();
class Lua_HateEntry : public Lua_Ptr<tHateEntry>
class Lua_HateEntry : public Lua_Ptr<struct_HateList>
{
typedef tHateEntry NativeType;
typedef struct_HateList NativeType;
public:
Lua_HateEntry() : Lua_Ptr(nullptr) { }
Lua_HateEntry(tHateEntry *d) : Lua_Ptr(d) { }
Lua_HateEntry(struct_HateList *d) : Lua_Ptr(d) { }
virtual ~Lua_HateEntry() { }
Lua_Mob GetEnt();

View File

@ -576,6 +576,11 @@ int Lua_Mob::GetCorruption() {
return self->GetCorrup();
}
int Lua_Mob::GetPhR() {
Lua_Safe_Call_Int();
return self->GetPhR();
}
int Lua_Mob::GetMaxSTR() {
Lua_Safe_Call_Int();
return self->GetMaxSTR();
@ -895,17 +900,17 @@ void Lua_Mob::AddToHateList(Lua_Mob other, int hate, int damage, bool yell_for_h
void Lua_Mob::SetHate(Lua_Mob other) {
Lua_Safe_Call_Void();
self->SetHate(other);
self->SetHateAmountOnEnt(other);
}
void Lua_Mob::SetHate(Lua_Mob other, int hate) {
Lua_Safe_Call_Void();
self->SetHate(other, hate);
self->SetHateAmountOnEnt(other, hate);
}
void Lua_Mob::SetHate(Lua_Mob other, int hate, int damage) {
Lua_Safe_Call_Void();
self->SetHate(other, hate, damage);
self->SetHateAmountOnEnt(other, hate, damage);
}
void Lua_Mob::HalveAggro(Lua_Mob other) {
@ -1962,6 +1967,7 @@ luabind::scope lua_register_mob() {
.def("GetPR", &Lua_Mob::GetPR)
.def("GetCR", &Lua_Mob::GetCR)
.def("GetCorruption", &Lua_Mob::GetCorruption)
.def("GetPhR", &Lua_Mob::GetPhR)
.def("GetMaxSTR", &Lua_Mob::GetMaxSTR)
.def("GetMaxSTA", &Lua_Mob::GetMaxSTA)
.def("GetMaxDEX", &Lua_Mob::GetMaxDEX)

View File

@ -128,6 +128,7 @@ public:
int GetPR();
int GetCR();
int GetCorruption();
int GetPhR();
int GetMaxSTR();
int GetMaxSTA();
int GetMaxDEX();

Some files were not shown because too many files have changed in this diff Show More