From 478eb35a3bbb58f673a615010a805388f99c3f18 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 10 Aug 2014 08:37:30 -0400 Subject: [PATCH 01/15] Rule ArcheryHitPenalty fix for calc mistake from prior update. --- zone/attack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 2403293e6..3195b4234 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -311,7 +311,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c hitBonus += (attacker->CastToNPC()->GetAccuracyRating() / 10.0f); //Modifier from database if(skillinuse == SkillArchery) - hitBonus -= hitBonus*(RuleR(Combat, ArcheryHitPenalty)*100.0f); + hitBonus -= hitBonus*RuleR(Combat, ArcheryHitPenalty); //Calculate final chance to hit chancetohit += ((chancetohit * (hitBonus - avoidanceBonus)) / 100.0f); From 99b25f42e4a52e4dbc61b25b3802c6ff10652f9f Mon Sep 17 00:00:00 2001 From: Michael Cook Date: Sun, 10 Aug 2014 12:42:43 -0400 Subject: [PATCH 02/15] Add Travis-CI bling --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index edee03cca..bee563054 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ EQEmu - Custom Game Implementation for EverQuest +[![Build Status](https://api.travis-ci.org/EQEmu/Server.svg)](https://travis-ci.org/EQEmu/Server) + Dependencies can be obtained at http://eqemu.github.io More Information: https://github.com/EQEmu/Server/wiki From c02cb2c343d352fbf74420fee588be42807de940 Mon Sep 17 00:00:00 2001 From: Michael Cook Date: Sun, 10 Aug 2014 13:08:50 -0400 Subject: [PATCH 03/15] Proper bling instead of copy paste for another [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bee563054..d7ca01121 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ EQEmu - Custom Game Implementation for EverQuest -[![Build Status](https://api.travis-ci.org/EQEmu/Server.svg)](https://travis-ci.org/EQEmu/Server) +[![Build Status](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) Dependencies can be obtained at http://eqemu.github.io From 8940e987c1d7fba36a1f939997590d904ee494b7 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 10 Aug 2014 15:56:58 -0400 Subject: [PATCH 04/15] Fix some compiler warnings --- client_files/export/main.cpp | 4 ++-- client_files/import/main.cpp | 4 ++-- common/shareddb.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client_files/export/main.cpp b/client_files/export/main.cpp index 8aa29bea6..d89976b88 100644 --- a/client_files/export/main.cpp +++ b/client_files/export/main.cpp @@ -70,7 +70,7 @@ void ExportSpells(SharedDatabase *db) { } char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = "SELECT * FROM spells_new ORDER BY id"; + const char *query = "SELECT * FROM spells_new ORDER BY id"; MYSQL_RES *result; MYSQL_ROW row; if(db->RunQuery(query, strlen(query), errbuf, &result)) { @@ -176,7 +176,7 @@ void ExportBaseData(SharedDatabase *db) { } char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = "SELECT * FROM base_data ORDER BY level, class"; + const char *query = "SELECT * FROM base_data ORDER BY level, class"; MYSQL_RES *result; MYSQL_ROW row; if(db->RunQuery(query, strlen(query), errbuf, &result)) { diff --git a/client_files/import/main.cpp b/client_files/import/main.cpp index 8115600bf..d902bc98e 100644 --- a/client_files/import/main.cpp +++ b/client_files/import/main.cpp @@ -61,7 +61,7 @@ int main(int argc, char **argv) { int GetSpellColumns(SharedDatabase *db) { char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = "DESCRIBE spells_new"; + const char *query = "DESCRIBE spells_new"; MYSQL_RES *result; MYSQL_ROW row; int res = 0; @@ -234,4 +234,4 @@ void ImportBaseData(SharedDatabase *db) { } fclose(f); -} \ No newline at end of file +} diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 7c7a99efa..7a9858789 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1775,7 +1775,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { int SharedDatabase::GetMaxBaseDataLevel() { char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = "SELECT MAX(level) FROM base_data"; + const char *query = "SELECT MAX(level) FROM base_data"; MYSQL_RES *result; MYSQL_ROW row; int32 ret = 0; @@ -1826,7 +1826,7 @@ bool SharedDatabase::LoadBaseData() { void SharedDatabase::LoadBaseData(void *data, int max_level) { char *base_ptr = reinterpret_cast(data); char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = "SELECT * FROM base_data ORDER BY level, class ASC"; + const char *query = "SELECT * FROM base_data ORDER BY level, class ASC"; MYSQL_RES *result; MYSQL_ROW row; From 8b2dba97159cff2d382952dd1c7b3492f84e9b91 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 10 Aug 2014 20:13:01 -0400 Subject: [PATCH 05/15] ST_PetMaster target type support added Targets pets master. (Works for regular and swarm pets) --- common/spdat.h | 4 ++-- zone/spells.cpp | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/common/spdat.h b/common/spdat.h index aaf29e61a..40f5e658f 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -131,10 +131,10 @@ typedef enum { /* 41 */ ST_Group = 0x29, /* 42 */ ST_Directional = 0x2a, //ae around this target between two angles /* 43 */ ST_GroupClientAndPet = 0x2b, -/* 44 */ ST_Beam = 0x2c, //like directional but facing in front of you always +/* 44 */ //ST_Beam = 0x2c, //like directional but facing in front of you always /* 45 */ //ST_Ring = 0x2d, // Like a mix of PB ae + rain spell(has ae duration) /* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target -/* 47 */ //ST_PetMaster = 0x2e, // uses the master as target +/* 47 */ ST_PetMaster = 0x2f, // uses the master as target } SpellTargetType; typedef enum { diff --git a/zone/spells.cpp b/zone/spells.cpp index b7b5dd169..5d891629e 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1780,6 +1780,24 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce break; } + case ST_PetMaster: + { + + Mob *owner = nullptr; + + if (IsPet()) + owner = GetOwner(); + else if ((IsNPC() && CastToNPC()->GetSwarmOwner())) + owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner()); + + if (!owner) + return false; + + spell_target = owner; + CastAction = SingleTarget; + break; + } + default: { mlog(SPELLS__CASTING_ERR, "I dont know Target Type: %d Spell: (%d) %s", spells[spell_id].targettype, spell_id, spells[spell_id].name); From 091047d08be6a11caf1018b44da2e3496a6fee51 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 10 Aug 2014 23:07:05 -0400 Subject: [PATCH 06/15] Pretty up the read me [skip ci] --- README.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d7ca01121..f2245dcf4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,53 @@ -EQEmu - Custom Game Implementation for EverQuest +EQEmu +=== [![Build Status](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) -Dependencies can be obtained at http://eqemu.github.io +Overview +--- + +EQEmu is a custom server implementation for EverQuest + +Dependencies +--- + +For Windows: http://eqemu.github.io + +Login Server dependencies for Windows/Linux/OSX: http://eqemu.github.io + +For Debian based distros (adjust to your local flavor): + +- libmysqlclient-dev +- libperl-dev +- liblua5.1-0-dev (5.2 should work as well) +- libboost-dev + +Further instructions on building the source can be found on the +[wiki](http://wiki.eqemulator.org/i?M=Wiki). + +Bug reports +--- + +Please use the [issue tracker](issue-tracker) provided by GitHub to send us bug +reports or feature requests. + +The [EQEmu Forums](http://www.eqemulator.org/forums/) also have forums to submit +bugs/get help with bugs. + +Contributions +--- + +The preferred way to contribute is to fork the repo and submit a pull request on +GitHub. If you need help with your changes, you can always post on the forums or +try IRC. You can also post unified diffs (`git diff` should do the trick) on the +[Server Code Submissions](http://www.eqemulator.org/forums/forumdisplay.php?f=669) +forum, although pull requests will be much quicker and easier on all parties. + +Contact +--- + - **User IRC Channel**: `#eqemu` on `irc.eqemulator.net` + - **Developer IRC Channel**: `#eqemucoders` on `irc.eqemulator.net` + +- [EQEmulator Forums](http://www.eqemulator.org/forums) +- [EQEmulator Wiki](http://wiki.eqemulator.org/i?M=Wiki) -More Information: https://github.com/EQEmu/Server/wiki From cfd636499908ece72ec76ee7c9aaa842479be7dd Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 11 Aug 2014 18:55:00 -0400 Subject: [PATCH 07/15] Re-worked server 'discovery' code to better handle inclusions and exclusions. --- utils/scripts/opcode_handlers.py | 1178 ++++++++++++++++++++++-------- 1 file changed, 868 insertions(+), 310 deletions(-) diff --git a/utils/scripts/opcode_handlers.py b/utils/scripts/opcode_handlers.py index 2a1921d5d..ddad43eda 100644 --- a/utils/scripts/opcode_handlers.py +++ b/utils/scripts/opcode_handlers.py @@ -1,12 +1,15 @@ #! /usr/bin/env python # -# This script generates cross-references to show associated (handled) opcodes -# between the server and client. It will generate files for each client and -# server found, and provide some basic information..such as opcode names and -# values, server handler and whether opcodes are translated on tx/rx, etc... -# -# It's currently limited to the 'Zone' server..but, can be expounded upon to -# include other servers and clients, and other criteria and features. + +""" +'Opcode-Handlers' for EQEmulator + +This script generates cross-references to show associated (handled) opcodes +between the server and client. It will generate files for each client and +server found, and provide some basic information..such as opcode names and +values, server handler and whether opcodes are translated on tx/rx, etc... + +""" import sys @@ -15,122 +18,137 @@ import os from time import time, ctime -DEBUG = 1 # {0 - normal, 1 - verbose, 2 - in-depth} +VERBOSE = False # messaging: {False - minimal, True - robust} base_path = os.getcwd()[:-14] # '/utils/scripts' +base_path = base_path.replace('\\', '/') client_list = ['6.2', 'Titanium', 'SoF', 'SoD', 'Underfoot', 'RoF', 'RoF2', 'ClientTest'] server_list = ['Login', 'World', 'Zone', 'UCS', 'ServerTest'] -client_opcodes = {} -server_opcodes = {} +client_opcodes = {} # x[key='Client'][key='OP_CodeName'](value='0x####') +server_opcodes = {} # x[key='OP_CodeName'](value=) - opcodes apply to all servers -client_encodes = {} -client_decodes = {} +client_encodes = {} # x[key='Client'](value='OP_CodeName') +client_decodes = {} # x[key='Client'](value='OP_CodeName') -server_handlers = {} +server_handlers = {} # x[key='Server'][key='OP_CodeName'](value='[%X] Near Handler::ReferenceFunction') -out_files = {} +out_files = {} # x[key='Server'](value=) + +#statistics = {} +#report_entries = {} def main(): - """ Call each method independently and track success """ + """ Call TASK METHODS independently and track success """ fault = False faults = [] - print('') + print('Initializing...') - if fault is False: + if not fault: fault = not createoutputdirectory() - if fault is True: + if fault: faults.append('createoutputdirectory()') - if fault is False: + if not fault: fault = not opendebugfile() - if fault is True: + if fault: faults.append('opendebugfile()') - if fault is False: + if not fault: + fault = not openundefinedfile() + + if fault: + faults.append('openundefinedfile()') + + if not fault: print('Loading source data...') - if fault is False: + if not fault: fault = not loadclientopcodes() - if fault is True: + if fault: faults.append('loadclientopcodes()') - if fault is False: + if not fault: fault = not loadserveropcodes() - if fault is True: + if fault: faults.append('loadserveropcodes()') - if fault is False: + if not fault: fault = not loadclienttranslators() - if fault is True: + if fault: faults.append('loadclienttranslators()') - if fault is False: + if not fault: fault = not loadserverhandlers() - if fault is True: + if fault: faults.append('loadserverhandlers()') - if fault is False: + if not fault: fault = not discoverserverhandlers() - if fault is True: + if fault: faults.append('discoverserverhandlers()') - if fault is False: + if not fault: fault = not clearemptyserverentries() - if fault is True: + if fault: faults.append('clearemptyserverentries()') - if fault is False: + if not fault: print('Creating output streams...') - if fault is False: + if not fault: fault = not openoutputfiles() - if fault is True: + if fault: faults.append('openoutputfiles()') - if fault is False: + if not fault: print('Parsing opcode data...') - if fault is False: + if not fault: fault = not parseclientopcodedata() - if fault is True: + if fault: faults.append('parseclientopcodedata()') - if fault is False: + if not fault: fault = not parseserveropcodedata() - if fault is True: + if fault: faults.append('parseserveropcodedata()') - if fault is False: + if not fault: print('Destroying output streams...') - # these should always be processed..verbose or silent if not closeoutputfiles(): + fault = True faults.append('closeoutputfiles()') + if not closeundefinedfile(): + fault = True + faults.append('closeundefinedfile()') + if not closedebugfile(): + fault = True faults.append('closedebugfile()') - if len(faults) > 0: + if fault and len(faults) > 0: message = 'Script failed due to errors in:\n' for entry in faults: - message += ' {0}'.format(entry) + message += ' {0}\n'.format(entry) print(message) @@ -138,58 +156,105 @@ def main(): def createoutputdirectory(): - """ Check for output directory - create if does not exist """ + """ Check for OUTPUT DIRECTORY - create if does not exist """ try: output_path = '{0}/utils/scripts/opcode_handlers_output'.format(base_path) - if DEBUG >= 1: - print(output_path) + vprint(output_path) if not os.path.exists(output_path): os.mkdir(output_path) return True except: - if DEBUG >= 2: - print('EXCEPTION ERROR->createoutputdirectory({0})'.format(sys.exc_info()[0])) + print('(Exception Error: {0}) createoutputdirectory()'.format(sys.exc_info()[0])) return False def opendebugfile(): - file_name = '{0}/utils/scripts/opcode_handlers_output/DEBUG.txt'.format(base_path) + """ DEBUG FILE should always open """ - if DEBUG >= 1: - print(file_name) + try: + file_name = '{0}/utils/scripts/opcode_handlers_output/DEBUG.txt'.format(base_path) - out_files['DEBUG'] = open(file_name, 'w') + vprint(file_name) - return True + out_files['DEBUG'] = open(file_name, 'w') + + dprint( + '>> \'Opcode-Handler\' DEBUG dump file\n' + '>> file generated @ {0}\n\n' + '->open: \'{1}\' in \'w\' mode\n' + 'leaving \'opendebugfile()\'\n\n'.format( + ctime(time()), + file_name + ) + ) + + return True + except: + print('(Exception Error: {0}) opendebugfile()'.format(sys.exc_info()[0])) + + return False + + +def openundefinedfile(): + """ UNDEFINED FILE should always open """ + + dprint('entering \'openundefinedfile()\'\n') + + try: + file_name = '{0}/utils/scripts/opcode_handlers_output/Undefined.txt'.format(base_path) + + vprint(file_name) + + out_files['Undefined'] = open(file_name, 'w') + + uprint( + '>> \'Opcode-Handler\' Undefined dump file\n' + '>> file generated @ {0}\n\n'.format(ctime(time())) + ) + + dprint( + '->open: \'{0}\' in \'w\' mode\n' + 'leaving \'openundefinedfile()\'\n\n'.format(file_name) + ) + + return True + except: + print('(Exception Error: {0}) openundefinedfile()'.format(sys.exc_info()[0])) + + return False def loadclientopcodes(): + """ Load CLIENT OPCODES into memory """ + + dprint('entering \'loadclientopcodes()\'\n') + bad_clients = [] for client in client_list: try: - short_name = '{0}{1}{2}'.format( - '/patch_', - client, - '.conf') + short_name = '/patch_{0}.conf'.format(client) - file_name = '{0}{1}{2}'.format( + file_name = '{0}/utils/patches{1}'.format( base_path, - '/utils/patches', - short_name) + short_name + ) - if DEBUG >= 1: - print(file_name) + vprint(file_name) with open(file_name, 'r') as data_file: - client_opcodes[client] = {} # force empty dictionary to avoid collisions + dprint('->open: \'{0}\' in \'r\' mode\n'.format(file_name)) + + client_opcodes[client] = {} + line_no = 0 for data_line in data_file: + line_no += 1 key_begin = data_line.find('OP_') key_end = data_line.find('=', key_begin) @@ -197,7 +262,7 @@ def loadclientopcodes(): continue val_begin = data_line.find('0x', key_end) - val_end = val_begin + 6 # max size is always 6 bytes + val_end = val_begin + 6 if val_begin < 0: continue @@ -209,57 +274,89 @@ def loadclientopcodes(): client_opcodes[client][data_line[key_begin:key_end]] = '0x{0}'.format(hex(value)[2:].zfill(4)) - if DEBUG >= 2: - print('[{0}][{1}] = {2} (int: {3})'.format( - client, - data_line[key_begin:key_end], - client_opcodes[client][data_line[key_begin:key_end]], - value)) + dprint('../utils/patches{0}({1}:{2}) [{3}][{4}] = {5}\n'.format( + short_name, + line_no, + key_begin, + client, + data_line[key_begin:key_end], + client_opcodes[client][data_line[key_begin:key_end]] + )) data_file.close() + + dprint('->close: \'{0}\'\n'.format(file_name)) + + if not len(client_opcodes[client]) > 0: + bad_clients.append(client) except: - if DEBUG >= 2: - print('EXCEPTION ERROR->loadclientopcodes({0})'.format(sys.exc_info()[0])) + print('(Exception Error: {0}) loadclientopcodes() [{1}]'.format( + sys.exc_info()[0], + client + )) + + dprint('<-except: \'{0} [{1}]\'\n'.format( + sys.exc_info()[0], + client + )) bad_clients.append(client) for bad_client in bad_clients: - if DEBUG >= 1: - print('Deleting \'{0}\' client from search criteria...'.format(bad_client)) + vprint('Deleting \'{0}\' client from search criteria...'.format(bad_client)) client_list.remove(bad_client) - if DEBUG >= 1: - print('Deleting stale entries for \'{0}\' client...'.format(bad_client)) + dprint('->delete: \'{0}\' client\n'.format(bad_client)) if bad_client in client_opcodes: + vprint('Deleting stale entries for \'{0}\' client...'.format(bad_client)) + del client_opcodes[bad_client] - + + dprint('->delete: \'{0}\' client opcode entries\n'.format(bad_client)) + if not len(client_list) > 0: + print('Could not locate valid clients...') + + dprint('leaving \'loadclientopcodes(): NO VALID CLIENTS EXIST\'\n\n') + return False + if not len(client_opcodes) > 0: + print('Could not locate client opcode lists...') + + dprint('leaving \'loadclientopcodes(): CLIENT OPCODES NOT FOUND\'\n\n') + + return False + + dprint('leaving \'loadclientopcodes()\'\n\n') + return True def loadserveropcodes(): + """ Load SERVER OPCODES into memory """ + + dprint('entering \'loadserveropcodes()\'\n') + try: - value = 0 + server_opcodes['OP_Unknown'] = 0 + value = 1 - server_opcodes['OP_Unknown'] = value - value += 1 + dprint('(manual) \'Servers\' [OP_Unknown] = {0}\n'.format(server_opcodes['OP_Unknown'])) - if DEBUG >= 2: - print('N[Server](OP_Unknown) = {0}'.format(server_opcodes['OP_Unknown'])) + file_name = '{0}/common/emu_oplist.h'.format(base_path) - file_name = '{0}{1}'.format( - base_path, - '/common/emu_oplist.h') - - if DEBUG >= 1: - print(file_name) + vprint(file_name) with open(file_name, 'r') as data_file: + dprint('->open: \'{0}\' in \'r\' mode\n'.format(file_name)) + + line_no = 0 + for data_line in data_file: + line_no += 1 val_begin = data_line.find('OP_', 2) val_end = data_line.find(')', val_begin) @@ -270,23 +367,28 @@ def loadserveropcodes(): server_opcodes[data_line[val_begin:val_end]] = value value += 1 - if DEBUG >= 2: - print('N[{0}]({1}) = {2}'.format( - 'Server', - data_line[val_begin:val_end], - server_opcodes[data_line[val_begin:val_end]])) + dprint('../common/emu_oplist.h({0}:{1}) \'Servers\' [{2}] = {3}\n'.format( + line_no, + val_begin, + data_line[val_begin:val_end], + server_opcodes[data_line[val_begin:val_end]] + )) data_file.close() - file_name = '{0}{1}'.format( - base_path, - '/common/mail_oplist.h') + dprint('->close: \'{0}\'\n'.format(file_name)) - if DEBUG >= 1: - print(file_name) + file_name = '{0}/common/mail_oplist.h'.format(base_path) + + vprint(file_name) with open(file_name, 'r') as data_file: + dprint('->open: \'{0}\' in \'r\' mode\n'.format(file_name)) + + line_no = 0 + for data_line in data_file: + line_no += 1 val_begin = data_line.find('OP_', 2) val_end = data_line.find(')', val_begin) @@ -297,46 +399,72 @@ def loadserveropcodes(): server_opcodes[data_line[val_begin:val_end]] = value value += 1 - if DEBUG >= 2: - print('N[{0}]({1}) = {2}'.format( - 'Server', - data_line[val_begin:val_end], - server_opcodes[data_line[val_begin:val_end]])) + dprint('../common/mail_oplist.h({0}:{1}) \'Servers\' [{2}] = {3}\n'.format( + line_no, + val_begin, + data_line[val_begin:val_end], + server_opcodes[data_line[val_begin:val_end]] + )) data_file.close() + + dprint('->close: \'{0}\'\n'.format(file_name)) except: - if DEBUG >= 2: - print('EXCEPTION ERROR->loadserveropcodes({0})'.format(sys.exc_info()[0])) + print('(Exception Error: {0}) loadserveropcodes()'.format(sys.exc_info()[0])) + + dprint('leaving \'loadserveropcodes(): EXCEPTION ERROR\'\n\n') return False + if not len(server_opcodes) > 0: + print('Could not locate server opcode list...') + + dprint('leaving \'loadserveropcodes(): SERVER OPCODES NOT FOUND\'\n\n') + + return False + + dprint('leaving \'loadserveropcodes()\'\n\n') + return True def loadclienttranslators(): + """ + Load CLIENT ENCODES and CLIENT DECODES OPCODES into memory + + The CLIENT LIST should be clean of any invalid entries by the time this + function is called. Client translator load failures are only commented + upon in output streams and do not trigger a removal of the client. + + """ + + dprint('entering \'loadclienttranslators()\'\n') + + bad_clients = [] + for client in client_list: - if client == '6.2': - short_name = '{0}'.format('/Client62_ops.h') - else: - short_name = '{0}{1}{2}'.format( - '/', - client, - '_ops.h') - try: - file_name = '{0}{1}{2}'.format( + if client == '6.2': + short_name = '/Client62_ops.h' + else: + short_name = '/{0}_ops.h'.format(client) + + file_name = '{0}/common/patches{1}'.format( base_path, - '/common/patches', - short_name) + short_name + ) - if DEBUG >= 1: - print(file_name) + vprint(file_name) with open(file_name, 'r') as data_file: + dprint('->open: \'{0}\' in \'r\' mode\n'.format(file_name)) + client_encodes[client] = [] client_decodes[client] = [] + line_no = 0 for data_line in data_file: + line_no += 1 val_begin = data_line.find('OP_', 2) val_end = data_line.find(')', val_begin) @@ -345,159 +473,254 @@ def loadclienttranslators(): if data_line[:1] == 'E': client_encodes[client].append(data_line[val_begin:val_end]) - - if DEBUG >= 2: - print('E[{0}]({1}) (listed: {2})'.format( - client, - data_line[val_begin:val_end], - data_line[val_begin:val_end] in client_encodes[client])) + + dprint('..{0}({1}:{2}) \'ENCODE\' [{3}] = {4}\n'.format( + short_name, + line_no, + val_begin, + client, + data_line[val_begin:val_end] + )) elif data_line[:1] == 'D': client_decodes[client].append(data_line[val_begin:val_end]) - if DEBUG >= 2: - print('D[{0}]({1}) (listed: {2})'.format( - client, - data_line[val_begin:val_end], - data_line[val_begin:val_end] in client_decodes[client])) + dprint('..{0}({1}:{2}) \'DECODE\' [{3}] = {4}\n'.format( + short_name, + line_no, + val_begin, + client, + data_line[val_begin:val_end] + )) data_file.close() + + dprint('->close: \'{0}\'\n'.format(file_name)) except: - if DEBUG >= 2: - print('EXCEPTION ERROR->loadclienttranslators({0})'.format(sys.exc_info()[0])) + print('(Exception Error: {0}) loadclienttranslators() [{1}]'.format( + sys.exc_info()[0], + client + )) - return False + dprint('<-except: \'{0} [{1}]\'\n'.format( + sys.exc_info()[0], + client + )) + + bad_clients.append(client) + + for bad_client in bad_clients: + if bad_client in client_encodes or bad_client in client_decodes: + vprint('Deleting stale entries for \'{0}\' client...'.format(bad_client)) + + if bad_client in client_encodes: + del client_encodes[bad_client] + + dprint('->delete: \'{0}\' client encode entries\n'.format(bad_client)) + + if bad_client in client_decodes: + del client_decodes[bad_client] + + dprint('->delete: \'{0}\' client decode entries\n'.format(bad_client)) - # there's always going to be at least one client with one encode or decode if not len(client_encodes) > 0 and not len(client_decodes) > 0: + dprint('leaving \'loadclienttranslators(): NO CLIENT ENCODES OR DECODES FOUND\'\n\n') + return False + dprint('leaving \'loadclienttranslators()\'\n\n') + return True def loadserverhandlers(): - """ Load pre-designated SERVER opcode handlers """ + """ Load pre-designated SERVER OPCODE HANDLERS """ + + # TODO: handle remarked out definitions in file (i.e., // and /**/) + + dprint('entering \'loadserverhandlers()\'\n') - # TODO: handle remarked out definitions in file (i.e., // and /**/); bad_servers = [] for server in server_list: try: if server == 'Login': - if DEBUG >= 1: - print('No pre-designated server opcode handlers for \'{0}\''.format(server)) + vprint('No pre-designated server opcode handlers for \'Login\'') + dprint('->pass: \'Login\' server\n') continue elif server == 'World': - if DEBUG >= 1: - print('No pre-designated server opcode handlers for \'{0}\''.format(server)) + vprint('No pre-designated server opcode handlers for \'World\'') + dprint('->pass: \'World\' server\n') continue elif server == 'Zone': - file_name = '{0}{1}'.format( - base_path, - '/zone/client_packet.cpp') + file_name = '{0}/zone/client_packet.cpp'.format(base_path) - if DEBUG >= 1: - print(file_name) + vprint(file_name) with open(file_name, 'r') as data_file: + dprint('->open: \'{0}\' in \'r\' mode\n'.format(file_name)) + server_handlers[server] = {} - can_run = False + handler_assigns = {} + step_1 = False + step_2 = False line_no = 0 + hint = 'Near beginning of file' for data_line in data_file: line_no += 1 - if can_run is False: + if step_1 is False: if data_line[:19] == 'void MapOpcodes() {': - can_run = True + step_1 = True continue - if data_line[0:1] == '}': - break + if step_2 is False: + if data_line[0:1] == '}': + step_2 = True + + continue + + val_begin = data_line.find('OP_') + val_end = data_line.find(']', val_begin) - key_begin = data_line.find('OP_') - key_end = data_line.find(']', key_begin) + if val_begin < 0 or val_end < 0: + continue + + if not data_line[val_begin:val_end] in server_opcodes: + dprint('\nILLEGAL OPCODE FOUND: ../zone/client_packet.cpp({0}:{1}) \'{2}\'\n'.format( + line_no, + val_begin, + data_line[val_begin:val_end] + )) + + continue + + key_begin = data_line.find('Client::', val_end) + key_end = data_line.find(';', key_begin) - if key_begin < 0 or key_end < 0: - continue - - val_begin = data_line.find('Client::', key_end) - val_end = data_line.find(';', val_begin) - - if val_begin < 0 or val_end < 0: + if key_begin < 0 or key_end < 0: + continue + + if not data_line[key_begin:key_end] in handler_assigns: + handler_assigns[data_line[key_begin:key_end]] = data_line[val_begin:val_end] + continue - # TODO: add continue on 'in server_opcodes' failure + if data_line[:1].isalpha(): + hint_begin = 0 + hint_end = data_line.find('(') - if not data_line[key_begin:key_end] in server_handlers[server]: - server_handlers[server][data_line[key_begin:key_end]] = [] + if not hint_end < 0: + hint_begin = hint_end - 1 - server_handlers[server][data_line[key_begin:key_end]].append( - '../zone/client_packet.cpp({0}:{1}) \'{2}\''.format( + while not hint_begin < 0: + if data_line[(hint_begin - 1):hint_begin].isspace(): + if not data_line[hint_begin:(hint_begin + 1)].isalpha(): + hint_begin += 1 + + hint = '[RX] Near {0}'.format(data_line[hint_begin:hint_end]) + + break + + hint_begin -= 1 + else: + continue + + if hint[10:] in handler_assigns: + if not handler_assigns[hint[10:]] in server_handlers[server]: + server_handlers[server][handler_assigns[hint[10:]]] = [] + + server_handlers[server][handler_assigns[hint[10:]]].append( + '../zone/client_packet.cpp({0}:{1}) \'{2}\''.format( + line_no, + hint_begin, + hint + ) + ) + + dprint('../zone/client_packet.cpp({0}:{1}) [{2}][{3}] = \'{4}\'\n'.format( line_no, - key_begin, - data_line[val_begin:val_end])) - - if DEBUG >= 2: - print('[{0}][{1}]({2}) [{3}]'.format( + hint_begin, server, - data_line[key_begin:key_end], - data_line[val_begin:val_end], - data_line[val_begin:val_end] in server_handlers[server][data_line[key_begin:key_end]])) + handler_assigns[hint[10:]], + hint + )) + + del handler_assigns[hint[10:]] + + if len(handler_assigns) > 0: + for unhandled in handler_assigns: + dprint('\nUNMATCHED DESIGNATED HANDLER FOUND: ../zone/client_packet.cpp \'{0}\'\n'.format( + unhandled + )) data_file.close() + + dprint('->close: \'{0}\'\n'.format(file_name)) elif server == 'UCS': - if DEBUG >= 1: - print('No pre-designated server opcode handlers for \'{0}\''.format(server)) + vprint('No pre-designated server opcode handlers for \'UCS\'') + dprint('->pass: \'UCS\' server\n') continue else: - if DEBUG >= 1: - print('No pre-designated server opcode handlers for \'{0}\''.format(server)) - - if DEBUG >= 2: - print('->LoadServerHandlers(Someone added a new server and forgot to code for the data load...)') + vprint('No pre-designated server opcode handlers for \'{0}\''.format(server)) + dprint('->pass: \'{0}\' server\n'.format(server)) continue except: - if DEBUG >= 2: - print('EXCEPTION ERROR->loadserverhandlers({0})'.format(sys.exc_info()[0])) + print('(Exception Error: {0}) loadserverhandlers() [{1}]'.format( + sys.exc_info()[0], + server + )) + + dprint('<-except: \'{0} [{1}]\'\n'.format( + sys.exc_info()[0], + server + )) bad_servers.append(server) for bad_server in bad_servers: - if DEBUG >= 1: - print('Deleting \'{0}\' server from search criteria...'.format(bad_server)) - - server_list.remove(bad_server) - - if DEBUG >= 1: - print('Deleting stale entries for \'{0}\' server...'.format(bad_server)) - if bad_server in server_handlers: + vprint('Deleting stale entries for \'{0}\' server...'.format(bad_server)) + del server_handlers[bad_server] - if not len(server_list) > 0: - return False + dprint('->delete: \'{0}\' server designated handler entries\n'.format(bad_server)) + + dprint('leaving \'loadserverhandlers()\'\n\n') return True def discoverserverhandlers(): - """ Load undefined SERVER opcode handlers using 'discovery' method """ + """ + Load undefined SERVER OPCODE HANDLERS using 'discovery' method + When adding new servers and/or search locations, use the following format: + + if 'Server' in locations: + locations['Server'].append('//.') + + Lists are instantiated for all SERVERS in SERVER LIST. The lists are then appended + with location data based on the presence of the list in the parent dictionary. + + """ + + # TODO: handle remarked out definitions in file (i.e., // and /**/) + # TODO: if/how to include perl/lua handlers... + + dprint('entering \'discoverserverhandlers()\'\n') + + bad_servers = [] locations = {} - for server in server_list: # initialize lists for any remaining servers - locations[server] = [] - - # manually enter search locations - #if 'Server' in locations: - # locations['Server'].append('//.') - - # TODO: if/how to include perl/lua handlers... + for server in server_list: + if not server in locations: + locations[server] = [] if 'Login' in locations: locations['Login'].append('/loginserver/Client.cpp') @@ -507,8 +730,6 @@ def discoverserverhandlers(): if 'World' in locations: locations['World'].append('/world/client.cpp') - # the bulk of opcodes are handled in 'Zone' - if processing occurs on a different - # server, you will need to manually trace 'ServerPacket' to the deferred location if 'Zone' in locations: locations['Zone'].append('/zone/AA.cpp') locations['Zone'].append('/zone/attack.cpp') @@ -564,10 +785,11 @@ def discoverserverhandlers(): base_path, location) - if DEBUG >= 1: - print(file_name) + vprint(file_name) with open(file_name, 'r') as data_file: + dprint('->open: \'{0}\' in \'r\' mode\n'.format(file_name)) + line_no = 0 hint = 'Near beginning of file' @@ -598,21 +820,192 @@ def discoverserverhandlers(): if data_line[(op_begin - 20):op_begin] == 'EQApplicationPacket(': key_begin = op_begin - key_end = data_line.find(',', key_begin) + key_end = key_begin + 3 + direction = '[TX]' + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 elif data_line[(op_begin - 12):op_begin] == '->SetOpcode(': key_begin = op_begin - key_end = data_line.find(')', key_begin) + key_end = key_begin + 3 + direction = '[TX]' + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 elif data_line[(op_begin - 5):op_begin] == 'case ': key_begin = op_begin - key_end = data_line.find(':', key_begin) + key_end = key_begin + 3 + direction = '[RX]' + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + elif data_line[(op_begin - 3):op_begin] == '== ': + key_begin = op_begin + key_end = key_begin + 3 + direction = '[RX]' + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + elif data_line[(op_begin - 2):op_begin] == '==': + key_begin = op_begin + key_end = key_begin + 3 + direction = '[RX]' + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + elif data_line[(op_begin - 3):op_begin] == '!= ': + key_begin = op_begin + key_end = key_begin + 3 + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + + dprint( + '\nILL-DEFINED OPCODE CONDITIONAL FOUND: ..{0}({1}:{2}) \'{3}\'\n' + '->line: \'{4}\'\n'.format( + location, + line_no, + key_begin, + data_line[key_begin:key_end], + data_line[:-1] + ) + ) + + continue + elif data_line[(op_begin - 2):op_begin] == '!=': + key_begin = op_begin + key_end = key_begin + 3 + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + + dprint( + '\nILL-DEFINED OPCODE CONDITIONAL FOUND: ..{0}({1}:{2}) \'{3}\'\n' + '->line: \'{4}\'\n'.format( + location, + line_no, + key_begin, + data_line[key_begin:key_end], + data_line[:-1] + ) + ) + + continue + elif data_line[(op_begin - 3):op_begin] == '>= ': + key_begin = op_begin + key_end = key_begin + 3 + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + + dprint( + '\nILL-DEFINED OPCODE CONDITIONAL FOUND: ..{0}({1}:{2}) \'{3}\'\n' + '->line: \'{4}\'\n'.format( + location, + line_no, + key_begin, + data_line[key_begin:key_end], + data_line[:-1] + ) + ) + + continue + elif data_line[(op_begin - 2):op_begin] == '>=': + key_begin = op_begin + key_end = key_begin + 3 + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + + dprint( + '\nILL-DEFINED OPCODE CONDITIONAL FOUND: ..{0}({1}:{2}) \'{3}\'\n' + '->line: \'{4}\'\n'.format( + location, + line_no, + key_begin, + data_line[key_begin:key_end], + data_line[:-1] + ) + ) + + continue + elif data_line[(op_begin - 3):op_begin] == '<= ': + key_begin = op_begin + key_end = key_begin + 3 + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + + dprint( + '\nILL-DEFINED OPCODE CONDITIONAL FOUND: ..{0}({1}:{2}) \'{3}\'\n' + '->line: \'{4}\'\n'.format( + location, + line_no, + key_begin, + data_line[key_begin:key_end], + data_line[:-1] + ) + ) + + continue + elif data_line[(op_begin - 2):op_begin] == '<=': + key_begin = op_begin + key_end = key_begin + 3 + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + + dprint( + '\nILL-DEFINED OPCODE CONDITIONAL FOUND: ..{0}({1}:{2}) \'{3}\'\n' + '->line: \'{4}\'\n'.format( + location, + line_no, + key_begin, + data_line[key_begin:key_end], + data_line[:-1] + ) + ) + + continue + elif data_line[(op_begin - 2):op_begin] == '= ': + key_begin = op_begin + key_end = key_begin + 3 + direction = '[TX]' + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + elif data_line[(op_begin - 1):op_begin] == '=': + key_begin = op_begin + key_end = key_begin + 3 + direction = '[TX]' + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 else: + key_begin = op_begin + key_end = key_begin + 3 + + while data_line[key_end:(key_end + 1)].isalnum(): + key_end += 1 + + uprint( + '\nUNDEFINED OPCODE CONDITIONAL FOUND: ..{0}({1}:{2}) \'{3}\'\n' + '->line: \'{4}\'\n'.format( + location, + line_no, + key_begin, + data_line[key_begin:key_end], + data_line[:-1] + ) + ) + continue if key_end < 0: continue if not data_line[key_begin:key_end] in server_opcodes: - out_files['DEBUG'].write('Illegal Opcode Found: ..{0} ({1}:{2}) \'{3}\'\n'.format( + dprint('\nILLEGAL OPCODE FOUND: ..{0}({1}:{2}) \'{3}\'\n'.format( location, line_no, key_begin, @@ -624,25 +1017,77 @@ def discoverserverhandlers(): if not data_line[key_begin:key_end] in server_handlers[server]: server_handlers[server][data_line[key_begin:key_end]] = [] - if not data_line in server_handlers[server][data_line[key_begin:key_end]]: - server_handlers[server][data_line[key_begin:key_end]].append( - '..{0}({1}:{2}) \'{3}\''.format( - location, - line_no, - key_begin, - hint)) + server_handlers[server][data_line[key_begin:key_end]].append( + '..{0}({1}:{2}) \'{3}\''.format( + location, + line_no, + key_begin, + '{0} {1}'.format( + direction, + hint + ) + ) + ) + + dprint('..{0}({1}:{2}) [{3}][{4}] = \'{5} {6}\'\n'.format( + location, + line_no, + key_begin, + server, + data_line[key_begin:key_end], + direction, + hint + )) + + data_file.close() + + dprint('->close: \'{0}\'\n'.format(file_name)) except: - if DEBUG >= 2: - print('EXCEPTION ERROR->discoverserverhandlers({0})'.format(sys.exc_info()[0])) + print('(Exception Error: {0}) discoverserverhandlers() [{1}]'.format( + sys.exc_info()[0], + server + )) + + dprint('<-except: \'{0} [{1}]\'\n'.format( + sys.exc_info()[0], + server + )) + + if not server in bad_servers: + bad_servers.append(server) + + for bad_server in bad_servers: + if bad_server in server_handlers: + vprint('Deleting stale entries for \'{0}\' server...'.format(bad_server)) + + del server_handlers[bad_server] + + dprint('->delete: \'{0}\' server discovered handler entries\n'.format(bad_server)) + + dprint('leaving \'discoverserverhandlers()\'\n\n') return True def clearemptyserverentries(): + """ + Delete SERVER OPCODE HANDLERS with no references + + Server methods are treated a little differently than client ones. Because of multiple + search functions, we do not want to invalidate a server until all data-load processes + are performed. + + This function cleans up and removes unused server references after all relevant + processing is complete. + + """ + + dprint('entering \'clearemptyserverentries()\'\n') + bad_servers = [] for server in server_list: - if len(server_handlers[server]) == 0: + if not server in server_handlers or not len(server_handlers[server]) > 0: bad_servers.append(server) else: bad_opcodes = [] @@ -658,108 +1103,138 @@ def clearemptyserverentries(): bad_servers.append(server) for bad_server in bad_servers: - if DEBUG >= 1: - print('Deleting \'{0}\' server from search criteria...'.format(bad_server)) - print('Deleting stale entries for \'{0}\' server...'.format(bad_server)) + vprint('Deleting \'{0}\' server from search criteria...'.format(bad_server)) - del server_handlers[bad_server] server_list.remove(bad_server) + dprint('->delete: \'{0}\' server\n'.format(bad_server)) + + if bad_server in server_handlers: + vprint('Deleting stale entries for \'{0}\' server...'.format(bad_server)) + + del server_handlers[bad_server] + + dprint('->delete: \'{0}\' server handler entries\n'.format(bad_server)) + + if not len(server_list) > 0: + print('Could not locate valid servers...') + + dprint('leaving \'clearemptyserverentries(): NO VALID SERVERS EXIST\'\n\n') + + return False + + if not len(server_handlers) > 0: + print('Could not locate server handlers...') + + dprint('leaving \'clearemptyserverentries(): SERVER HANDLERS NOT FOUND\'\n\n') + + return False + + dprint('leaving \'clearemptyserverentries()\'\n\n') + return True def openoutputfiles(): - """ Open output files in 'w' mode - create/overwrite mode """ + """ Open OUTPUT FILES in 'w' mode - create/overwrite mode """ + + dprint('entering \'openoutputfiles()\'\n') try: file_name = '{0}/utils/scripts/opcode_handlers_output/Report.txt'.format(base_path) - if DEBUG >= 1: - print(file_name) + vprint(file_name) out_files['Report'] = open(file_name, 'w') + dprint('->open: \'{0}\' in \'w\' mode\n'.format(file_name)) + + rprint( + '>> \'Opcode-Handler\' Report file\n' + '>> file generated @ {0}\n\n'.format(ctime(time())) + ) + for client in client_list: - file_name = '{0}{1}{2}{3}'.format( + file_name = '{0}/utils/scripts/opcode_handlers_output/{1}_opcode_handlers.txt'.format( base_path, - '/utils/scripts/opcode_handlers_output/', - client, - '_opcode_handlers.txt') + client + ) - if DEBUG >= 1: - print(file_name) + vprint(file_name) out_files[client] = open(file_name, 'w') - message = \ - '>> \'Opcode-Handler\' analysis for \'{0}\' client\n' \ - '>> file generated @ {1}\n' \ - '\n'.format( + dprint('->open: \'{0}\' in \'w\' mode\n'.format(file_name)) + + cprint( + client, + '>> \'Opcode-Handler\' analysis for \'{0}\' client\n' + '>> file generated @ {1}\n\n'.format( client, - ctime(time())) - - out_files[client].write(message) - - if DEBUG >= 2: - print(message[:-2]) + ctime(time()) + ) + ) for server in server_list: - file_name = '{0}{1}{2}{3}'.format( + file_name = '{0}/utils/scripts/opcode_handlers_output/{1}_opcode_handlers.txt'.format( base_path, - '/utils/scripts/opcode_handlers_output/', - server, - '_opcode_handlers.txt') + server + ) - if DEBUG >= 1: - print(file_name) + vprint(file_name) out_files[server] = open(file_name, 'w') - message = \ - '>> \'Opcode-Handler\' analysis for \'{0}\' server\n' \ - '>> file generated @ {1}\n' \ - '\n'.format( + dprint('->open: \'{0}\' in \'w\' mode\n'.format(file_name)) + + sprint( + server, + '>> \'Opcode-Handler\' analysis for \'{0}\' server\n' + '>> file generated @ {1}\n\n'.format( server, - ctime(time())) + ctime(time()) + ) + ) - out_files[server].write(message) + dprint('leaving \'openoutputfiles()\'\n\n') - if DEBUG >= 2: - print(message[:-2]) + return True except: - if DEBUG >= 2: - print('EXCEPTION ERROR->openoutputfiles({0})'.format(sys.exc_info()[0])) + print('(Exception Error: {0}) openoutputfiles()'.format(sys.exc_info()[0])) + + if 'Report' in out_files: + vprint('Closing Report output file...') + + out_files['Report'].close() + + del out_files['Report'] for client in client_list: if client in out_files: + vprint('Closing {0} client output file...'.format(client)) + out_files[client].close() + del out_files[client] - if DEBUG >= 2: - print('->OpeningClientStream(exception): {0}'.format(client)) - for server in server_list: if server in out_files: + vprint('Closing {0} server output file...'.format(server)) + out_files[server].close() + del out_files[server] - if DEBUG >= 2: - print('->OpeningServerStream(exception): {0}'.format(server)) - - if 'Report' in out_files: - out_files['Report'].close() - del out_files['Report'] - - if DEBUG >= 2: - print('->OpeningReportStream(exception)') + dprint('leaving \'openoutputfiles(): EXCEPTION ERROR\'\n\n') return False - return True - def parseclientopcodedata(): - # TODO: add metrics + """ Process CLIENT OPCODE cross-link references """ + + dprint('entering \'parseclientopcodedata()\'\n') + for client in client_list: server_max_len = 0 @@ -785,7 +1260,8 @@ def parseclientopcodedata(): client_opcodes[client][client_opcode], handled, encoded, - decoded) + decoded + ) for server in server_list: if client_opcode in server_handlers[server] and len(server_handlers[server][client_opcode]) > 0: @@ -796,30 +1272,29 @@ def parseclientopcodedata(): message += ' Server: {0} ({1}) | Handler: {2}\n'.format( server.ljust(len(server) + (server_max_len - len(server)), ' '), '{0}'.format(server_opcodes[client_opcode]).zfill(4), - handler_entry) + handler_entry + ) else: message += ' Server: {0} (0000) | Handler: N/A\n'.format( - server.ljust(len(server) + (server_max_len - len(server)), ' ')) - - if DEBUG >= 2: - print('->EndOfServerLoop: {0}'.format(server)) + server.ljust(len(server) + (server_max_len - len(server)), ' ') + ) message += '\n' - out_files[client].write(message) + cprint(client, message) - if DEBUG >= 2: - print(message[:-2]) - print('->EndOfOpcodeLoop: {0}'.format(client_opcode)) + dprint('->parse: \'{0}\' client\n'.format(client)) - if DEBUG >= 2: - print('->EndOfClientLoop: {0}'.format(client)) + dprint('leaving \'parseclientopcodedata()\'\n\n') return True def parseserveropcodedata(): - # TODO: add metrics + """ Process SERVER OPCODE cross-link references """ + + dprint('entering \'parseserveropcodedata()\'\n') + for server in server_list: client_max_len = 0 @@ -859,62 +1334,145 @@ def parseserveropcodedata(): val1, val2.ljust(len(val2) + (len('False') - len(val2)), ' '), val3.ljust(len(val3) + (len('False') - len(val3)), ' '), - val4.ljust(len(val4) + (len('False') - len(val4)), ' ')) - - if DEBUG >= 2: - print('->EndOfClientLoop: {0}'.format(client)) + val4.ljust(len(val4) + (len('False') - len(val4)), ' ') + ) message += '\n' - out_files[server].write(message) + sprint(server, message) - if DEBUG >= 2: - print(message[:-2]) - print('->EndOfOpcodeLoop: {0}'.format(handler_opcode)) + dprint('->parse: \'{0}\' server\n'.format(server)) - if DEBUG >= 2: - print('->EndOfServerLoop: {0}'.format(server)) + dprint('leaving \'parseserveropcodedata()\'\n\n') return True def closeoutputfiles(): + """ Close OUTPUT FILES - excluding DEBUG FILE """ + + dprint('entering \'closeoutputfiles()\'\n') + + if 'Report' in out_files: + file_name = out_files['Report'].name + + out_files['Report'].close() + + del out_files['Report'] + + dprint('->close: \'{0}\'\n'.format(file_name)) + + if 'Undefined' in out_files: + file_name = out_files['Undefined'].name + + out_files['Undefined'].close() + + del out_files['Undefined'] + + dprint('->close: \'{0}\'\n'.format(file_name)) + for client in client_list: if client in out_files: + file_name = out_files[client].name + out_files[client].close() + del out_files[client] - if DEBUG >= 2: - print('->ClosingClientStream: {0}'.format(client)) + dprint('->close: \'{0}\'\n'.format(file_name)) for server in server_list: if server in out_files: + file_name = out_files[server].name + out_files[server].close() + del out_files[server] - if DEBUG >= 2: - print('->ClosingServerStream: {0}'.format(server)) + dprint('->close: \'{0}\'\n'.format(file_name)) - if 'Report' in out_files: - out_files['Report'].close() - del out_files['Report'] + dprint('leaving \'closeoutputfiles()\'\n\n') - if DEBUG >= 2: - print('->ClosingReportStream') + return True + + +def closeundefinedfile(): + """ Close UNDEFINED FILE """ + + dprint('entering \'closeundefinedfile()\'\n') + + if 'Undefined' in out_files: + file_name = out_files['Undefined'].name + + dprint('closing \'{0}\'\n'.format(file_name)) + + out_files['Undefined'].close() + + del out_files['Undefined'] + + dprint('leaving \'closeundefinedfile()\'\n\n') return True def closedebugfile(): - if 'DEBUG' in out_files: - out_files['DEBUG'].close() - del out_files['DEBUG'] + """ Close DEBUG FILE - last performed action to catch late messages """ - if DEBUG >= 2: - print('->ClosingDEBUGStream') + dprint('entering \'closedebugfile()\'\n') + + if 'DEBUG' in out_files: + file_name = out_files['DEBUG'].name + + dprint('closing \'{0}\'\n'.format(file_name)) + + out_files['DEBUG'].close() + + del out_files['DEBUG'] return True +def cprint(client, message): + """ CLIENT PRINT helper function """ + + if client in out_files: + out_files[client].write(message) + + +def dprint(message): + """ DEBUG PRINT helper function """ + + if 'DEBUG' in out_files: + out_files['DEBUG'].write(message) + + +def rprint(message): + """ REPORT PRINT helper function """ + + if 'Report' in out_files: + out_files['Report'].write(message) + + +def sprint(server, message): + """ SERVER PRINT helper function """ + + if server in out_files: + out_files[server].write(message) + + +def uprint(message): + """ UNDEFINED PRINT helper function """ + + if 'Undefined' in out_files: + out_files['Undefined'].write(message) + + +def vprint(message): + """ VERBOSE PRINT helper function """ + + if VERBOSE: + print(message) + + if __name__ == '__main__': main() From 1ba4b6fc3124bf3a4376b1f18564ecd576dabc5a Mon Sep 17 00:00:00 2001 From: Russell Kinasz Date: Tue, 12 Aug 2014 15:18:11 -0700 Subject: [PATCH 08/15] Implemented Raid OOC Regen --- common/ruletypes.h | 1 + zone/client.cpp | 28 ++++++++++++++++++++++++---- zone/client.h | 6 ++++++ zone/client_packet.cpp | 3 ++- zone/hate_list.cpp | 5 ++++- zone/mob.h | 1 + zone/npc.cpp | 1 + zone/npc.h | 4 ++++ zone/zonedb.cpp | 4 +++- zone/zonedump.h | 1 + 10 files changed, 47 insertions(+), 7 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 0fd413e5a..91ade257b 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -76,6 +76,7 @@ RULE_BOOL ( Character, SharedBankPlat, false) //off by default to prevent duping RULE_BOOL ( Character, BindAnywhere, false) RULE_INT ( Character, RestRegenPercent, 0) // Set to >0 to enable rest state bonus HP and mana regen. RULE_INT ( Character, RestRegenTimeToActivate, 30) // Time in seconds for rest state regen to kick in. +RULE_INT ( Character, RestRegenRaidTimeToActivate, 300) // Time in seconds for rest state regen to kick in with a raid target. RULE_BOOL ( Character, RestRegenEndurance, false) // Whether rest regen will work for endurance or not. RULE_INT ( Character, KillsPerGroupLeadershipAA, 250) // Number of dark blues or above per Group Leadership AA RULE_INT ( Character, KillsPerRaidLeadershipAA, 250) // Number of dark blues or above per Raid Leadership AA diff --git a/zone/client.cpp b/zone/client.cpp index 6b7828f1d..aa93478ba 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -324,6 +324,9 @@ Client::Client(EQStreamInterface* ieqs) initial_respawn_selection = 0; alternate_currency_loaded = false; + + EngagedRaidTarget = false; + SavedRaidRestTimer = 0; } Client::~Client() { @@ -4330,12 +4333,16 @@ void Client::IncrementAggroCount() { if(!RuleI(Character, RestRegenPercent)) return; - + // If we already had aggro before this method was called, the combat indicator should already be up for SoF clients, // so we don't need to send it again. // if(AggroCount > 1) return; + + // Pause the rest timer + if (AggroCount == 1) + SavedRaidRestTimer = rest_timer.GetRemainingTime(); if(GetClientVersion() >= EQClientSoF) { @@ -4367,14 +4374,27 @@ void Client::DecrementAggroCount() { // Something else is still aggro on us, can't rest yet. if(AggroCount) return; - rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000); - + uint32 time_until_rest; + if (GetEngagedRaidTarget()) { + time_until_rest = RuleI(Character, RestRegenRaidTimeToActivate) * 1000; + SetEngagedRaidTarget(false); + } else { + if (SavedRaidRestTimer > (RuleI(Character, RestRegenTimeToActivate) * 1000)) { + time_until_rest = SavedRaidRestTimer; + SavedRaidRestTimer = 0; + } else { + time_until_rest = RuleI(Character, RestRegenTimeToActivate) * 1000; + } + } + + rest_timer.Start(time_until_rest); + if(GetClientVersion() >= EQClientSoF) { EQApplicationPacket *outapp = new EQApplicationPacket(OP_RestState, 5); char *Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0x00); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, RuleI(Character, RestRegenTimeToActivate)); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, (uint32)(time_until_rest / 1000)); QueuePacket(outapp); safe_delete(outapp); } diff --git a/zone/client.h b/zone/client.h index cce84673c..cadf9b583 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1198,6 +1198,9 @@ public: int mod_food_value(const Item_Struct *item, int change); int mod_drink_value(const Item_Struct *item, int change); + void SetEngagedRaidTarget(bool value) { EngagedRaidTarget = value; } + bool GetEngagedRaidTarget() const { return EngagedRaidTarget; } + protected: friend class Mob; void CalcItemBonuses(StatBonuses* newbon); @@ -1442,6 +1445,9 @@ private: unsigned int RestRegenHP; unsigned int RestRegenMana; unsigned int RestRegenEndurance; + + bool EngagedRaidTarget; + uint32 SavedRaidRestTimer; std::set zone_flags; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 01e768c1f..0d44bfa93 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -9140,7 +9140,8 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { m_pp.timeentitledonaccount = database.GetTotalTimeEntitledOnAccount(AccountID()) / 1440; - if(m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) + // Reset rest timer if the durations have been lowered in the database + if ((m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) && (m_pp.RestTimer > RuleI(Character, RestRegenRaidTimeToActivate))) m_pp.RestTimer = 0; //This checksum should disappear once dynamic structs are in... each struct strategy will do it diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 1b585ca32..2d7bd3ea6 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -198,8 +198,11 @@ void HateList::Add(Mob *ent, int32 in_hate, int32 in_dam, bool bFrenzy, bool iAd list.push_back(p); parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "1", 0); - if(ent->IsClient()) + if (ent->IsClient()) { + if (owner->CastToNPC()->IsRaidTarget()) + ent->CastToClient()->SetEngagedRaidTarget(true); ent->CastToClient()->IncrementAggroCount(); + } } } diff --git a/zone/mob.h b/zone/mob.h index 15f1728ec..a0c8dbdc4 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -524,6 +524,7 @@ public: //More stuff to sort: + virtual bool IsRaidTarget() { return false; }; virtual bool IsAttackAllowed(Mob *target, bool isSpellAttack = false); bool IsTargeted() const { return (targeted > 0); } inline void IsTargeted(int in_tar) { targeted += in_tar; if(targeted < 0) targeted = 0;} diff --git a/zone/npc.cpp b/zone/npc.cpp index 565a89598..f4e307bbc 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -358,6 +358,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float SetEmoteID(d->emoteid); InitializeBuffSlots(); CalcBonuses(); + raid_target = d->raid_target; } NPC::~NPC() diff --git a/zone/npc.h b/zone/npc.h index 6bc9813fe..5c8fd43bb 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -395,6 +395,8 @@ public: void mod_npc_killed_merit(Mob* c); void mod_npc_killed(Mob* oos); void AISpellsList(Client *c); + + bool IsRaidTarget() const { return raid_target; }; protected: @@ -500,6 +502,8 @@ protected: //mercenary stuff std::list mercTypeList; std::list mercDataList; + + bool raid_target; private: uint32 loottable_id; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index b14e63f26..0d1653453 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1115,7 +1115,8 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { "npc_types.emoteid," "npc_types.spellscale," "npc_types.healscale," - "npc_types.no_target_hotkey"; + "npc_types.no_target_hotkey," + "npc_types.raid_target"; MakeAnyLenString(&query, "%s FROM npc_types WHERE id=%d", basic_query, id); @@ -1302,6 +1303,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { tmpNPCType->spellscale = atoi(row[r++]); tmpNPCType->healscale = atoi(row[r++]); tmpNPCType->no_target_hotkey = atoi(row[r++]) == 1 ? true : false; + tmpNPCType->raid_target = atoi(row[r++]) == 0 ? false : true; // If NPC with duplicate NPC id already in table, // free item we attempted to add. diff --git a/zone/zonedump.h b/zone/zonedump.h index 3b5b91577..98841630a 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -125,6 +125,7 @@ struct NPCType float spellscale; float healscale; bool no_target_hotkey; + bool raid_target; }; /* From 6badd7e00e7e5aeeea5955061b1b2b3d0fac84ca Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 12 Aug 2014 22:51:36 -0400 Subject: [PATCH 09/15] Added SQLs from previous commit [skip ci] --- utils/sql/git/optional/2014_08_12_raid_timer_rule.sql | 1 + utils/sql/git/required/2014_08_12_NPC_raid_targets.sql | 1 + 2 files changed, 2 insertions(+) create mode 100644 utils/sql/git/optional/2014_08_12_raid_timer_rule.sql create mode 100644 utils/sql/git/required/2014_08_12_NPC_raid_targets.sql diff --git a/utils/sql/git/optional/2014_08_12_raid_timer_rule.sql b/utils/sql/git/optional/2014_08_12_raid_timer_rule.sql new file mode 100644 index 000000000..46f5acb37 --- /dev/null +++ b/utils/sql/git/optional/2014_08_12_raid_timer_rule.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Character:RestRegenRaidTimeToActivate', 300, 'Time in seconds for rest state regen to kick in with a raid target.'); diff --git a/utils/sql/git/required/2014_08_12_NPC_raid_targets.sql b/utils/sql/git/required/2014_08_12_NPC_raid_targets.sql new file mode 100644 index 000000000..c045b18e3 --- /dev/null +++ b/utils/sql/git/required/2014_08_12_NPC_raid_targets.sql @@ -0,0 +1 @@ +ALTER TABLE `npc_types` ADD `raid_target` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `fixed`; From c2282ced0e97f16f19fd2f7b519b4da51a852544 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 13 Aug 2014 13:20:10 -0400 Subject: [PATCH 10/15] Some people were having issues with the other one [skip ci] --- utils/sql/git/required/2014_08_12_NPC_raid_targets.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/git/required/2014_08_12_NPC_raid_targets.sql b/utils/sql/git/required/2014_08_12_NPC_raid_targets.sql index c045b18e3..a91a02815 100644 --- a/utils/sql/git/required/2014_08_12_NPC_raid_targets.sql +++ b/utils/sql/git/required/2014_08_12_NPC_raid_targets.sql @@ -1 +1 @@ -ALTER TABLE `npc_types` ADD `raid_target` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `fixed`; +ALTER TABLE `npc_types` ADD `raid_target` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `no_target_hotkey`; From dc6e6fd05f4e5a1b3914bef66777078948205565 Mon Sep 17 00:00:00 2001 From: Uleat Date: Wed, 13 Aug 2014 14:24:42 -0400 Subject: [PATCH 11/15] Fix for bot chest armor display glitch in SoF+ clients --- changelog.txt | 3 +++ zone/bot.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 16d63a05e..32b1a105c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 08/13/2014 == +Uleat (Kingly_Krab): Fix for bot chest armor graphic glitch. (fix also caused RoF #wc to work properly) + == 08/02/2014 == Kayen: Implemented spell_news fields - npc_no_los (check if LOS is required for spells) diff --git a/zone/bot.cpp b/zone/bot.cpp index eef5f803f..283f482de 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -4303,8 +4303,9 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) { // Get the zone id this bot spawned in _lastZoneId = GetZoneID(); - this->helmtexture = 0xFF; - this->texture = 0xFF; + // this change propagates to Bot::FillSpawnStruct() + this->helmtexture = 0; //0xFF; + this->texture = 0; //0xFF; if(this->Save()) this->GetBotOwner()->CastToClient()->Message(0, "%s saved.", this->GetCleanName()); @@ -4586,8 +4587,8 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { ns->spawn.size = 0; ns->spawn.NPC = 0; // 0=player,1=npc,2=pc corpse,3=npc corpse - ns->spawn.helm = 0xFF; - ns->spawn.equip_chest2 = 0xFF; + ns->spawn.helm = helmtexture; //0xFF; + ns->spawn.equip_chest2 = texture; //0xFF; const Item_Struct* item = 0; const ItemInst* inst = 0; From e2874b2cc6cb44ff59cb1c0ee97acfadea22d715 Mon Sep 17 00:00:00 2001 From: Michael Cook Date: Thu, 14 Aug 2014 15:05:44 -0400 Subject: [PATCH 12/15] Update README.md [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2245dcf4..0c973ed43 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Further instructions on building the source can be found on the Bug reports --- -Please use the [issue tracker](issue-tracker) provided by GitHub to send us bug +Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug reports or feature requests. The [EQEmu Forums](http://www.eqemulator.org/forums/) also have forums to submit From bce3b1b9617543cbad615659a65e1386b52c9cf3 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Fri, 15 Aug 2014 04:15:37 -0400 Subject: [PATCH 13/15] Edit some uint32 to int32: GetAugmentIDAt, GetItemIDAt, GetItemStat --- zone/client.h | 4 ++-- zone/inventory.cpp | 4 ++-- zone/mob.cpp | 2 +- zone/mob.h | 2 +- zone/perl_client.cpp | 8 ++++---- zone/perl_mob.cpp | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/zone/client.h b/zone/client.h index cadf9b583..718efbb6e 100644 --- a/zone/client.h +++ b/zone/client.h @@ -789,8 +789,8 @@ public: void SetTint(int16 slot_id, Color_Struct& color); void SetMaterial(int16 slot_id, uint32 item_id); void Undye(); - uint32 GetItemIDAt(int16 slot_id); - uint32 GetAugmentIDAt(int16 slot_id, uint8 augslot); + int32 GetItemIDAt(int16 slot_id); + 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 DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true); diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 969065fdb..9a815c6ca 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -659,7 +659,7 @@ void Client::DropInst(const ItemInst* inst) } // Returns a slot's item ID (returns INVALID_ID if not found) -uint32 Client::GetItemIDAt(int16 slot_id) { +int32 Client::GetItemIDAt(int16 slot_id) { const ItemInst* inst = m_inv[slot_id]; if (inst) return inst->GetItem()->ID; @@ -670,7 +670,7 @@ uint32 Client::GetItemIDAt(int16 slot_id) { // Returns an augment's ID that's in an item (returns INVALID_ID if not found) // Pass in the slot ID of the item and which augslot you want to check (0-4) -uint32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) { +int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) { const ItemInst* inst = m_inv[slot_id]; if (inst) if (inst->GetAugmentItemID(augslot)) diff --git a/zone/mob.cpp b/zone/mob.cpp index 24b691e36..03e7bbdaa 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3537,7 +3537,7 @@ void Mob::TrySympatheticProc(Mob *target, uint32 spell_id) } } -uint32 Mob::GetItemStat(uint32 itemid, const char *identifier) +int32 Mob::GetItemStat(uint32 itemid, const char *identifier) { const ItemInst* inst = database.CreateItem(itemid); if (!inst) diff --git a/zone/mob.h b/zone/mob.h index a0c8dbdc4..fe0919f7e 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -553,7 +553,7 @@ public: void Shout(const char *format, ...); void Emote(const char *format, ...); void QuestJournalledSay(Client *QuestInitiator, const char *str); - uint32 GetItemStat(uint32 itemid, const char *identifier); + int32 GetItemStat(uint32 itemid, const char *identifier); int16 CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, bool best_focus=false); uint8 IsFocusEffect(uint16 spellid, int effect_index, bool AA=false,uint32 aa_effect=0); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 0bab3cfb0..816956d86 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -2955,7 +2955,7 @@ XS(XS_Client_GetItemIDAt) Perl_croak(aTHX_ "Usage: Client::GetItemIDAt(THIS, slot_id)"); { Client * THIS; - uint32 RETVAL; + int32 RETVAL; dXSTARG; int16 slot_id = (int16)SvIV(ST(1)); @@ -2969,7 +2969,7 @@ XS(XS_Client_GetItemIDAt) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); RETVAL = THIS->GetItemIDAt(slot_id); - XSprePUSH; PUSHu((UV)RETVAL); + XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } @@ -2982,7 +2982,7 @@ XS(XS_Client_GetAugmentIDAt) Perl_croak(aTHX_ "Usage: Client::GetAugmentIDAt(THIS, slot_id, augslot)"); { Client * THIS; - uint32 RETVAL; + int32 RETVAL; dXSTARG; int16 slot_id = (int16)SvIV(ST(1)); int16 augslot = (uint8)SvIV(ST(2)); @@ -2997,7 +2997,7 @@ XS(XS_Client_GetAugmentIDAt) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); RETVAL = THIS->GetAugmentIDAt(slot_id, augslot); - XSprePUSH; PUSHu((UV)RETVAL); + XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 86cf58981..14d84a70e 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -7298,7 +7298,7 @@ XS(XS_Mob_GetItemStat) Perl_croak(aTHX_ "Usage: Mob::GetItemStat(THIS, itemid, stat)"); { Mob * THIS; - uint32 RETVAL; + int32 RETVAL; uint32 itemid = (uint32)SvUV(ST(1)); Const_char * stat = (Const_char *)SvPV_nolen(ST(2)); dXSTARG; @@ -7313,7 +7313,7 @@ XS(XS_Mob_GetItemStat) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); RETVAL = THIS->GetItemStat(itemid, stat); - XSprePUSH; PUSHu((UV)RETVAL); + XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } From f7bb763aaca6dd55bb591ab20ba280b3b5adca1c Mon Sep 17 00:00:00 2001 From: Uleat Date: Fri, 15 Aug 2014 16:28:16 -0400 Subject: [PATCH 14/15] Reactivation of wear change updates in Bot::Spawn() until fix can be found. --- changelog.txt | 3 +++ zone/bot.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 32b1a105c..1f43ed0d9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 08/15/2014 == +Uleat: Reactivated the Bot::Spawn() code for sending post-spawn wear change updates..temporary until I can sort out the proper usage. + == 08/13/2014 == Uleat (Kingly_Krab): Fix for bot chest armor graphic glitch. (fix also caused RoF #wc to work properly) diff --git a/zone/bot.cpp b/zone/bot.cpp index 283f482de..aa5ab33f0 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -4330,18 +4330,18 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) { this->SendPosition(); - /* // fillspawnstruct now properly handles this -U + // there is something askew with spawn struct appearance fields... + // I re-enabled this until I can sort it out -U uint32 itemID = 0; uint8 materialFromSlot = 0xFF; - for(int i=EmuConstants::EQUIPMENT_BEGIN; i<=EmuConstants::EQUIPMENT_END; ++i) { + for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { itemID = GetBotItemBySlot(i); if(itemID != 0) { materialFromSlot = Inventory::CalcMaterialFromSlot(i); - if(materialFromSlot != 0xFF) { + if(materialFromSlot != 0xFF) this->SendWearChange(materialFromSlot); - } } - }*/ + } } } From 0f5214f4818a9751e52288424db25d362a70e39a Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Sat, 16 Aug 2014 01:13:15 -0400 Subject: [PATCH 15/15] Fixed GetItemStat making all information it pulls default it uint32. --- zone/mob.cpp | 314 ++++++++++++++++++++++++++------------------------- 1 file changed, 158 insertions(+), 156 deletions(-) diff --git a/zone/mob.cpp b/zone/mob.cpp index 03e7bbdaa..a6baabd1a 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3550,7 +3550,7 @@ int32 Mob::GetItemStat(uint32 itemid, const char *identifier) if (!identifier) return 0; - uint32 stat = 0; + int32 stat = 0; std::string id = identifier; for(int i = 0; i < id.length(); ++i) @@ -3559,316 +3559,318 @@ int32 Mob::GetItemStat(uint32 itemid, const char *identifier) } if (id == "itemclass") - stat = uint32(item->ItemClass); + stat = int32(item->ItemClass); if (id == "id") - stat = uint32(item->ID); + stat = int32(item->ID); + if (id == "idfile") + stat = atoi(&item->IDFile[2]); if (id == "weight") - stat = uint32(item->Weight); + stat = int32(item->Weight); if (id == "norent") - stat = uint32(item->NoRent); + stat = int32(item->NoRent); if (id == "nodrop") - stat = uint32(item->NoDrop); + stat = int32(item->NoDrop); if (id == "size") - stat = uint32(item->Size); + stat = int32(item->Size); if (id == "slots") - stat = uint32(item->Slots); + stat = int32(item->Slots); if (id == "price") - stat = uint32(item->Price); + stat = int32(item->Price); if (id == "icon") - stat = uint32(item->Icon); + stat = int32(item->Icon); if (id == "loregroup") - stat = uint32(item->LoreGroup); + stat = int32(item->LoreGroup); if (id == "loreflag") - stat = uint32(item->LoreFlag); + stat = int32(item->LoreFlag); if (id == "pendingloreflag") - stat = uint32(item->PendingLoreFlag); + stat = int32(item->PendingLoreFlag); if (id == "artifactflag") - stat = uint32(item->ArtifactFlag); + stat = int32(item->ArtifactFlag); if (id == "summonedflag") - stat = uint32(item->SummonedFlag); + stat = int32(item->SummonedFlag); if (id == "fvnodrop") - stat = uint32(item->FVNoDrop); + stat = int32(item->FVNoDrop); if (id == "favor") - stat = uint32(item->Favor); + stat = int32(item->Favor); if (id == "guildfavor") - stat = uint32(item->GuildFavor); + stat = int32(item->GuildFavor); if (id == "pointtype") - stat = uint32(item->PointType); + stat = int32(item->PointType); if (id == "bagtype") - stat = uint32(item->BagType); + stat = int32(item->BagType); if (id == "bagslots") - stat = uint32(item->BagSlots); + stat = int32(item->BagSlots); if (id == "bagsize") - stat = uint32(item->BagSize); + stat = int32(item->BagSize); if (id == "bagwr") - stat = uint32(item->BagWR); + stat = int32(item->BagWR); if (id == "benefitflag") - stat = uint32(item->BenefitFlag); + stat = int32(item->BenefitFlag); if (id == "tradeskills") - stat = uint32(item->Tradeskills); + stat = int32(item->Tradeskills); if (id == "cr") - stat = uint32(item->CR); + stat = int32(item->CR); if (id == "dr") - stat = uint32(item->DR); + stat = int32(item->DR); if (id == "pr") - stat = uint32(item->PR); + stat = int32(item->PR); if (id == "mr") - stat = uint32(item->MR); + stat = int32(item->MR); if (id == "fr") - stat = uint32(item->FR); + stat = int32(item->FR); if (id == "astr") - stat = uint32(item->AStr); + stat = int32(item->AStr); if (id == "asta") - stat = uint32(item->ASta); + stat = int32(item->ASta); if (id == "aagi") - stat = uint32(item->AAgi); + stat = int32(item->AAgi); if (id == "adex") - stat = uint32(item->ADex); + stat = int32(item->ADex); if (id == "acha") - stat = uint32(item->ACha); + stat = int32(item->ACha); if (id == "aint") - stat = uint32(item->AInt); + stat = int32(item->AInt); if (id == "awis") - stat = uint32(item->AWis); + stat = int32(item->AWis); if (id == "hp") - stat = uint32(item->HP); + stat = int32(item->HP); if (id == "mana") - stat = uint32(item->Mana); + stat = int32(item->Mana); if (id == "ac") - stat = uint32(item->AC); + stat = int32(item->AC); if (id == "deity") - stat = uint32(item->Deity); + stat = int32(item->Deity); if (id == "skillmodvalue") - stat = uint32(item->SkillModValue); + stat = int32(item->SkillModValue); if (id == "skillmodtype") - stat = uint32(item->SkillModType); + stat = int32(item->SkillModType); if (id == "banedmgrace") - stat = uint32(item->BaneDmgRace); + stat = int32(item->BaneDmgRace); if (id == "banedmgamt") - stat = uint32(item->BaneDmgAmt); + stat = int32(item->BaneDmgAmt); if (id == "banedmgbody") - stat = uint32(item->BaneDmgBody); + stat = int32(item->BaneDmgBody); if (id == "magic") - stat = uint32(item->Magic); + stat = int32(item->Magic); if (id == "casttime_") - stat = uint32(item->CastTime_); + stat = int32(item->CastTime_); if (id == "reqlevel") - stat = uint32(item->ReqLevel); + stat = int32(item->ReqLevel); if (id == "bardtype") - stat = uint32(item->BardType); + stat = int32(item->BardType); if (id == "bardvalue") - stat = uint32(item->BardValue); + stat = int32(item->BardValue); if (id == "light") - stat = uint32(item->Light); + stat = int32(item->Light); if (id == "delay") - stat = uint32(item->Delay); + stat = int32(item->Delay); if (id == "reclevel") - stat = uint32(item->RecLevel); + stat = int32(item->RecLevel); if (id == "recskill") - stat = uint32(item->RecSkill); + stat = int32(item->RecSkill); if (id == "elemdmgtype") - stat = uint32(item->ElemDmgType); + stat = int32(item->ElemDmgType); if (id == "elemdmgamt") - stat = uint32(item->ElemDmgAmt); + stat = int32(item->ElemDmgAmt); if (id == "range") - stat = uint32(item->Range); + stat = int32(item->Range); if (id == "damage") - stat = uint32(item->Damage); + stat = int32(item->Damage); if (id == "color") - stat = uint32(item->Color); + stat = int32(item->Color); if (id == "classes") - stat = uint32(item->Classes); + stat = int32(item->Classes); if (id == "races") - stat = uint32(item->Races); + stat = int32(item->Races); if (id == "maxcharges") - stat = uint32(item->MaxCharges); + stat = int32(item->MaxCharges); if (id == "itemtype") - stat = uint32(item->ItemType); + stat = int32(item->ItemType); if (id == "material") - stat = uint32(item->Material); + stat = int32(item->Material); if (id == "casttime") - stat = uint32(item->CastTime); + stat = int32(item->CastTime); if (id == "elitematerial") - stat = uint32(item->EliteMaterial); + stat = int32(item->EliteMaterial); if (id == "procrate") - stat = uint32(item->ProcRate); + stat = int32(item->ProcRate); if (id == "combateffects") - stat = uint32(item->CombatEffects); + stat = int32(item->CombatEffects); if (id == "shielding") - stat = uint32(item->Shielding); + stat = int32(item->Shielding); if (id == "stunresist") - stat = uint32(item->StunResist); + stat = int32(item->StunResist); if (id == "strikethrough") - stat = uint32(item->StrikeThrough); + stat = int32(item->StrikeThrough); if (id == "extradmgskill") - stat = uint32(item->ExtraDmgSkill); + stat = int32(item->ExtraDmgSkill); if (id == "extradmgamt") - stat = uint32(item->ExtraDmgAmt); + stat = int32(item->ExtraDmgAmt); if (id == "spellshield") - stat = uint32(item->SpellShield); + stat = int32(item->SpellShield); if (id == "avoidance") - stat = uint32(item->Avoidance); + stat = int32(item->Avoidance); if (id == "accuracy") - stat = uint32(item->Accuracy); + stat = int32(item->Accuracy); if (id == "charmfileid") - stat = uint32(item->CharmFileID); + stat = int32(item->CharmFileID); if (id == "factionmod1") - stat = uint32(item->FactionMod1); + stat = int32(item->FactionMod1); if (id == "factionmod2") - stat = uint32(item->FactionMod2); + stat = int32(item->FactionMod2); if (id == "factionmod3") - stat = uint32(item->FactionMod3); + stat = int32(item->FactionMod3); if (id == "factionmod4") - stat = uint32(item->FactionMod4); + stat = int32(item->FactionMod4); if (id == "factionamt1") - stat = uint32(item->FactionAmt1); + stat = int32(item->FactionAmt1); if (id == "factionamt2") - stat = uint32(item->FactionAmt2); + stat = int32(item->FactionAmt2); if (id == "factionamt3") - stat = uint32(item->FactionAmt3); + stat = int32(item->FactionAmt3); if (id == "factionamt4") - stat = uint32(item->FactionAmt4); + stat = int32(item->FactionAmt4); if (id == "augtype") - stat = uint32(item->AugType); + stat = int32(item->AugType); if (id == "ldontheme") - stat = uint32(item->LDoNTheme); + stat = int32(item->LDoNTheme); if (id == "ldonprice") - stat = uint32(item->LDoNPrice); + stat = int32(item->LDoNPrice); if (id == "ldonsold") - stat = uint32(item->LDoNSold); + stat = int32(item->LDoNSold); if (id == "banedmgraceamt") - stat = uint32(item->BaneDmgRaceAmt); + stat = int32(item->BaneDmgRaceAmt); if (id == "augrestrict") - stat = uint32(item->AugRestrict); + stat = int32(item->AugRestrict); if (id == "endur") - stat = uint32(item->Endur); + stat = int32(item->Endur); if (id == "dotshielding") - stat = uint32(item->DotShielding); + stat = int32(item->DotShielding); if (id == "attack") - stat = uint32(item->Attack); + stat = int32(item->Attack); if (id == "regen") - stat = uint32(item->Regen); + stat = int32(item->Regen); if (id == "manaregen") - stat = uint32(item->ManaRegen); + stat = int32(item->ManaRegen); if (id == "enduranceregen") - stat = uint32(item->EnduranceRegen); + stat = int32(item->EnduranceRegen); if (id == "haste") - stat = uint32(item->Haste); + stat = int32(item->Haste); if (id == "damageshield") - stat = uint32(item->DamageShield); + stat = int32(item->DamageShield); if (id == "recastdelay") - stat = uint32(item->RecastDelay); + stat = int32(item->RecastDelay); if (id == "recasttype") - stat = uint32(item->RecastType); + stat = int32(item->RecastType); if (id == "augdistiller") - stat = uint32(item->AugDistiller); + stat = int32(item->AugDistiller); if (id == "attuneable") - stat = uint32(item->Attuneable); + stat = int32(item->Attuneable); if (id == "nopet") - stat = uint32(item->NoPet); + stat = int32(item->NoPet); if (id == "potionbelt") - stat = uint32(item->PotionBelt); + stat = int32(item->PotionBelt); if (id == "stackable") - stat = uint32(item->Stackable); + stat = int32(item->Stackable); if (id == "notransfer") - stat = uint32(item->NoTransfer); + stat = int32(item->NoTransfer); if (id == "questitemflag") - stat = uint32(item->QuestItemFlag); + stat = int32(item->QuestItemFlag); if (id == "stacksize") - stat = uint32(item->StackSize); + stat = int32(item->StackSize); if (id == "potionbeltslots") - stat = uint32(item->PotionBeltSlots); + stat = int32(item->PotionBeltSlots); if (id == "book") - stat = uint32(item->Book); + stat = int32(item->Book); if (id == "booktype") - stat = uint32(item->BookType); + stat = int32(item->BookType); if (id == "svcorruption") - stat = uint32(item->SVCorruption); + stat = int32(item->SVCorruption); if (id == "purity") - stat = uint32(item->Purity); + stat = int32(item->Purity); if (id == "backstabdmg") - stat = uint32(item->BackstabDmg); + stat = int32(item->BackstabDmg); if (id == "dsmitigation") - stat = uint32(item->DSMitigation); + stat = int32(item->DSMitigation); if (id == "heroicstr") - stat = uint32(item->HeroicStr); + stat = int32(item->HeroicStr); if (id == "heroicint") - stat = uint32(item->HeroicInt); + stat = int32(item->HeroicInt); if (id == "heroicwis") - stat = uint32(item->HeroicWis); + stat = int32(item->HeroicWis); if (id == "heroicagi") - stat = uint32(item->HeroicAgi); + stat = int32(item->HeroicAgi); if (id == "heroicdex") - stat = uint32(item->HeroicDex); + stat = int32(item->HeroicDex); if (id == "heroicsta") - stat = uint32(item->HeroicSta); + stat = int32(item->HeroicSta); if (id == "heroiccha") - stat = uint32(item->HeroicCha); + stat = int32(item->HeroicCha); if (id == "heroicmr") - stat = uint32(item->HeroicMR); + stat = int32(item->HeroicMR); if (id == "heroicfr") - stat = uint32(item->HeroicFR); + stat = int32(item->HeroicFR); if (id == "heroiccr") - stat = uint32(item->HeroicCR); + stat = int32(item->HeroicCR); if (id == "heroicdr") - stat = uint32(item->HeroicDR); + stat = int32(item->HeroicDR); if (id == "heroicpr") - stat = uint32(item->HeroicPR); + stat = int32(item->HeroicPR); if (id == "heroicsvcorrup") - stat = uint32(item->HeroicSVCorrup); + stat = int32(item->HeroicSVCorrup); if (id == "healamt") - stat = uint32(item->HealAmt); + stat = int32(item->HealAmt); if (id == "spelldmg") - stat = uint32(item->SpellDmg); + stat = int32(item->SpellDmg); if (id == "ldonsellbackrate") - stat = uint32(item->LDoNSellBackRate); + stat = int32(item->LDoNSellBackRate); if (id == "scriptfileid") - stat = uint32(item->ScriptFileID); + stat = int32(item->ScriptFileID); if (id == "expendablearrow") - stat = uint32(item->ExpendableArrow); + stat = int32(item->ExpendableArrow); if (id == "clairvoyance") - stat = uint32(item->Clairvoyance); + stat = int32(item->Clairvoyance); // Begin Effects if (id == "clickeffect") - stat = uint32(item->Click.Effect); + stat = int32(item->Click.Effect); if (id == "clicktype") - stat = uint32(item->Click.Type); + stat = int32(item->Click.Type); if (id == "clicklevel") - stat = uint32(item->Click.Level); + stat = int32(item->Click.Level); if (id == "clicklevel2") - stat = uint32(item->Click.Level2); + stat = int32(item->Click.Level2); if (id == "proceffect") - stat = uint32(item->Proc.Effect); + stat = int32(item->Proc.Effect); if (id == "proctype") - stat = uint32(item->Proc.Type); + stat = int32(item->Proc.Type); if (id == "proclevel") - stat = uint32(item->Proc.Level); + stat = int32(item->Proc.Level); if (id == "proclevel2") - stat = uint32(item->Proc.Level2); + stat = int32(item->Proc.Level2); if (id == "worneffect") - stat = uint32(item->Worn.Effect); + stat = int32(item->Worn.Effect); if (id == "worntype") - stat = uint32(item->Worn.Type); + stat = int32(item->Worn.Type); if (id == "wornlevel") - stat = uint32(item->Worn.Level); + stat = int32(item->Worn.Level); if (id == "wornlevel2") - stat = uint32(item->Worn.Level2); + stat = int32(item->Worn.Level2); if (id == "focuseffect") - stat = uint32(item->Focus.Effect); + stat = int32(item->Focus.Effect); if (id == "focustype") - stat = uint32(item->Focus.Type); + stat = int32(item->Focus.Type); if (id == "focuslevel") - stat = uint32(item->Focus.Level); + stat = int32(item->Focus.Level); if (id == "focuslevel2") - stat = uint32(item->Focus.Level2); + stat = int32(item->Focus.Level2); if (id == "scrolleffect") - stat = uint32(item->Scroll.Effect); + stat = int32(item->Scroll.Effect); if (id == "scrolltype") - stat = uint32(item->Scroll.Type); + stat = int32(item->Scroll.Type); if (id == "scrolllevel") - stat = uint32(item->Scroll.Level); + stat = int32(item->Scroll.Level); if (id == "scrolllevel2") - stat = uint32(item->Scroll.Level2); + stat = int32(item->Scroll.Level2); safe_delete(inst); return stat;