diff --git a/README.md b/README.md index baac6618e..47b835788 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,7 @@ |:---:|:---:|:---:| |**Install Count**|![Windows Install Count](http://analytics.akkadius.com/?install_count&windows_count)|![Linux Install Count](http://analytics.akkadius.com/?install_count&linux_count)| ### > Windows -* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows) -* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide) - - +* [Install](https://github.com/EQEmu/Server/wiki/Windows-Server) ### > Debian/Ubuntu/CentOS/Fedora * You can use curl or wget to kick off the installer (whichever your OS has) @@ -55,7 +52,7 @@ forum, although pull requests will be much quicker and easier on all parties. ## Resources - [EQEmulator Forums](http://www.eqemulator.org/forums) -- [EQEmulator Wiki](http://wiki.eqemulator.org/i?M=Wiki) +- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki) ## Related Repositories * [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests) diff --git a/changelog.txt b/changelog.txt index 72434e602..f2f200fa6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,63 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 03/07/2018 == +Uleat: Added command '#ucs' to force a reconnect to UCS server. + - Works in place of client auto-reconnect packet in zones where feature is unsupported + - Currently, you will need to manually re-join channels + +== 03/04/2018 == +Uleat: Updated UCS versioning + - SoF and higher clients have a new opcode identified (update your *.conf files) + - Rework of previous ucs connectivity code + - Unrelated: Zone::weatherSend() now takes an optional parameter for singular updates (as in client entering zone) + -- prior to this, every client already in-zone received a weather update packet whenever a new client zoned in + +== 02/18/2018 == +Uleat: Bug reporting fix and overhaul. + - Fixed bug reporting for SoD+ clients + - Added ability to disable bug reporting (set rule 'Bugs:ReportingSystemActive' to 'false') + - Implemented a more detailed reporting system (set rule 'Bugs:UseOldReportingMethod' to 'false') + -- New system is not currently compatible with script-based monitoring + - Soft-removal of defunct 'Petition Bug' system + +== 02/14/2018 == +mackal: Fix Heading -- Quests broken + +Please report any other issues with heading, most things were tested and worked + +You can use eqemu_server.pl to run a conversion to fix your headings in quests. +Some may need manual review. + +== 02/10/2018 == +mackal: Add Global Loot system + +This will allow us to implement global loot similarly to how it works on live +This system reuses our current loottable tables which the global_loot table references. +The limits for the rules to govern if a table should be rolled are min level, max level, rare, +raid, race, class, bodytype, and zone + +race, class, bodytype, and zone are a pipe | separated list of IDs. + +== 01/31/2018 == +Uleat: Re-work of Bot::AI_Process(). Overall behavior is much improved. + - Removed a 'ton' of unneeded packet updates + - Added a 'leash' to the distance a bot can travel + - Added a 'main assist' feature to target control (set using group roles) + - Added combat 'jitter' movement to complement the existing rogue movement + - Attack can now be aborted if target contains no leash owner nor bot hate and leash owner turns off auto-attack + - Please report any issues with the bot AI code + +Added a work-around for heal rotations crashing the server - under certain conditions. + +== 01/28/2018 == +Mackal: Spell AI tweaks + +AI spells are treated as "innate" spells (devs use this term, and I think this is what they mean by it) +These spells are spammed by the NPC, lots of encounters on live work like this and this will greatly reduce +the need to do quest scripting on these types of encounters. + +You can safely run update npc_spells_entries set priority = priority + 1 where priority >= 0; if you want to disable this new behavior + == 10/08/2017 == Mackal: Rework regens diff --git a/common/database_conversions.cpp b/common/database_conversions.cpp index d5cdbdb25..f04e9a93b 100644 --- a/common/database_conversions.cpp +++ b/common/database_conversions.cpp @@ -472,16 +472,6 @@ bool Database::CheckDatabaseConversions() { CheckDatabaseConvertPPDeblob(); CheckDatabaseConvertCorpseDeblob(); - /* Fetch EQEmu Server script */ - if (!std::ifstream("eqemu_server.pl")){ - std::cout << "Pulling down automatic database upgrade script..." << std::endl; -#ifdef _WIN32 - system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl'); if ($response->is_success){ open(FILE, '> eqemu_server.pl'); print FILE $response->decoded_content; close(FILE); }\""); -#else - system("wget --no-check-certificate -O eqemu_server.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl"); -#endif - } - /* Run EQEmu Server script (Checks for database updates) */ system("perl eqemu_server.pl ran_from_world"); diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp index a8fa73d1c..e5e9ae841 100644 --- a/common/emu_constants.cpp +++ b/common/emu_constants.cpp @@ -18,3 +18,68 @@ */ #include "emu_constants.h" + + +const char* EQEmu::bug::CategoryIDToCategoryName(CategoryID category_id) { + switch (category_id) { + case catVideo: + return "Video"; + case catAudio: + return "Audio"; + case catPathing: + return "Pathing"; + case catQuest: + return "Quest"; + case catTradeskills: + return "Tradeskills"; + case catSpellStacking: + return "Spell stacking"; + case catDoorsPortals: + return "Doors/Portals"; + case catItems: + return "Items"; + case catNPC: + return "NPC"; + case catDialogs: + return "Dialogs"; + case catLoNTCG: + return "LoN - TCG"; + case catMercenaries: + return "Mercenaries"; + case catOther: + default: + return "Other"; + } +} + +EQEmu::bug::CategoryID EQEmu::bug::CategoryNameToCategoryID(const char* category_name) { + if (!category_name) + return catOther; + + if (!strcmp(category_name, "Video")) + return catVideo; + if (!strcmp(category_name, "Audio")) + return catAudio; + if (!strcmp(category_name, "Pathing")) + return catPathing; + if (!strcmp(category_name, "Quest")) + return catQuest; + if (!strcmp(category_name, "Tradeskills")) + return catTradeskills; + if (!strcmp(category_name, "Spell stacking")) + return catSpellStacking; + if (!strcmp(category_name, "Doors/Portals")) + return catDoorsPortals; + if (!strcmp(category_name, "Items")) + return catItems; + if (!strcmp(category_name, "NPC")) + return catNPC; + if (!strcmp(category_name, "Dialogs")) + return catDialogs; + if (!strcmp(category_name, "LoN - TCG")) + return catLoNTCG; + if (!strcmp(category_name, "Mercenaries")) + return catMercenaries; + + return catOther; +} diff --git a/common/emu_constants.h b/common/emu_constants.h index e156fe98a..32968458c 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -24,7 +24,7 @@ #include "emu_legacy.h" #include "emu_versions.h" -#include +#include namespace EQEmu @@ -114,7 +114,11 @@ namespace EQEmu const EQEmu::versions::ClientVersion CharacterCreationClient = EQEmu::versions::ClientVersion::RoF2; const size_t CharacterCreationMax = RoF2::constants::CharacterCreationLimit; + const size_t SayLinkOpenerSize = 1; const size_t SayLinkBodySize = RoF2::constants::SayLinkBodySize; + const size_t SayLinkTextSize = 256; // this may be varied until it breaks something (tested:374) - the others are constant + const size_t SayLinkCloserSize = 1; + const size_t SayLinkMaximumSize = (SayLinkOpenerSize + SayLinkBodySize + SayLinkTextSize + SayLinkCloserSize); const int LongBuffs = RoF2::constants::LongBuffs; const int ShortBuffs = RoF2::constants::ShortBuffs; @@ -126,6 +130,37 @@ namespace EQEmu } /*constants*/ + namespace bug { + enum CategoryID : uint32 { + catOther = 0, + catVideo, + catAudio, + catPathing, + catQuest, + catTradeskills, + catSpellStacking, + catDoorsPortals, + catItems, + catNPC, + catDialogs, + catLoNTCG, + catMercenaries + }; + + enum OptionalInfoFlag : uint32 { + infoNoOptionalInfo = 0x0, + infoCanDuplicate = 0x1, + infoCrashBug = 0x2, + infoTargetInfo = 0x4, + infoCharacterFlags = 0x8, + infoUnknownValue = 0xFFFFFFF0 + }; + + const char* CategoryIDToCategoryName(CategoryID category_id); + CategoryID CategoryNameToCategoryID(const char* category_name); + + } // namespace bug + enum class CastingSlot : uint32 { Gem1 = 0, Gem2 = 1, diff --git a/common/emu_legacy.h b/common/emu_legacy.h index a624be883..812a33ca1 100644 --- a/common/emu_legacy.h +++ b/common/emu_legacy.h @@ -78,6 +78,8 @@ namespace EQEmu SLOT_CURSOR_BAG_END = 340, SLOT_TRIBUTE_BEGIN = 400, SLOT_TRIBUTE_END = 404, + SLOT_GUILD_TRIBUTE_BEGIN = 450, + SLOT_GUILD_TRIBUTE_END = 451, SLOT_BANK_BEGIN = 2000, SLOT_BANK_END = 2023, SLOT_BANK_BAGS_BEGIN = 2031, @@ -173,8 +175,6 @@ namespace EQEmu // POTION_BELT_SIZE sets maximum limit..active limit will need to be handled by the appropriate AA or spell (or item?) static const size_t POTION_BELT_ITEM_COUNT = 5; - - static const size_t TEXT_LINK_BODY_LENGTH = 56; } } diff --git a/common/emu_oplist.h b/common/emu_oplist.h index 319517499..5078cca68 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -340,6 +340,7 @@ N(OP_MOTD), N(OP_MoveCoin), N(OP_MoveDoor), N(OP_MoveItem), +N(OP_MoveMultipleItems), N(OP_MoveLogDisregard), N(OP_MoveLogRequest), N(OP_MultiLineMsg), @@ -392,6 +393,7 @@ N(OP_PVPLeaderBoardReply), N(OP_PVPLeaderBoardRequest), N(OP_PVPStats), N(OP_QueryResponseThing), +N(OP_QueryUCSServerStatus), N(OP_RaidInvite), N(OP_RaidJoin), N(OP_RaidUpdate), diff --git a/common/emu_versions.h b/common/emu_versions.h index 9d9e1f580..a5f3d0183 100644 --- a/common/emu_versions.h +++ b/common/emu_versions.h @@ -28,7 +28,7 @@ namespace EQEmu { namespace versions { - enum class ClientVersion { + enum class ClientVersion : uint32 { Unknown = 0, Client62, // Build: 'Aug 4 2005 15:40:59' Titanium, // Build: 'Oct 31 2005 10:33:37' @@ -72,7 +72,7 @@ namespace EQEmu uint32 ConvertClientVersionToExpansion(ClientVersion client_version); - enum class MobVersion { + enum class MobVersion : uint32 { Unknown = 0, Client62, Titanium, @@ -121,6 +121,20 @@ namespace EQEmu ClientVersion ConvertOfflinePCMobVersionToClientVersion(MobVersion mob_version); MobVersion ConvertClientVersionToOfflinePCMobVersion(ClientVersion client_version); + + enum UCSVersion : char { + ucsUnknown = '\0', + ucsClient62Chat = 'A', + ucsClient62Mail = 'a', + ucsTitaniumChat = 'B', + ucsTitaniumMail = 'b', + ucsSoFCombined = 'C', + ucsSoDCombined = 'D', + ucsUFCombined = 'E', + ucsRoFCombined = 'F', + ucsRoF2Combined = 'G' + }; + } /*versions*/ } /*EQEmu*/ diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 8452813f5..fd09f4d56 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -280,7 +280,7 @@ union // horse: 0=brown, 1=white, 2=black, 3=tan }; /*0340*/ uint32 spawnId; // Spawn Id -/*0344*/ uint8 unknown0344[3]; +/*0344*/ float bounding_radius; // used in melee, overrides calc /*0347*/ uint8 IsMercenary; /*0348*/ EQEmu::TintProfile equipment_tint; /*0384*/ uint8 lfg; // 0=off, 1=lfg on @@ -1253,21 +1253,22 @@ struct Action_Struct { /* 00 */ uint16 target; // id of target /* 02 */ uint16 source; // id of caster - /* 04 */ uint16 level; // level of caster - /* 06 */ uint16 instrument_mod; - /* 08 */ uint32 bard_focus_id; - /* 12 */ uint16 unknown16; -// some kind of sequence that's the same in both actions -// as well as the combat damage, to tie em together? - /* 14 */ uint32 sequence; - /* 18 */ uint32 unknown18; - /* 22 */ uint8 type; // 231 (0xE7) for spells - /* 23 */ uint32 unknown23; + /* 04 */ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level + /* 06 */ uint32 instrument_mod; // OSX dump says base damage, spells use it for bard song (different from newer clients) + /* 10 */ float force; + /* 14 */ float hit_heading; + /* 18 */ float hit_pitch; + /* 22 */ uint8 type; // 231 (0xE7) for spells, skill + /* 23 */ uint16 unknown23; // OSX says min_damage + /* 25 */ uint16 unknown25; // OSX says tohit /* 27 */ uint16 spell; // spell id being cast - /* 29 */ uint8 unknown29; + /* 29 */ uint8 spell_level; // this field seems to be some sort of success flag, if it's 4 - /* 30 */ uint8 buff_unknown; // if this is 4, a buff icon is made - /* 31 */ + /* 30 */ uint8 effect_flag; // if this is 4, a buff icon is made +// newer clients have some data for setting LaunchSpellData when effect_flag & 4 +// /* 31 */ uint8 spell_gem; +// /* 32 */ uint32 inventory_slot; +// /* 36 */ uint32 item_cast_type; }; // this is what prints the You have been struck. and the regular @@ -1277,12 +1278,12 @@ struct CombatDamage_Struct { /* 00 */ uint16 target; /* 02 */ uint16 source; -/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells +/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells, skill /* 05 */ uint16 spellid; /* 07 */ uint32 damage; /* 11 */ float force; -/* 15 */ float meleepush_xy; // see above notes in Action_Struct -/* 19 */ float meleepush_z; +/* 15 */ float hit_heading; // see above notes in Action_Struct +/* 19 */ float hit_pitch; /* 23 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage }; @@ -3323,23 +3324,32 @@ struct GuildMakeLeader{ char target[64]; }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ char unknown308[160]; -/*0468*/ char target_name[64]; -/*0532*/ uint32 type; -/*0536*/ char unknown536[2052]; -/*2584*/ char bug[2048]; -/*4632*/ char unknown4632[6]; -/*4638*/ char system_info[4094]; +struct BugReport_Struct { +/*0000*/ uint32 category_id; +/*0004*/ char category_name[64]; +/*0068*/ char reporter_name[64]; +/*0132*/ char unused_0132[32]; +/*0164*/ char ui_path[128]; +/*0292*/ float pos_x; +/*0296*/ float pos_y; +/*0300*/ float pos_z; +/*0304*/ uint32 heading; +/*0308*/ uint32 unused_0308; +/*0312*/ uint32 time_played; +/*0316*/ char padding_0316[8]; +/*0324*/ uint32 target_id; +/*0328*/ char padding_0328[140]; +/*0468*/ uint32 unknown_0468; // seems to always be '0' +/*0472*/ char target_name[64]; +/*0536*/ uint32 optional_info_mask; + +// this looks like a butchered 8k buffer with 2 trailing dword fields +/*0540*/ char unused_0540[2052]; +/*2592*/ char bug_report[2050]; +/*4642*/ char system_info[4098]; +/*8740*/ }; + struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3366,20 +3376,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; @@ -5356,6 +5367,23 @@ struct AuraDestory_Struct { }; // I think we can assume it's just action for 2, client doesn't seem to do anything with the rest of the data in that case +struct SayLinkBodyFrame_Struct { +/*000*/ char ActionID[1]; +/*001*/ char ItemID[5]; +/*006*/ char Augment1[5]; +/*011*/ char Augment2[5]; +/*016*/ char Augment3[5]; +/*021*/ char Augment4[5]; +/*026*/ char Augment5[5]; +/*031*/ char Augment6[5]; +/*036*/ char IsEvolving[1]; +/*037*/ char EvolveGroup[4]; +/*041*/ char EvolveLevel[2]; +/*043*/ char OrnamentIcon[5]; +/*048*/ char Hash[8]; +/*056*/ +}; + // Restore structure packing to default #pragma pack() diff --git a/common/eqemu_config.cpp b/common/eqemu_config.cpp index 96980f834..3516f15d1 100644 --- a/common/eqemu_config.cpp +++ b/common/eqemu_config.cpp @@ -23,351 +23,112 @@ #include #include -std::string EQEmuConfig::ConfigFile = "eqemu_config.xml"; +std::string EQEmuConfig::ConfigFile = "eqemu_config.json"; EQEmuConfig *EQEmuConfig::_config = nullptr; -void EQEmuConfig::do_world(TiXmlElement *ele) -{ - const char *text; - TiXmlElement * sub_ele;; - text = ParseTextBlock(ele, "shortname"); - if (text) { - ShortName = text; - } - text = ParseTextBlock(ele, "longname"); - if (text) { - LongName = text; - } - text = ParseTextBlock(ele, "address", true); - if (text) { - WorldAddress = text; - } - text = ParseTextBlock(ele, "localaddress", true); - if (text) { - LocalAddress = text; - } - text = ParseTextBlock(ele, "maxclients", true); - if (text) { - MaxClients = atoi(text); - } - // Get the element - text = ParseTextBlock(ele, "key", true); - if (text) { - SharedKey = text; - } - // Get the element - sub_ele = ele->FirstChildElement("loginserver"); - if (sub_ele) { - text = ParseTextBlock(sub_ele, "host", true); - if (text) { - LoginHost = text; - } - text = ParseTextBlock(sub_ele, "port", true); - if (text) { - LoginPort = atoi(text); - } - text = ParseTextBlock(sub_ele, "legacy", true); - if (text) { - LoginLegacy = atoi(text) > 0 ? true : false; - } - text = ParseTextBlock(sub_ele, "account", true); - if (text) { - LoginAccount = text; - } - text = ParseTextBlock(sub_ele, "password", true); - if (text) { - LoginPassword = text; - } +void EQEmuConfig::parse_config() { + + ShortName = _root["server"]["world"].get("shortname", "").asString(); + LongName = _root["server"]["world"].get("longname", "").asString(); + WorldAddress = _root["server"]["world"].get("address", "").asString(); + LocalAddress = _root["server"]["world"].get("localaddress", "").asString(); + MaxClients = atoi(_root["server"]["world"].get("maxclients", "-1").asString().c_str()); + SharedKey = _root["server"]["world"].get("key", "").asString(); + LoginCount = 0; + + if (_root["server"]["world"]["loginserver"].isObject()) { + LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString(); + LoginPort = atoi(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str()); + LoginLegacy = false; + if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") LoginLegacy = true; + LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString(); + LoginPassword = _root["server"]["world"]["loginserver"].get("password", "").asString(); } else { - char str[32]; + char str[32]; + loginlist.Clear(); do { sprintf(str, "loginserver%i", ++LoginCount); - sub_ele = ele->FirstChildElement(str); - if (sub_ele) { - auto loginconfig = new LoginConfig; - text = ParseTextBlock(sub_ele, "host", true); - if (text) { - loginconfig->LoginHost = text; - } - text = ParseTextBlock(sub_ele, "port", true); - if (text) { - loginconfig->LoginPort = atoi(text); - } - text = ParseTextBlock(sub_ele, "legacy", true); - if (text) { - loginconfig->LoginLegacy = atoi(text) > 0 ? true : false; - } - text = ParseTextBlock(sub_ele, "account", true); - if (text) { - loginconfig->LoginAccount = text; - } - text = ParseTextBlock(sub_ele, "password", true); - if (text) { - loginconfig->LoginPassword = text; - } - loginlist.Insert(loginconfig); + if (!_root["server"]["world"][str].isObject()) { + break; } - } while (sub_ele); - } - // Check for locked - sub_ele = ele->FirstChildElement("locked"); - if (sub_ele != nullptr) { - Locked = true; - } - // Get the element - sub_ele = ele->FirstChildElement("tcp"); - if (sub_ele != nullptr) { - text = sub_ele->Attribute("ip"); - if (text) { - WorldIP = text; - } - text = sub_ele->Attribute("port"); - if (text) { - WorldTCPPort = atoi(text); - } - } - sub_ele = ele->FirstChildElement("telnet"); - if (sub_ele != nullptr) { - text = sub_ele->Attribute("ip"); - if (text) { - TelnetIP = text; - } - text = sub_ele->Attribute("port"); - if (text) { - TelnetTCPPort = atoi(text); - } - text = sub_ele->Attribute("enabled"); - if (text && !strcasecmp(text, "true")) { - TelnetEnabled = true; - } - } + auto loginconfig = new LoginConfig; + loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString(); + loginconfig->LoginPort = atoi(_root["server"]["world"][str].get("port", "5998").asString().c_str()); + loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString(); + loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString(); - // Get the element - sub_ele = ele->FirstChildElement("http"); - if (sub_ele != nullptr) { -// text = sub_ele->Attribute("ip"); -// if (text) -// WorldIP=text; - text = sub_ele->Attribute("mimefile"); - if (text) { - WorldHTTPMimeFile = text; - } - text = sub_ele->Attribute("port"); - if (text) { - WorldHTTPPort = atoi(text); - } - text = sub_ele->Attribute("enabled"); - if (text && !strcasecmp(text, "true")) { - WorldHTTPEnabled = true; - } + loginconfig->LoginLegacy = false; + if (_root["server"]["world"][str].get("legacy", "0").asString() == "1") loginconfig->LoginLegacy = true; + loginlist.Insert(loginconfig); + } while (LoginCount < 100); } + + + // from xml converts to json as locked: "", so i default to "false". + //The only way to enable locked is by switching to true, meaning this value is always false until manually set true + Locked = false; + if (_root["server"]["world"].get("locked", "false").asString() == "true") Locked = true; + WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString(); + WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str()); + + TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString(); + TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str()); + TelnetEnabled = false; + if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") TelnetEnabled = true; + + WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString(); + WorldHTTPPort = atoi(_root["server"]["world"]["http"].get("port", "9080").asString().c_str()); + WorldHTTPEnabled = false; + if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") WorldHTTPEnabled = true; + + ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString(); + ChatPort = atoi(_root["server"]["chatserver"].get("port", "7778").asString().c_str()); + + MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString(); + MailPort = atoi(_root["server"]["mailserver"].get("port", "7778").asString().c_str()); + + DatabaseUsername = _root["server"]["database"].get("username", "eq").asString(); + DatabasePassword = _root["server"]["database"].get("password", "eq").asString(); + DatabaseHost = _root["server"]["database"].get("host", "localhost").asString(); + DatabasePort = atoi(_root["server"]["database"].get("port", "3306").asString().c_str()); + DatabaseDB = _root["server"]["database"].get("db", "eq").asString(); + + QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString(); + QSDatabasePort = atoi(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str()); + QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString(); + QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString(); + QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString(); + + DefaultStatus = atoi(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str()); + ZonePortLow = atoi(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str()); + ZonePortHigh = atoi(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str()); + + SpellsFile = _root["server"]["files"].get("spells", "spells_us.txt").asString(); + OpCodesFile = _root["server"]["files"].get("opcodes", "opcodes.conf").asString(); + PluginPlFile = _root["server"]["files"].get("plugin.pl", "plugin.pl").asString(); + + MapDir = _root["server"]["directories"].get("maps", "Maps/").asString(); + QuestDir = _root["server"]["directories"].get("quests", "quests/").asString(); + PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString(); + LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString(); + PatchDir = _root["server"]["directories"].get("patches", "./").asString(); + SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString(); + LogDir = _root["server"]["directories"].get("logs", "logs/").asString(); + + LogPrefix = _root["server"]["launcher"].get("logprefix", "logs/zone-").asString(); + LogSuffix = _root["server"]["launcher"].get("logsuffix", ".log").asString(); + RestartWait = atoi(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str()); + TerminateWait = atoi(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str()); + InitialBootWait = atoi(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str()); + ZoneBootInterval = atoi(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str()); +#ifdef WIN32 + ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString(); +#else + ZoneExe = _root["server"]["launcher"].get("exe", "./zone").asString(); +#endif + } - -void EQEmuConfig::do_chatserver(TiXmlElement *ele) -{ - const char *text; - text = ParseTextBlock(ele, "host", true); - if (text) { - ChatHost = text; - } - text = ParseTextBlock(ele, "port", true); - if (text) { - ChatPort = atoi(text); - } -} - -void EQEmuConfig::do_mailserver(TiXmlElement *ele) -{ - const char *text; - text = ParseTextBlock(ele, "host", true); - if (text) { - MailHost = text; - } - text = ParseTextBlock(ele, "port", true); - if (text) { - MailPort = atoi(text); - } -} - -void EQEmuConfig::do_database(TiXmlElement *ele) -{ - const char *text; - text = ParseTextBlock(ele, "host", true); - if (text) { - DatabaseHost = text; - } - text = ParseTextBlock(ele, "port", true); - if (text) { - DatabasePort = atoi(text); - } - text = ParseTextBlock(ele, "username", true); - if (text) { - DatabaseUsername = text; - } - text = ParseTextBlock(ele, "password", true); - if (text) { - DatabasePassword = text; - } - text = ParseTextBlock(ele, "db", true); - if (text) { - DatabaseDB = text; - } -} - - -void EQEmuConfig::do_qsdatabase(TiXmlElement *ele) -{ - const char *text; - text = ParseTextBlock(ele, "host", true); - if (text) { - QSDatabaseHost = text; - } - text = ParseTextBlock(ele, "port", true); - if (text) { - QSDatabasePort = atoi(text); - } - text = ParseTextBlock(ele, "username", true); - if (text) { - QSDatabaseUsername = text; - } - text = ParseTextBlock(ele, "password", true); - if (text) { - QSDatabasePassword = text; - } - text = ParseTextBlock(ele, "db", true); - if (text) { - QSDatabaseDB = text; - } -} - -void EQEmuConfig::do_zones(TiXmlElement *ele) -{ - const char *text; - TiXmlElement *sub_ele; -// TiXmlNode *node,*sub_node; - text = ParseTextBlock(ele, "defaultstatus", true); - if (text) { - DefaultStatus = atoi(text); - } - // Get the element - sub_ele = ele->FirstChildElement("ports"); - if (sub_ele != nullptr) { - text = sub_ele->Attribute("low"); - if (text) { - ZonePortLow = atoi(text); - }; - text = sub_ele->Attribute("high"); - if (text) { - ZonePortHigh = atoi(text); - } - } -} - -void EQEmuConfig::do_files(TiXmlElement *ele) -{ - const char *text; - text = ParseTextBlock(ele, "spells", true); - if (text) { - SpellsFile = text; - } - text = ParseTextBlock(ele, "opcodes", true); - if (text) { - OpCodesFile = text; - } - text = ParseTextBlock(ele, "plugin.pl", true); - if (text) { - PluginPlFile = text; - } -} - -void EQEmuConfig::do_directories(TiXmlElement *ele) -{ - const char *text; - text = ParseTextBlock(ele, "maps", true); - if (text) { - MapDir = text; - if ( MapDir.back() != '/' ) - MapDir += '/'; - } - text = ParseTextBlock(ele, "quests", true); - if (text) { - QuestDir = text; - if ( QuestDir.back() != '/' ) - QuestDir += '/'; - } - text = ParseTextBlock(ele, "plugins", true); - if (text) { - PluginDir = text; - if ( PluginDir.back() != '/' ) - PluginDir += '/'; - } - text = ParseTextBlock(ele, "lua_modules", true); - if (text) { - LuaModuleDir = text; - if ( LuaModuleDir.back() != '/' ) - LuaModuleDir += '/'; - } - text = ParseTextBlock(ele, "patches", true); - if (text) { - PatchDir = text; - if ( PatchDir.back() != '/' ) - PatchDir += '/'; - } - text = ParseTextBlock(ele, "shared_memory", true); - if (text) { - SharedMemDir = text; - if ( SharedMemDir.back() != '/' ) - SharedMemDir += '/'; - } - //Not Fully Implemented yet LogDir - text = ParseTextBlock(ele, "logs", true); - if (text) { - LogDir = text; - if ( LogDir.back() != '/' ) - LogDir += '/'; - } -} - -void EQEmuConfig::do_launcher(TiXmlElement *ele) -{ - const char *text; - TiXmlElement *sub_ele; - text = ParseTextBlock(ele, "logprefix", true); - if (text) { - LogPrefix = text; - } - text = ParseTextBlock(ele, "logsuffix", true); - if (text) { - LogSuffix = text; - } - // Get the element - text = ParseTextBlock(ele, "exe", true); - if (text) { - ZoneExe = text; - } - // Get the element - sub_ele = ele->FirstChildElement("timers"); - if (sub_ele != nullptr) { - text = sub_ele->Attribute("restart"); - if (text) { - RestartWait = atoi(text); - } - text = sub_ele->Attribute("reterminate"); - if (text) { - TerminateWait = atoi(text); - } - text = sub_ele->Attribute("initial"); - if (text) { - InitialBootWait = atoi(text); - } - text = sub_ele->Attribute("interval"); - if (text) { - ZoneBootInterval = atoi(text); - } - } -} - std::string EQEmuConfig::GetByName(const std::string &var_name) const { if (var_name == "ShortName") { @@ -564,4 +325,3 @@ void EQEmuConfig::Dump() const std::cout << "DefaultStatus = " << (int)DefaultStatus << std::endl; // std::cout << "DynamicCount = " << DynamicCount << std::endl; } - diff --git a/common/eqemu_config.h b/common/eqemu_config.h index 0f51f550f..66cf962c6 100644 --- a/common/eqemu_config.h +++ b/common/eqemu_config.h @@ -18,8 +18,9 @@ #ifndef __EQEmuConfig_H #define __EQEmuConfig_H -#include "xml_parser.h" +#include "json/json.h" #include "linked_list.h" +#include struct LoginConfig { std::string LoginHost; @@ -29,7 +30,7 @@ struct LoginConfig { bool LoginLegacy; }; -class EQEmuConfig : public XMLParser +class EQEmuConfig { public: virtual std::string GetByName(const std::string &var_name) const; @@ -115,88 +116,14 @@ class EQEmuConfig : public XMLParser protected: static EQEmuConfig *_config; - + Json::Value _root; static std::string ConfigFile; -#define ELEMENT(name) \ - void do_##name(TiXmlElement *ele); -#include "eqemu_config_elements.h" - + void parse_config(); EQEmuConfig() - { - // import the needed handler prototypes -#define ELEMENT(name) \ - Handlers[#name]=(ElementHandler)&EQEmuConfig::do_##name; -#include "eqemu_config_elements.h" - // Set sane defaults - // Login server - LoginHost = "login.eqemulator.net"; - LoginPort = 5998; - LoginLegacy = false; - // World - Locked = false; - WorldTCPPort = 9000; - TelnetTCPPort = 9001; - TelnetEnabled = false; - WorldHTTPEnabled = false; - WorldHTTPPort = 9080; - WorldHTTPMimeFile = "mime.types"; - SharedKey = ""; //blank disables authentication - // Mail - ChatHost = "eqchat.eqemulator.net"; - ChatPort = 7778; - // Mail - MailHost = "eqmail.eqemulator.net"; - MailPort = 7779; - // Mysql - DatabaseHost = "localhost"; - DatabasePort = 3306; - DatabaseUsername = "eq"; - DatabasePassword = "eq"; - DatabaseDB = "eq"; - // QueryServ Database - QSDatabaseHost = "localhost"; - QSDatabasePort = 3306; - QSDatabaseUsername = "eq"; - QSDatabasePassword = "eq"; - QSDatabaseDB = "eq"; - // Files - SpellsFile = "spells_us.txt"; - OpCodesFile = "opcodes.conf"; - PluginPlFile = "plugin.pl"; - // Dirs - MapDir = "Maps/"; - QuestDir = "quests/"; - PluginDir = "plugins/"; - LuaModuleDir = "lua_modules/"; - PatchDir = "./"; - SharedMemDir = "shared/"; - LogDir = "logs/"; + { - // Launcher - LogPrefix = "logs/zone-"; - LogSuffix = ".log"; - RestartWait = 10000; //milliseconds - TerminateWait = 10000; //milliseconds - InitialBootWait = 20000; //milliseconds - ZoneBootInterval = 2000; //milliseconds - #ifdef WIN32 - ZoneExe = "zone.exe"; - #else - ZoneExe = "./zone"; - #endif - // Zones - ZonePortLow = 7000; - ZonePortHigh = 7999; - DefaultStatus = 0; - // For where zones need to connect to. - WorldIP = "127.0.0.1"; - TelnetIP = "127.0.0.1"; - // Dynamics to start - //DynamicCount=5; - MaxClients = -1; - LoginCount = 0; } virtual ~EQEmuConfig() {} @@ -205,9 +132,7 @@ class EQEmuConfig : public XMLParser // Produce a const singleton static const EQEmuConfig *get() { - if (_config == nullptr) { - LoadConfig(); - } + LoadConfig(); return (_config); } @@ -221,10 +146,28 @@ class EQEmuConfig : public XMLParser static bool LoadConfig() { if (_config != nullptr) { - delete _config; + return true; } _config = new EQEmuConfig; - return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(), "server"); + + return parseFile(); + } + + // Load config file and parse data + static bool parseFile() { + if (_config == nullptr) { + return LoadConfig(); + } + + std::ifstream fconfig(EQEmuConfig::ConfigFile, std::ifstream::binary); + try { + fconfig >> _config->_root; + _config->parse_config(); + } + catch (std::exception) { + return false; + } + return true; } void Dump() const; diff --git a/common/features.h b/common/features.h index 486255f28..a35431bff 100644 --- a/common/features.h +++ b/common/features.h @@ -219,6 +219,9 @@ enum { //some random constants //the square of the maximum range at whihc you could possibly use NPC services (shop, tribute, etc) #define USE_NPC_RANGE2 200*200 //arbitrary right now +// Squared range for rampage 75.0 * 75.0 for now +#define NPC_RAMPAGE_RANGE2 5625.0f + //the formula for experience for killing a mob. //level is the only valid variable to use #define EXP_FORMULA level*level*75*35/10 diff --git a/common/glm/glm/simd/platform.h b/common/glm/glm/simd/platform.h index f77939088..19bce7d02 100644 --- a/common/glm/glm/simd/platform.h +++ b/common/glm/glm/simd/platform.h @@ -111,7 +111,8 @@ #define GLM_COMPILER_GCC70 0x02000A00 #define GLM_COMPILER_GCC71 0x02000B00 #define GLM_COMPILER_GCC72 0x02000C00 -#define GLM_COMPILER_GCC80 0x02000D00 +#define GLM_COMPILER_GCC73 0x02000D00 +#define GLM_COMPILER_GCC80 0x02000E00 // CUDA #define GLM_COMPILER_CUDA 0x10000000 @@ -283,6 +284,8 @@ # define GLM_COMPILER (GLM_COMPILER_GCC71) # elif (__GNUC__ == 7) && (__GNUC_MINOR__ == 2) # define GLM_COMPILER (GLM_COMPILER_GCC72) +# elif (__GNUC__ == 7) && (__GNUC_MINOR__ == 3) +# define GLM_COMPILER (GLM_COMPILER_GCC73) # elif (__GNUC__ >= 8) # define GLM_COMPILER (GLM_COMPILER_GCC80) # else diff --git a/common/misc_functions.cpp b/common/misc_functions.cpp index dcdbad561..e31da211f 100644 --- a/common/misc_functions.cpp +++ b/common/misc_functions.cpp @@ -194,32 +194,70 @@ uint32 rnd_hash( time_t t, clock_t c ) float EQ13toFloat(int d) { - return ( float(d)/float(1<<2)); -} - -float NewEQ13toFloat(int d) -{ - return ( float(d)/float(1<<6)); + return static_cast(d) / 64.0f; } float EQ19toFloat(int d) { - return ( float(d)/float(1<<3)); + return static_cast(d) / 8.0f; } int FloatToEQ13(float d) { - return int(d*float(1<<2)); -} - -int NewFloatToEQ13(float d) -{ - return int(d*float(1<<6)); + return static_cast(d * 64.0f); } int FloatToEQ19(float d) { - return int(d*float(1<<3)); + return static_cast(d * 8.0f); +} + +float EQ12toFloat(int d) +{ + return static_cast(d) / 4.0f; +} + +int FloatToEQ12(float d) +{ + return static_cast((d + 2048.0f) * 4.0f) % 2048; +} + +float EQ10toFloat(int d) +{ + return static_cast(d) / 20.0f; +} + +int FloatToEQ10(float d) +{ + return static_cast(d * 20.0f); +} + +float EQSpeedRunToFloat(int d) +{ + return static_cast(d) / 40.0f; +} + +int FloatToEQSpeedRun(float d) +{ + return static_cast(d * 40.0f); +} + +float FixHeading(float in) +{ + int i = 0; + if (in >= 512.0f) { + do { + in -= 512.0f; + } while (in >= 512.0f && i++ <= 5); + } + i = 0; + if (in < 0.0f) { + do { + in += 512.0f; + } while (in < 0.0f && i++ <= 5); + } + + return in; } /* diff --git a/common/misc_functions.h b/common/misc_functions.h index 501244fda..8214c7df0 100644 --- a/common/misc_functions.h +++ b/common/misc_functions.h @@ -50,13 +50,25 @@ uint32 ResolveIP(const char* hostname, char* errbuf = 0); bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf = 0); void CoutTimestamp(bool ms = true); float EQ13toFloat(int d); -float NewEQ13toFloat(int d); float EQ19toFloat(int d); float EQHtoFloat(int d); int FloatToEQ13(float d); -int NewFloatToEQ13(float d); int FloatToEQ19(float d); int FloatToEQH(float d); + +float EQ12toFloat(int d); +int FloatToEQ12(float d); + +float EQ10toFloat(int d); +int FloatToEQ10(float d); + +// this is also a 10 bit float +float EQSpeedRunToFloat(int d); +int FloatToEQSpeedRun(float d); + +// brings heading back into EQ angles range +float FixHeading(float in); + uint32 SwapBits21and22(uint32 mask); uint32 Catch22(uint32 mask); diff --git a/common/net/daybreak_connection.cpp b/common/net/daybreak_connection.cpp index 095fab525..d32f9f678 100644 --- a/common/net/daybreak_connection.cpp +++ b/common/net/daybreak_connection.cpp @@ -165,7 +165,7 @@ void EQ::Net::DaybreakConnectionManager::ProcessResend() { auto iter = m_connections.begin(); while (iter != m_connections.end()) { - auto connection = iter->second; + auto &connection = iter->second; auto status = connection->m_status; switch (status) @@ -1397,4 +1397,4 @@ EQ::Net::SequenceOrder EQ::Net::DaybreakConnection::CompareSequence(uint16_t exp } return SequencePast; -} \ No newline at end of file +} diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index b655cffb0..62ef6751a 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -57,11 +57,11 @@ namespace RoF static inline uint32 RoFToServerTypelessSlot(structs::TypelessInventorySlot_Struct rofSlot); static inline uint32 RoFToServerCorpseSlot(uint32 rofCorpseSlot); - // server to client text link converter - static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink); + // server to client say link converter + static inline void ServerToRoFSayLink(std::string& rofSayLink, const std::string& serverSayLink); - // client to server text link converter - static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink); + // client to server say link converter + static inline void RoFToServerSayLink(std::string& serverSayLink, const std::string& rofSayLink); static inline CastingSlot ServerToRoFCastingSlot(EQEmu::CastingSlot slot); static inline EQEmu::CastingSlot RoFToServerCastingSlot(CastingSlot slot); @@ -163,22 +163,23 @@ namespace RoF OUT(level); eq->unknown06 = 0; eq->instrument_mod = 1.0f + (emu->instrument_mod - 10) / 10.0f; - eq->bard_focus_id = emu->bard_focus_id; - eq->knockback_angle = emu->sequence; - eq->unknown22 = 0; + OUT(force); + OUT(hit_heading); + OUT(hit_pitch); OUT(type); eq->damage = 0; eq->unknown31 = 0; OUT(spell); - eq->level2 = eq->level; - eq->effect_flag = emu->buff_unknown; - eq->unknown39 = 14; - eq->unknown43 = 0; - eq->unknown44 = 17; - eq->unknown45 = 0; - eq->unknown46 = -1; - eq->unknown50 = 0; - eq->unknown54 = 0; + OUT(spell_level); + OUT(effect_flag); + eq->spell_gem = 0; + eq->slot.Type = INVALID_INDEX; + eq->slot.Unknown02 = 0; + eq->slot.Slot = INVALID_INDEX; + eq->slot.SubIndex = INVALID_INDEX; + eq->slot.AugIndex = INVALID_INDEX; + eq->slot.Unknown01 = 0; + eq->item_cast_type = 0; FINISH_ENCODE(); } @@ -520,7 +521,7 @@ namespace RoF std::string old_message = emu->message; std::string new_message; - ServerToRoFTextLink(new_message, old_message); + ServerToRoFSayLink(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; @@ -659,8 +660,8 @@ namespace RoF OUT(spellid); OUT(damage); OUT(force); - OUT(meleepush_xy); - OUT(meleepush_z); + OUT(hit_heading); + OUT(hit_pitch); OUT(special); FINISH_ENCODE(); @@ -847,7 +848,7 @@ namespace RoF std::string old_message = emu->message; std::string new_message; - ServerToRoFTextLink(new_message, old_message); + ServerToRoFSayLink(new_message, old_message); //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) // new_message = new_message.substr(0, 512); @@ -899,7 +900,7 @@ namespace RoF for (int i = 0; i < 9; ++i) { if (old_message_array[i].length() == 0) { break; } - ServerToRoFTextLink(new_message_array[i], old_message_array[i]); + ServerToRoFSayLink(new_message_array[i], old_message_array[i]); new_message_size += new_message_array[i].length() + 1; } @@ -3295,7 +3296,7 @@ namespace RoF std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; - ServerToRoFTextLink(new_message, old_message); + ServerToRoFSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; in->size = strlen(emu->sayer) + new_message.length() + 25; @@ -3369,7 +3370,7 @@ namespace RoF std::string old_message = InBuffer; // start 'Reward' as string std::string new_message; - ServerToRoFTextLink(new_message, old_message); + ServerToRoFSayLink(new_message, old_message); in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ @@ -3847,9 +3848,12 @@ namespace RoF OUT(y); OUT(x); OUT(z) - OUT(zone_reason); + OUT(zone_reason); OUT(success); + if (eq->success < 0) + eq->success -= 1; + FINISH_ENCODE(); } @@ -4352,7 +4356,7 @@ namespace RoF std::string old_message = InBuffer; std::string new_message; - RoFToServerTextLink(new_message, old_message); + RoFToServerSayLink(new_message, old_message); //__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1; __packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; @@ -4463,7 +4467,7 @@ namespace RoF IN(type); IN(spellid); IN(damage); - IN(meleepush_xy); + IN(hit_heading); FINISH_DIRECT_DECODE(); } @@ -4486,7 +4490,7 @@ namespace RoF std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset std::string new_message; - RoFToServerTextLink(new_message, old_message); + RoFToServerSayLink(new_message, old_message); __packet->size = sizeof(Emote_Struct); __packet->pBuffer = new unsigned char[__packet->size]; @@ -5913,19 +5917,19 @@ namespace RoF return (rofCorpseSlot - 1); } - static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink) + static inline void ServerToRoFSayLink(std::string& rofSayLink, const std::string& serverSayLink) { - if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { - rofTextLink = serverTextLink; + if ((constants::SayLinkBodySize == EQEmu::constants::SayLinkBodySize) || (serverSayLink.find('\x12') == std::string::npos)) { + rofSayLink = serverSayLink; return; } - auto segments = SplitString(serverTextLink, '\x12'); + auto segments = SplitString(serverSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { - rofTextLink.append(segments[segment_iter]); + if (segments[segment_iter].length() <= EQEmu::constants::SayLinkBodySize) { + rofSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -5935,36 +5939,36 @@ namespace RoF // RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55) // Diff: ^ - rofTextLink.push_back('\x12'); - rofTextLink.append(segments[segment_iter].substr(0, 41)); + rofSayLink.push_back('\x12'); + rofSayLink.append(segments[segment_iter].substr(0, 41)); if (segments[segment_iter][41] == '0') - rofTextLink.push_back(segments[segment_iter][42]); + rofSayLink.push_back(segments[segment_iter][42]); else - rofTextLink.push_back('F'); + rofSayLink.push_back('F'); - rofTextLink.append(segments[segment_iter].substr(43)); - rofTextLink.push_back('\x12'); + rofSayLink.append(segments[segment_iter].substr(43)); + rofSayLink.push_back('\x12'); } else { - rofTextLink.append(segments[segment_iter]); + rofSayLink.append(segments[segment_iter]); } } } - static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink) + static inline void RoFToServerSayLink(std::string& serverSayLink, const std::string& rofSayLink) { - if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (rofTextLink.find('\x12') == std::string::npos)) { - serverTextLink = rofTextLink; + if ((EQEmu::constants::SayLinkBodySize == constants::SayLinkBodySize) || (rofSayLink.find('\x12') == std::string::npos)) { + serverSayLink = rofSayLink; return; } - auto segments = SplitString(rofTextLink, '\x12'); + auto segments = SplitString(rofSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { if (segments[segment_iter].length() <= constants::SayLinkBodySize) { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -5974,14 +5978,14 @@ namespace RoF // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^ - serverTextLink.push_back('\x12'); - serverTextLink.append(segments[segment_iter].substr(0, 41)); - serverTextLink.push_back('0'); - serverTextLink.append(segments[segment_iter].substr(41)); - serverTextLink.push_back('\x12'); + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 41)); + serverSayLink.push_back('0'); + serverSayLink.append(segments[segment_iter].substr(41)); + serverSayLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); } } } diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index baf6d6b09..5a30c1695 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -57,11 +57,11 @@ namespace RoF2 static inline uint32 RoF2ToServerTypelessSlot(structs::TypelessInventorySlot_Struct rof2Slot); static inline uint32 RoF2ToServerCorpseSlot(uint32 rof2CorpseSlot); - // server to client text link converter - static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink); + // server to client say link converter + static inline void ServerToRoF2SayLink(std::string& rof2SayLink, const std::string& serverSayLink); - // client to server text link converter - static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink); + // client to server say link converter + static inline void RoF2ToServerSayLink(std::string& serverSayLink, const std::string& rof2SayLink); static inline CastingSlot ServerToRoF2CastingSlot(EQEmu::CastingSlot slot); static inline EQEmu::CastingSlot RoF2ToServerCastingSlot(CastingSlot slot); @@ -232,22 +232,23 @@ namespace RoF2 OUT(level); eq->unknown06 = 0; eq->instrument_mod = 1.0f + (emu->instrument_mod - 10) / 10.0f; - eq->bard_focus_id = emu->bard_focus_id; - eq->knockback_angle = emu->sequence; - eq->unknown22 = 0; + OUT(force); + OUT(hit_heading); + OUT(hit_pitch); OUT(type); eq->damage = 0; eq->unknown31 = 0; OUT(spell); - eq->level2 = eq->level; - eq->effect_flag = emu->buff_unknown; - eq->unknown39 = 14; - eq->unknown43 = 0; - eq->unknown44 = 17; - eq->unknown45 = 0; - eq->unknown46 = -1; - eq->unknown50 = 0; - eq->unknown54 = 0; + OUT(spell_level); + OUT(effect_flag); + eq->spell_gem = 0; + eq->slot.Type = INVALID_INDEX; + eq->slot.Unknown02 = 0; + eq->slot.Slot = INVALID_INDEX; + eq->slot.SubIndex = INVALID_INDEX; + eq->slot.AugIndex = INVALID_INDEX; + eq->slot.Unknown01 = 0; + eq->item_cast_type = 0; FINISH_ENCODE(); } @@ -588,7 +589,7 @@ namespace RoF2 std::string old_message = emu->message; std::string new_message; - ServerToRoF2TextLink(new_message, old_message); + ServerToRoF2SayLink(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; @@ -727,8 +728,8 @@ namespace RoF2 OUT(spellid); OUT(damage); OUT(force); - OUT(meleepush_xy); - OUT(meleepush_z); + OUT(hit_heading); + OUT(hit_pitch); OUT(special); FINISH_ENCODE(); @@ -915,7 +916,7 @@ namespace RoF2 std::string old_message = emu->message; std::string new_message; - ServerToRoF2TextLink(new_message, old_message); + ServerToRoF2SayLink(new_message, old_message); //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) // new_message = new_message.substr(0, 512); @@ -967,7 +968,7 @@ namespace RoF2 for (int i = 0; i < 9; ++i) { if (old_message_array[i].length() == 0) { break; } - ServerToRoF2TextLink(new_message_array[i], old_message_array[i]); + ServerToRoF2SayLink(new_message_array[i], old_message_array[i]); new_message_size += new_message_array[i].length() + 1; } @@ -3364,7 +3365,7 @@ namespace RoF2 std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; - ServerToRoF2TextLink(new_message, old_message); + ServerToRoF2SayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; in->size = strlen(emu->sayer) + new_message.length() + 25; @@ -3438,7 +3439,7 @@ namespace RoF2 std::string old_message = InBuffer; // start 'Reward' as string std::string new_message; - ServerToRoF2TextLink(new_message, old_message); + ServerToRoF2SayLink(new_message, old_message); in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ @@ -3991,9 +3992,12 @@ namespace RoF2 OUT(y); OUT(x); OUT(z) - OUT(zone_reason); + OUT(zone_reason); OUT(success); + if (eq->success < 0) + eq->success -= 1; + FINISH_ENCODE(); } @@ -4592,7 +4596,7 @@ namespace RoF2 std::string old_message = InBuffer; std::string new_message; - RoF2ToServerTextLink(new_message, old_message); + RoF2ToServerSayLink(new_message, old_message); //__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1; __packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; @@ -4703,7 +4707,7 @@ namespace RoF2 IN(type); IN(spellid); IN(damage); - IN(meleepush_xy); + IN(hit_heading); FINISH_DIRECT_DECODE(); } @@ -4726,7 +4730,7 @@ namespace RoF2 std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset std::string new_message; - RoF2ToServerTextLink(new_message, old_message); + RoF2ToServerSayLink(new_message, old_message); __packet->size = sizeof(Emote_Struct); __packet->pBuffer = new unsigned char[__packet->size]; @@ -6230,19 +6234,19 @@ namespace RoF2 return (rof2CorpseSlot + EQEmu::legacy::CORPSE_BEGIN - 1); } - static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink) + static inline void ServerToRoF2SayLink(std::string& rof2SayLink, const std::string& serverSayLink) { - if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { - rof2TextLink = serverTextLink; + if ((constants::SayLinkBodySize == EQEmu::constants::SayLinkBodySize) || (serverSayLink.find('\x12') == std::string::npos)) { + rof2SayLink = serverSayLink; return; } - auto segments = SplitString(serverTextLink, '\x12'); + auto segments = SplitString(serverSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { - rof2TextLink.append(segments[segment_iter]); + if (segments[segment_iter].length() <= EQEmu::constants::SayLinkBodySize) { + rof2SayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -6252,29 +6256,29 @@ namespace RoF2 // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: - rof2TextLink.push_back('\x12'); - rof2TextLink.append(segments[segment_iter]); - rof2TextLink.push_back('\x12'); + rof2SayLink.push_back('\x12'); + rof2SayLink.append(segments[segment_iter]); + rof2SayLink.push_back('\x12'); } else { - rof2TextLink.append(segments[segment_iter]); + rof2SayLink.append(segments[segment_iter]); } } } - static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink) + static inline void RoF2ToServerSayLink(std::string& serverSayLink, const std::string& rof2SayLink) { - if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (rof2TextLink.find('\x12') == std::string::npos)) { - serverTextLink = rof2TextLink; + if ((EQEmu::constants::SayLinkBodySize == constants::SayLinkBodySize) || (rof2SayLink.find('\x12') == std::string::npos)) { + serverSayLink = rof2SayLink; return; } - auto segments = SplitString(rof2TextLink, '\x12'); + auto segments = SplitString(rof2SayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { if (segments[segment_iter].length() <= constants::SayLinkBodySize) { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -6284,12 +6288,12 @@ namespace RoF2 // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: - serverTextLink.push_back('\x12'); - serverTextLink.append(segments[segment_iter]); - serverTextLink.push_back('\x12'); + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter]); + serverSayLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); } } } diff --git a/common/patches/rof2_limits.h b/common/patches/rof2_limits.h index 6f4e649ff..0dd7067a9 100644 --- a/common/patches/rof2_limits.h +++ b/common/patches/rof2_limits.h @@ -164,7 +164,7 @@ namespace RoF2 ItemPacket11 = 111, ItemPacket12 = 112, ItemPacketRecovery = 113, - ItemPacket14 = 115 + ItemPacket14 = 115 // Parcel? adds to merchant window too }; } /*item*/ diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 28905dd4a..5be96e071 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -400,7 +400,7 @@ struct Spawn_Struct_Position struct Spawn_Struct_Position { - signed padding0000:12; + signed angle:12; // pitch of camera? signed y:19; signed padding0001:1; @@ -416,7 +416,7 @@ struct Spawn_Struct_Position signed z:19; signed padding0020:3; - signed animation:10; // animation + signed animation:10; // SpeedRun signed deltaY:13; signed padding0023:9; }; @@ -430,7 +430,7 @@ struct Spawn_Struct /*0000*/ //uint8 nullterm1; // hack to null terminate name /*0064*/ uint32 spawnId; /*0068*/ uint8 level; -/*0069*/ float unknown1; +/*0069*/ float bounding_radius; // used in melee, overrides calc /*0073*/ uint8 NPC; // 0=player,1=npc,2=pc corpse,3=npc corpse Spawn_Struct_Bitfields Bitfields; /*0000*/ uint8 otherData; // & 4 - has title, & 8 - has suffix, & 1 - it's a chest or untargetable @@ -1462,17 +1462,17 @@ struct Action_Struct { /*00*/ uint16 target; // id of target /*02*/ uint16 source; // id of caster -/*04*/ uint16 level; // level of caster - Seen 0 -/*06*/ uint32 unknown06; +/*04*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*06*/ uint32 unknown06; // OSX dump says base_damage, was used for bard mod too, this is 0'd :( /*10*/ float instrument_mod; -/*14*/ uint32 bard_focus_id; // seen 0 -/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again -/*22*/ uint32 unknown22; -/*26*/ uint8 type; -/*27*/ uint32 damage; -/*31*/ uint16 unknown31; +/*14*/ float force; +/*18*/ float hit_heading; +/*22*/ float hit_pitch; +/*26*/ uint8 type; // 231 (0xE7) for spells, skill +/*27*/ uint32 damage; // OSX says min_damage +/*31*/ uint16 unknown31; // OSX says tohit /*33*/ uint32 spell; // spell id being cast -/*37*/ uint8 level2; // level of caster again? Or maybe the castee +/*37*/ uint8 spell_level; // level of caster again? Or maybe the castee /*38*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? /*39*/ }; @@ -1484,25 +1484,21 @@ struct ActionAlt_Struct { /*00*/ uint16 target; // id of target /*02*/ uint16 source; // id of caster -/*04*/ uint16 level; // level of caster - Seen 0 -/*06*/ uint32 unknown06; +/*04*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*06*/ uint32 unknown06; // OSX dump says base_damage, was used for bard mod too, this is 0'd :( /*10*/ float instrument_mod; -/*14*/ uint32 bard_focus_id; // seen 0 -/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again -/*22*/ uint32 unknown22; -/*26*/ uint8 type; -/*27*/ uint32 damage; -/*31*/ uint16 unknown31; +/*14*/ float force; +/*18*/ float hit_heading; +/*22*/ float hit_pitch; +/*26*/ uint8 type; // 231 (0xE7) for spells, skill +/*27*/ uint32 damage; // OSX says min_damage +/*31*/ uint16 unknown31; // OSX says tohit /*33*/ uint32 spell; // spell id being cast -/*37*/ uint8 level2; // level of caster again? Or maybe the castee +/*37*/ uint8 spell_level; // level of caster again? Or maybe the castee /*38*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? -/*39*/ uint32 unknown39; // New field to Underfoot - Seen 14 -/*43*/ uint8 unknown43; // New field to Underfoot - Seen 0 -/*44*/ uint8 unknown44; // New field to Underfoot - Seen 17 -/*45*/ uint8 unknown45; // New field to Underfoot - Seen 0 -/*46*/ int32 unknown46; // New field to Underfoot - Seen -1 -/*50*/ uint32 unknown50; // New field to Underfoot - Seen 0 -/*54*/ uint16 unknown54; // New field to Underfoot - Seen 0 +/*39*/ uint8 spell_gem; +/*40*/ InventorySlot_Struct slot; +/*52*/ uint32 item_cast_type; // ItemSpellTypes enum from MQ2 /*56*/ }; @@ -1517,9 +1513,9 @@ struct CombatDamage_Struct /* 05 */ uint32 spellid; /* 09 */ int32 damage; /* 13 */ float force; // cd cc cc 3d -/* 17 */ float meleepush_xy; // see above notes in Action_Struct -/* 21 */ float meleepush_z; -/* 25 */ uint8 unknown25; // was [9] +/* 17 */ float hit_heading; // see above notes in Action_Struct +/* 21 */ float hit_pitch; +/* 25 */ uint8 secondary; // 0 for primary hand, 1 for secondary /* 26 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 30 */ }; @@ -1827,6 +1823,20 @@ struct MoveItem_Struct /*0028*/ }; +struct MultiMoveItemSub_Struct +{ +/*0000*/ InventorySlot_Struct from_slot; +/*0012*/ InventorySlot_Struct to_slot; +/*0024*/ uint32 number_in_stack; +/*0028*/ uint8 unknown[8]; +}; + +struct MultiMoveItem_Struct +{ +/*0000*/ uint32 count; +/*0004*/ MultiMoveItemSub_Struct moves[0]; +}; + // // from_slot/to_slot // -1 - destroy @@ -3591,21 +3601,6 @@ struct GuildSetRank_Struct /*80*/ }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3632,20 +3627,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; @@ -5089,6 +5085,23 @@ struct CrystalCountUpdate_Struct /*012*/ uint32 CareerEbonCrystals; }; +struct SayLinkBodyFrame_Struct { +/*000*/ char ActionID[1]; +/*001*/ char ItemID[5]; +/*006*/ char Augment1[5]; +/*011*/ char Augment2[5]; +/*016*/ char Augment3[5]; +/*021*/ char Augment4[5]; +/*026*/ char Augment5[5]; +/*031*/ char Augment6[5]; +/*036*/ char IsEvolving[1]; +/*037*/ char EvolveGroup[4]; +/*041*/ char EvolveLevel[2]; +/*043*/ char OrnamentIcon[5]; +/*048*/ char Hash[8]; +/*056*/ +}; + }; /*structs*/ }; /*RoF2*/ diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 8de4fb9ab..08e3647be 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -408,7 +408,7 @@ struct Spawn_Struct /*0000*/ //uint8 nullterm1; // hack to null terminate name /*0064*/ uint32 spawnId; /*0068*/ uint8 level; -/*0069*/ float unknown1; +/*0069*/ float bounding_radius; // used in melee, overrides calc /*0073*/ uint8 NPC; // 0=player,1=npc,2=pc corpse,3=npc corpse Spawn_Struct_Bitfields Bitfields; /*0000*/ uint8 otherData; // & 4 - has title, & 8 - has suffix, & 1 - it's a chest or untargetable @@ -1450,17 +1450,17 @@ struct Action_Struct { /*00*/ uint16 target; // id of target /*02*/ uint16 source; // id of caster -/*04*/ uint16 level; // level of caster - Seen 0 -/*06*/ uint32 unknown06; +/*04*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*06*/ uint32 unknown06; // OSX dump says base_damage, was used for bard mod too, this is 0'd :( /*10*/ float instrument_mod; -/*14*/ uint32 bard_focus_id; // seen 0 -/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again -/*22*/ uint32 unknown22; -/*26*/ uint8 type; -/*27*/ uint32 damage; -/*31*/ uint16 unknown31; +/*14*/ float force; +/*18*/ float hit_heading; +/*22*/ float hit_pitch; +/*26*/ uint8 type; // 231 (0xE7) for spells, skill +/*27*/ uint32 damage; // OSX says min_damage +/*31*/ uint16 unknown31; // OSX says tohit /*33*/ uint32 spell; // spell id being cast -/*37*/ uint8 level2; // level of caster again? Or maybe the castee +/*37*/ uint8 spell_level; // level of caster again? Or maybe the castee /*38*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? /*39*/ }; @@ -1472,25 +1472,21 @@ struct ActionAlt_Struct { /*00*/ uint16 target; // id of target /*02*/ uint16 source; // id of caster -/*04*/ uint16 level; // level of caster - Seen 0 -/*06*/ uint32 unknown06; +/*04*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*06*/ uint32 unknown06; // OSX dump says base_damage, was used for bard mod too, this is 0'd :( /*10*/ float instrument_mod; -/*14*/ uint32 bard_focus_id; // seen 0 -/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again -/*22*/ uint32 unknown22; -/*26*/ uint8 type; -/*27*/ uint32 damage; -/*31*/ uint16 unknown31; +/*14*/ float force; +/*18*/ float hit_heading; +/*22*/ float hit_pitch; +/*26*/ uint8 type; // 231 (0xE7) for spells, skill +/*27*/ uint32 damage; // OSX says min_damage +/*31*/ uint16 unknown31; // OSX says tohit /*33*/ uint32 spell; // spell id being cast -/*37*/ uint8 level2; // level of caster again? Or maybe the castee +/*37*/ uint8 spell_level; // level of caster again? Or maybe the castee /*38*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? -/*39*/ uint32 unknown39; // New field to Underfoot - Seen 14 -/*43*/ uint8 unknown43; // New field to Underfoot - Seen 0 -/*44*/ uint8 unknown44; // New field to Underfoot - Seen 17 -/*45*/ uint8 unknown45; // New field to Underfoot - Seen 0 -/*46*/ int32 unknown46; // New field to Underfoot - Seen -1 -/*50*/ uint32 unknown50; // New field to Underfoot - Seen 0 -/*54*/ uint16 unknown54; // New field to Underfoot - Seen 0 +/*39*/ uint8 spell_gem; +/*40*/ InventorySlot_Struct slot; +/*52*/ uint32 item_cast_type; // ItemSpellTypes enum from MQ2 /*56*/ }; @@ -1505,9 +1501,9 @@ struct CombatDamage_Struct /* 05 */ uint32 spellid; /* 09 */ int32 damage; /* 13 */ float force; // cd cc cc 3d -/* 17 */ float meleepush_xy; // see above notes in Action_Struct -/* 21 */ float meleepush_z; -/* 25 */ uint8 unknown25; // was [9] +/* 17 */ float hit_heading; // see above notes in Action_Struct +/* 21 */ float hit_pitch; +/* 25 */ uint8 secondary; // 0 for primary hand, 1 for secondary /* 26 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 30 */ }; @@ -3545,21 +3541,6 @@ struct GuildSetRank_Struct /*80*/ }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3586,20 +3567,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; @@ -5020,6 +5002,23 @@ struct MercenaryMerchantRequest_Struct { struct MercenaryMerchantResponse_Struct { /*0000*/ uint32 ResponseType; /*0004*/ +}; + +struct SayLinkBodyFrame_Struct { +/*000*/ char ActionID[1]; +/*001*/ char ItemID[5]; +/*006*/ char Augment1[5]; +/*011*/ char Augment2[5]; +/*016*/ char Augment3[5]; +/*021*/ char Augment4[5]; +/*026*/ char Augment5[5]; +/*031*/ char Augment6[5]; +/*036*/ char IsEvolving[1]; +/*037*/ char EvolveGroup[4]; +/*041*/ char EvolveLevel[1]; +/*042*/ char OrnamentIcon[5]; +/*047*/ char Hash[8]; +/*055*/ }; }; /*structs*/ diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index a77feedbc..560151bfa 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -53,11 +53,11 @@ namespace SoD static inline uint32 SoDToServerSlot(uint32 sodSlot); static inline uint32 SoDToServerCorpseSlot(uint32 sodCorpseSlot); - // server to client text link converter - static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink); + // server to client say link converter + static inline void ServerToSoDSayLink(std::string& sodSayLink, const std::string& serverSayLink); - // client to server text link converter - static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink); + // client to server say link converter + static inline void SoDToServerSayLink(std::string& serverSayLink, const std::string& sodSayLink); static inline CastingSlot ServerToSoDCastingSlot(EQEmu::CastingSlot slot); static inline EQEmu::CastingSlot SoDToServerCastingSlot(CastingSlot slot); @@ -161,15 +161,14 @@ namespace SoD OUT(source); OUT(level); OUT(instrument_mod); - eq->sequence = emu->sequence; + OUT(force); + OUT(hit_heading); + OUT(hit_pitch); OUT(type); //OUT(damage); OUT(spell); - eq->level2 = emu->level; - OUT(buff_unknown); // if this is 4, a buff icon is made - //eq->unknown0036 = -1; - //eq->unknown0040 = -1; - //eq->unknown0044 = -1; + OUT(spell_level); + OUT(effect_flag); // if this is 4, a buff icon is made FINISH_ENCODE(); } @@ -346,7 +345,7 @@ namespace SoD std::string old_message = emu->message; std::string new_message; - ServerToSoDTextLink(new_message, old_message); + ServerToSoDSayLink(new_message, old_message); in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; @@ -458,8 +457,8 @@ namespace SoD OUT(spellid); OUT(damage); OUT(force); - OUT(meleepush_xy); - OUT(meleepush_z); + OUT(hit_heading); + OUT(hit_pitch); OUT(special); FINISH_ENCODE(); @@ -625,7 +624,7 @@ namespace SoD std::string old_message = emu->message; std::string new_message; - ServerToSoDTextLink(new_message, old_message); + ServerToSoDSayLink(new_message, old_message); //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) // new_message = new_message.substr(0, 512); @@ -677,7 +676,7 @@ namespace SoD for (int i = 0; i < 9; ++i) { if (old_message_array[i].length() == 0) { break; } - ServerToSoDTextLink(new_message_array[i], old_message_array[i]); + ServerToSoDSayLink(new_message_array[i], old_message_array[i]); new_message_size += new_message_array[i].length() + 1; } @@ -2156,7 +2155,7 @@ namespace SoD std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; - ServerToSoDTextLink(new_message, old_message); + ServerToSoDSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; in->size = strlen(emu->sayer) + new_message.length() + 25; @@ -2252,7 +2251,7 @@ namespace SoD std::string old_message = InBuffer; // start 'Reward' as string std::string new_message; - ServerToSoDTextLink(new_message, old_message); + ServerToSoDSayLink(new_message, old_message); in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ @@ -2933,25 +2932,6 @@ namespace SoD FINISH_DIRECT_DECODE(); } - DECODE(OP_Bug) - { - DECODE_LENGTH_EXACT(structs::BugStruct); - SETUP_DIRECT_DECODE(BugStruct, structs::BugStruct); - - strn0cpy(emu->chartype, eq->chartype, sizeof(emu->chartype)); - strn0cpy(emu->name, eq->name, sizeof(emu->name)); - strn0cpy(emu->ui, eq->ui, sizeof(emu->ui)); - IN(x); - IN(y); - IN(z); - IN(heading); - strn0cpy(emu->target_name, eq->target_name, sizeof(emu->target_name)); - strn0cpy(emu->bug, eq->bug, sizeof(emu->bug)); - strn0cpy(emu->system_info, eq->system_info, sizeof(emu->system_info)); - - FINISH_DIRECT_DECODE(); - } - DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); @@ -2972,7 +2952,7 @@ namespace SoD std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)]; std::string new_message; - SoDToServerTextLink(new_message, old_message); + SoDToServerSayLink(new_message, old_message); __packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; __packet->pBuffer = new unsigned char[__packet->size]; @@ -3086,7 +3066,7 @@ namespace SoD std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset std::string new_message; - SoDToServerTextLink(new_message, old_message); + SoDToServerSayLink(new_message, old_message); __packet->size = sizeof(Emote_Struct); __packet->pBuffer = new unsigned char[__packet->size]; @@ -3936,19 +3916,19 @@ namespace SoD return (sodCorpseSlot - 1); } - static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink) + static inline void ServerToSoDSayLink(std::string& sodSayLink, const std::string& serverSayLink) { - if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { - sodTextLink = serverTextLink; + if ((constants::SayLinkBodySize == EQEmu::constants::SayLinkBodySize) || (serverSayLink.find('\x12') == std::string::npos)) { + sodSayLink = serverSayLink; return; } - auto segments = SplitString(serverTextLink, '\x12'); + auto segments = SplitString(serverSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { - sodTextLink.append(segments[segment_iter]); + if (segments[segment_iter].length() <= EQEmu::constants::SayLinkBodySize) { + sodSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -3958,37 +3938,37 @@ namespace SoD // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // Diff: ^^^^^ ^ - sodTextLink.push_back('\x12'); - sodTextLink.append(segments[segment_iter].substr(0, 31)); - sodTextLink.append(segments[segment_iter].substr(36, 5)); + sodSayLink.push_back('\x12'); + sodSayLink.append(segments[segment_iter].substr(0, 31)); + sodSayLink.append(segments[segment_iter].substr(36, 5)); if (segments[segment_iter][41] == '0') - sodTextLink.push_back(segments[segment_iter][42]); + sodSayLink.push_back(segments[segment_iter][42]); else - sodTextLink.push_back('F'); + sodSayLink.push_back('F'); - sodTextLink.append(segments[segment_iter].substr(43)); - sodTextLink.push_back('\x12'); + sodSayLink.append(segments[segment_iter].substr(43)); + sodSayLink.push_back('\x12'); } else { - sodTextLink.append(segments[segment_iter]); + sodSayLink.append(segments[segment_iter]); } } } - static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink) + static inline void SoDToServerSayLink(std::string& serverSayLink, const std::string& sodSayLink) { - if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (sodTextLink.find('\x12') == std::string::npos)) { - serverTextLink = sodTextLink; + if ((EQEmu::constants::SayLinkBodySize == constants::SayLinkBodySize) || (sodSayLink.find('\x12') == std::string::npos)) { + serverSayLink = sodSayLink; return; } - auto segments = SplitString(sodTextLink, '\x12'); + auto segments = SplitString(sodSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { if (segments[segment_iter].length() <= constants::SayLinkBodySize) { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -3998,16 +3978,16 @@ namespace SoD // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ - serverTextLink.push_back('\x12'); - serverTextLink.append(segments[segment_iter].substr(0, 31)); - serverTextLink.append("00000"); - serverTextLink.append(segments[segment_iter].substr(31, 5)); - serverTextLink.push_back('0'); - serverTextLink.append(segments[segment_iter].substr(36)); - serverTextLink.push_back('\x12'); + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 31)); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(31, 5)); + serverSayLink.push_back('0'); + serverSayLink.append(segments[segment_iter].substr(36)); + serverSayLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); } } } diff --git a/common/patches/sod_ops.h b/common/patches/sod_ops.h index 90c28b2eb..7c1109499 100644 --- a/common/patches/sod_ops.h +++ b/common/patches/sod_ops.h @@ -104,7 +104,6 @@ D(OP_AugmentInfo) D(OP_AugmentItem) D(OP_BazaarSearch) D(OP_Buff) -D(OP_Bug) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 88ccd7788..6b5c2f72c 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -292,7 +292,7 @@ struct Spawn_Struct /*0000*/ //uint8 nullterm1; // hack to null terminate name /*0064*/ uint32 spawnId; /*0068*/ uint8 level; -/*0069*/ float unknown1; +/*0069*/ float bounding_radius; // used in melee, overrides calc /*0073*/ uint8 NPC; // 0=player,1=npc,2=pc corpse,3=npc corpse Spawn_Struct_Bitfields Bitfields; /*0000*/ uint8 otherData; // & 4 - has title, & 8 - has suffix, & 1 - it's a chest or untargetable @@ -924,7 +924,7 @@ struct PlayerProfile_Struct /*06488*/ uint32 silver_cursor; // Silver Pieces on cursor /*06492*/ uint32 copper_cursor; // Copper Pieces on cursor /*06496*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer -/*06896*/ uint32 InnateSkills[MAX_PP_SKILL]; +/*06896*/ uint32 InnateSkills[MAX_PP_INNATE_SKILL]; /*06996*/ uint8 unknown04760[36]; /*07032*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3) /*07036*/ uint32 thirst_level; // Drink (ticks till next drink) @@ -1215,20 +1215,18 @@ struct Action_Struct { /* 00 */ uint16 target; // id of target /* 02 */ uint16 source; // id of caster - /* 04 */ uint16 level; // level of caster - /* 06 */ uint16 instrument_mod; // seems to be fixed to 0x0A - /* 08 */ uint32 unknown08; - /* 12 */ uint16 unknown16; -// some kind of sequence that's the same in both actions -// as well as the combat damage, to tie em together? - /* 14 */ float sequence; // was uint32 - /* 18 */ uint32 unknown18; - /* 22 */ uint8 type; // 231 (0xE7) for spells - /* 23 */ uint32 unknown23; + /* 04 */ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level + /* 06 */ uint32 instrument_mod; // OSX dump says base damage, spells use it for bard song (different from newer clients) + /* 10 */ float force; + /* 14 */ float hit_heading; + /* 18 */ float hit_pitch; + /* 22 */ uint8 type; // 231 (0xE7) for spells, skill + /* 23 */ uint16 unknown23; // OSX says min_damage + /* 25 */ uint16 unknown25; // OSX says tohit /* 27 */ uint16 spell; // spell id being cast - /* 29 */ uint8 level2; // level of caster again? Or maybe the castee + /* 29 */ uint8 spell_level; // level of caster again? Or maybe the castee // this field seems to be some sort of success flag, if it's 4 - /* 30 */ uint8 buff_unknown; // if this is 4, a buff icon is made + /* 30 */ uint8 effect_flag; // if this is 4, a buff icon is made /* 31 */ }; @@ -1237,26 +1235,23 @@ struct Action_Struct // has to do with buff blocking?? struct ActionAlt_Struct // ActionAlt_Struct - Size: 56 bytes { -/*0000*/ uint16 target; // Target ID -/*0002*/ uint16 source; // SourceID -/*0004*/ uint16 level; // level of caster -/*0006*/ uint16 instrument_mod; // seems to be fixed to 0x0A -/*0008*/ uint32 unknown08; -/*0012*/ uint16 unknown16; -/*0014*/ uint32 sequence; -/*0018*/ uint32 unknown18; -/*0022*/ uint8 type; // Casts, Falls, Bashes, etc... -/*0023*/ uint32 damage; // Amount of Damage -/*0027*/ uint16 spell; // SpellID -/*0029*/ uint8 unknown29; -/*0030*/ uint8 buff_unknown; // if this is 4, a buff icon is made -/*0031*/ uint32 unknown0031; // seen 00 00 00 00 -/*0035*/ uint8 unknown0035; // seen 00 -/*0036*/ uint32 unknown0036; // seen ff ff ff ff -/*0040*/ uint32 unknown0040; // seen ff ff ff ff -/*0044*/ uint32 unknown0044; // seen ff ff ff ff -/*0048*/ uint32 unknown0048; // seen 00 00 00 00 -/*0052*/ uint32 unknown0052; // seen 00 00 00 00 +/*0000*/ uint16 target; // id of target +/*0002*/ uint16 source; // id of caster +/*0004*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*0006*/ uint32 instrument_mod; // OSX dump says base damage, spells use it for bard song (different from newer clients) +/*0010*/ float force; +/*0014*/ float hit_heading; +/*0018*/ float hit_pitch; +/*0022*/ uint8 type; // 231 (0xE7) for spells, skill +/*0023*/ uint16 unknown23; // OSX says min_damage +/*0025*/ uint16 unknown25; // OSX says tohit +/*0027*/ uint16 spell; // spell id being cast +/*0029*/ uint8 spell_level; // level of caster again? Or maybe the castee +// this field seems to be some sort of success flag, if it's 4 +/*0030*/ uint8 effect_flag; // if this is 4, a buff icon is made +/*0031*/ uint8 spell_slot; +/*0032*/ uint32 slot[5]; +/*0052*/ uint32 item_cast_type; // ItemSpellTypes enum from MQ2 /*0056*/ }; @@ -1271,9 +1266,9 @@ struct CombatDamage_Struct /* 05 */ uint16 spellid; /* 07 */ int32 damage; /* 11 */ float force; // cd cc cc 3d -/* 15 */ float meleepush_xy; // see above notes in Action_Struct -/* 19 */ float meleepush_z; -/* 23 */ uint8 unknown23; // was [9] +/* 15 */ float hit_heading; // see above notes in Action_Struct +/* 19 */ float hit_pitch; +/* 23 */ uint8 secondary; // 0 for primary hand, 1 for secondary /* 24 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 28 */ }; @@ -3008,24 +3003,6 @@ struct GuildMakeLeader{ char target[64]; }; -struct BugStruct{ -/*0000*/ uint32 type1; //seems to be just a different way of seeing type; seems to be ordered completely differently -/*0004*/ char chartype[64]; -/*0068*/ char name[96]; -/*0164*/ char ui[128]; -/*0292*/ float x; -/*0296*/ float y; -/*0300*/ float z; -/*0304*/ float heading; -/*0308*/ uint32 unknown304; -/*0312*/ char unknown308[160]; -/*0472*/ char target_name[64]; -/*0536*/ uint32 type; -/*0540*/ char unknown536[2052]; -/*2588*/ char bug[2048]; -/*4636*/ char unknown4632[6]; -/*4642*/ char system_info[4094]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3052,20 +3029,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; @@ -4402,6 +4380,22 @@ struct MercenaryAssign_Struct { /*0004*/ uint32 MercUnk01; // /*0008*/ uint32 MercUnk02; // /*0012*/ +}; + +struct SayLinkBodyFrame_Struct { +/*000*/ char ActionID[1]; +/*001*/ char ItemID[5]; +/*006*/ char Augment1[5]; +/*011*/ char Augment2[5]; +/*016*/ char Augment3[5]; +/*021*/ char Augment4[5]; +/*026*/ char Augment5[5]; +/*031*/ char IsEvolving[1]; +/*032*/ char EvolveGroup[4]; +/*036*/ char EvolveLevel[1]; +/*037*/ char OrnamentIcon[5]; +/*042*/ char Hash[8]; +/*050*/ }; }; /*structs*/ diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 9df6ca1df..c16bed086 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -53,11 +53,11 @@ namespace SoF static inline uint32 SoFToServerSlot(uint32 sofSlot); static inline uint32 SoFToServerCorpseSlot(uint32 sofCorpseSlot); - // server to client text link converter - static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink); + // server to client say link converter + static inline void ServerToSoFSayLink(std::string& sofSayLink, const std::string& serverSayLink); - // client to server text link converter - static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink); + // client to server say link converter + static inline void SoFToServerSayLink(std::string& serverSayLink, const std::string& sofSayLink); static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot); static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 itemlocation); @@ -161,15 +161,14 @@ namespace SoF OUT(source); OUT(level); OUT(instrument_mod); - eq->sequence = emu->sequence; + OUT(force); + OUT(hit_heading); + OUT(hit_pitch); OUT(type); //OUT(damage); OUT(spell); - eq->level2 = emu->level; - OUT(buff_unknown); // if this is 4, a buff icon is made - //eq->unknown0036 = -1; - //eq->unknown0040 = -1; - //eq->unknown0044 = -1; + OUT(spell_level); + OUT(effect_flag); // if this is 4, a buff icon is made FINISH_ENCODE(); } @@ -328,7 +327,7 @@ namespace SoF std::string old_message = emu->message; std::string new_message; - ServerToSoFTextLink(new_message, old_message); + ServerToSoFSayLink(new_message, old_message); in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; @@ -440,8 +439,8 @@ namespace SoF OUT(spellid); OUT(damage); OUT(force); - OUT(meleepush_xy); - OUT(meleepush_z); + OUT(hit_heading); + OUT(hit_pitch); FINISH_ENCODE(); } @@ -613,7 +612,7 @@ namespace SoF std::string old_message = emu->message; std::string new_message; - ServerToSoFTextLink(new_message, old_message); + ServerToSoFSayLink(new_message, old_message); //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) // new_message = new_message.substr(0, 512); @@ -665,7 +664,7 @@ namespace SoF for (int i = 0; i < 9; ++i) { if (old_message_array[i].length() == 0) { break; } - ServerToSoFTextLink(new_message_array[i], old_message_array[i]); + ServerToSoFSayLink(new_message_array[i], old_message_array[i]); new_message_size += new_message_array[i].length() + 1; } @@ -1814,7 +1813,7 @@ namespace SoF std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; - ServerToSoFTextLink(new_message, old_message); + ServerToSoFSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; in->size = strlen(emu->sayer) + new_message.length() + 25; @@ -1882,7 +1881,7 @@ namespace SoF std::string old_message = InBuffer; // start 'Reward' as string std::string new_message; - ServerToSoFTextLink(new_message, old_message); + ServerToSoFSayLink(new_message, old_message); in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ @@ -2385,6 +2384,17 @@ namespace SoF FINISH_DIRECT_DECODE(); } + DECODE(OP_Bug) + { + DECODE_LENGTH_EXACT(structs::BugReport_Struct); + SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct); + + emu->category_id = EQEmu::bug::CategoryNameToCategoryID(eq->category_name); + memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct)); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); @@ -2404,7 +2414,7 @@ namespace SoF std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)]; std::string new_message; - SoFToServerTextLink(new_message, old_message); + SoFToServerSayLink(new_message, old_message); __packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; __packet->pBuffer = new unsigned char[__packet->size]; @@ -2518,7 +2528,7 @@ namespace SoF std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset std::string new_message; - SoFToServerTextLink(new_message, old_message); + SoFToServerSayLink(new_message, old_message); __packet->size = sizeof(Emote_Struct); __packet->pBuffer = new unsigned char[__packet->size]; @@ -3305,19 +3315,19 @@ namespace SoF return (sofCorpseSlot - 1); } - static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink) + static inline void ServerToSoFSayLink(std::string& sofSayLink, const std::string& serverSayLink) { - if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { - sofTextLink = serverTextLink; + if ((constants::SayLinkBodySize == EQEmu::constants::SayLinkBodySize) || (serverSayLink.find('\x12') == std::string::npos)) { + sofSayLink = serverSayLink; return; } - auto segments = SplitString(serverTextLink, '\x12'); + auto segments = SplitString(serverSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { - sofTextLink.append(segments[segment_iter]); + if (segments[segment_iter].length() <= EQEmu::constants::SayLinkBodySize) { + sofSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -3327,37 +3337,37 @@ namespace SoF // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // Diff: ^^^^^ ^ - sofTextLink.push_back('\x12'); - sofTextLink.append(segments[segment_iter].substr(0, 31)); - sofTextLink.append(segments[segment_iter].substr(36, 5)); + sofSayLink.push_back('\x12'); + sofSayLink.append(segments[segment_iter].substr(0, 31)); + sofSayLink.append(segments[segment_iter].substr(36, 5)); if (segments[segment_iter][41] == '0') - sofTextLink.push_back(segments[segment_iter][42]); + sofSayLink.push_back(segments[segment_iter][42]); else - sofTextLink.push_back('F'); + sofSayLink.push_back('F'); - sofTextLink.append(segments[segment_iter].substr(43)); - sofTextLink.push_back('\x12'); + sofSayLink.append(segments[segment_iter].substr(43)); + sofSayLink.push_back('\x12'); } else { - sofTextLink.append(segments[segment_iter]); + sofSayLink.append(segments[segment_iter]); } } } - static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink) + static inline void SoFToServerSayLink(std::string& serverSayLink, const std::string& sofSayLink) { - if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (sofTextLink.find('\x12') == std::string::npos)) { - serverTextLink = sofTextLink; + if ((EQEmu::constants::SayLinkBodySize == constants::SayLinkBodySize) || (sofSayLink.find('\x12') == std::string::npos)) { + serverSayLink = sofSayLink; return; } - auto segments = SplitString(sofTextLink, '\x12'); + auto segments = SplitString(sofSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { if (segments[segment_iter].length() <= constants::SayLinkBodySize) { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -3367,16 +3377,16 @@ namespace SoF // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ - serverTextLink.push_back('\x12'); - serverTextLink.append(segments[segment_iter].substr(0, 31)); - serverTextLink.append("00000"); - serverTextLink.append(segments[segment_iter].substr(31, 5)); - serverTextLink.push_back('0'); - serverTextLink.append(segments[segment_iter].substr(36)); - serverTextLink.push_back('\x12'); + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 31)); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(31, 5)); + serverSayLink.push_back('0'); + serverSayLink.append(segments[segment_iter].substr(36)); + serverSayLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); } } } diff --git a/common/patches/sof_ops.h b/common/patches/sof_ops.h index 180857388..c4e42d8d4 100644 --- a/common/patches/sof_ops.h +++ b/common/patches/sof_ops.h @@ -95,6 +95,7 @@ D(OP_ApplyPoison) D(OP_AugmentInfo) D(OP_AugmentItem) D(OP_Buff) +D(OP_Bug) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 2a1eab3f0..29272a7a6 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -52,6 +52,25 @@ struct EnterWorld_Struct { struct WorldObjectsSent_Struct { }; +// yep, even SoF had a version of the new inventory system, used by OP_MoveMultipleItems +struct InventorySlot_Struct +{ +/*000*/ int32 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Trade = 3, World = 4, Limbo = 5 +/*004*/ int32 Slot; +/*008*/ int32 SubIndex; +/*012*/ int32 AugIndex; +/*016*/ int32 Unknown01; +}; + +// unsure if they have a version of this, completeness though +struct TypelessInventorySlot_Struct +{ +/*000*/ int32 Slot; +/*004*/ int32 SubIndex; +/*008*/ int32 AugIndex; +/*012*/ int32 Unknown01; +}; + /* Name Approval Struct */ /* Len: */ /* Opcode: 0x8B20*/ @@ -307,7 +326,8 @@ union /*0725*/ uint8 targetable; // 1 = Targetable 0 = Not Targetable (is_npc?) /*0726*/ uint8 unknown0726[4]; /*0730*/ uint8 NPC; // 0=player,1=npc,2=pc corpse,3=npc corpse -/*0731*/ uint8 unknown0731[11]; +/*0731*/ float bounding_radius; // used in melee, overrides calc +/*0735*/ uint8 unknown0731[7]; /*0742*/ uint8 targetable_with_hotkey; /*0743*/ signed padding00:12; // ***Placeholder signed x:19; // x coord @@ -1195,20 +1215,18 @@ struct Action_Struct { /* 00 */ uint16 target; // id of target /* 02 */ uint16 source; // id of caster - /* 04 */ uint16 level; // level of caster - /* 06 */ uint16 instrument_mod; // seems to be fixed to 0x0A - /* 08 */ uint32 unknown08; - /* 12 */ uint16 unknown16; -// some kind of sequence that's the same in both actions -// as well as the combat damage, to tie em together? - /* 14 */ float sequence; // was uint32 - /* 18 */ uint32 unknown18; - /* 22 */ uint8 type; // 231 (0xE7) for spells - /* 23 */ uint32 unknown23; + /* 04 */ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level + /* 06 */ uint32 instrument_mod; // OSX dump says base damage, spells use it for bard song (different from newer clients) + /* 10 */ float force; + /* 14 */ float hit_heading; + /* 18 */ float hit_pitch; + /* 22 */ uint8 type; // 231 (0xE7) for spells, skill + /* 23 */ uint16 unknown23; // OSX says min_damage + /* 25 */ uint16 unknown25; // OSX says tohit /* 27 */ uint16 spell; // spell id being cast - /* 29 */ uint8 level2; // level of caster again? Or maybe the castee + /* 29 */ uint8 spell_level; // level of caster again? Or maybe the castee // this field seems to be some sort of success flag, if it's 4 - /* 30 */ uint8 buff_unknown; // if this is 4, a buff icon is made + /* 30 */ uint8 effect_flag; // if this is 4, a buff icon is made /* 31 */ }; @@ -1217,26 +1235,23 @@ struct Action_Struct // has to do with buff blocking?? struct ActionAlt_Struct // ActionAlt_Struct - Size: 56 bytes { -/*0000*/ uint16 target; // Target ID -/*0002*/ uint16 source; // SourceID -/*0004*/ uint16 level; // level of caster -/*0006*/ uint16 instrument_mod; // seems to be fixed to 0x0A -/*0008*/ uint32 unknown08; -/*0012*/ uint16 unknown16; -/*0014*/ uint32 sequence; -/*0018*/ uint32 unknown18; -/*0022*/ uint8 type; // Casts, Falls, Bashes, etc... -/*0023*/ uint32 damage; // Amount of Damage -/*0027*/ uint16 spell; // SpellID -/*0029*/ uint8 unknown29; -/*0030*/ uint8 buff_unknown; // if this is 4, a buff icon is made -/*0031*/ uint32 unknown0031; // seen 00 00 00 00 -/*0035*/ uint8 unknown0035; // seen 00 -/*0036*/ uint32 unknown0036; // seen ff ff ff ff -/*0040*/ uint32 unknown0040; // seen ff ff ff ff -/*0044*/ uint32 unknown0044; // seen ff ff ff ff -/*0048*/ uint32 unknown0048; // seen 00 00 00 00 -/*0052*/ uint32 unknown0052; // seen 00 00 00 00 +/*0000*/ uint16 target; // id of target +/*0002*/ uint16 source; // id of caster +/*0004*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*0006*/ uint32 instrument_mod; // OSX dump says base damage, spells use it for bard song (different from newer clients) +/*0010*/ float force; +/*0014*/ float hit_heading; +/*0018*/ float hit_pitch; +/*0022*/ uint8 type; // 231 (0xE7) for spells, skill +/*0023*/ uint16 unknown23; // OSX says min_damage +/*0025*/ uint16 unknown25; // OSX says tohit +/*0027*/ uint16 spell; // spell id being cast +/*0029*/ uint8 spell_level; // level of caster again? Or maybe the castee +// this field seems to be some sort of success flag, if it's 4 +/*0030*/ uint8 effect_flag; // if this is 4, a buff icon is made +/*0031*/ uint8 spell_slot; +/*0032*/ uint32 slot[5]; +/*0052*/ uint32 item_cast_type; // ItemSpellTypes enum from MQ2 /*0056*/ }; @@ -1251,9 +1266,10 @@ struct CombatDamage_Struct /* 05 */ uint16 spellid; /* 07 */ int32 damage; /* 11 */ float force; // cd cc cc 3d -/* 15 */ float meleepush_xy; // see above notes in Action_Struct -/* 19 */ float meleepush_z; -/* 23 */ uint8 unknown23[5]; // was [9] this appears unrelated to the stuff the other clients do here? +/* 15 */ float hit_heading; // see above notes in Action_Struct +/* 19 */ float hit_pitch; +/* 23 */ uint8 secondary; // 0 for primary hand, 1 for secondary +/* 24 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage, Report function doesn't seem to check this :P /* 28 */ }; @@ -1557,6 +1573,19 @@ struct MoveItem_Struct /*0012*/ }; +struct MultiMoveItemSub_Struct +{ +/*0000*/ InventorySlot_Struct from_slot; +/*0020*/ uint32 number_in_stack; // so the amount we are moving from the source +/*0024*/ InventorySlot_Struct to_slot; +}; + +struct MultiMoveItem_Struct +{ +/*0000*/ uint32 count; +/*0004*/ MultiMoveItemSub_Struct moves[0]; +}; + // // from_slot/to_slot // -1 - destroy @@ -2874,23 +2903,31 @@ struct GuildMakeLeader{ char target[64]; }; +struct BugReport_Struct { +/*0000*/ char category_name[64]; +/*0064*/ char character_name[64]; +/*0128*/ char unused_0128[32]; +/*0160*/ char ui_path[128]; +/*0288*/ float pos_x; +/*0292*/ float pos_y; +/*0296*/ float pos_z; +/*0300*/ uint32 heading; +/*0304*/ uint32 unused_0304; +/*0308*/ uint32 time_played; +/*0312*/ char padding_0312[8]; +/*0320*/ uint32 target_id; +/*0324*/ char padding_0324[140]; +/*0464*/ uint32 unknown_0464; // seems to always be '0' +/*0468*/ char target_name[64]; +/*0532*/ uint32 optional_info_mask; - -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; +// this looks like a butchered 8k buffer with 2 trailing dword fields +/*0536*/ char unused_0536[2052]; +/*2588*/ char bug_report[2050]; +/*4638*/ char system_info[4098]; +/*8736*/ }; + struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -2917,20 +2954,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; @@ -4114,6 +4152,22 @@ struct AltCurrencySellItem_Struct { /*004*/ uint32 slot_id; /*006*/ uint32 charges; /*010*/ uint32 cost; +}; + +struct SayLinkBodyFrame_Struct { +/*000*/ char ActionID[1]; +/*001*/ char ItemID[5]; +/*006*/ char Augment1[5]; +/*011*/ char Augment2[5]; +/*016*/ char Augment3[5]; +/*021*/ char Augment4[5]; +/*026*/ char Augment5[5]; +/*031*/ char IsEvolving[1]; +/*032*/ char EvolveGroup[4]; +/*036*/ char EvolveLevel[1]; +/*037*/ char OrnamentIcon[5]; +/*042*/ char Hash[8]; +/*050*/ }; }; /*structs*/ diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 45f267223..bf3c3d359 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -52,11 +52,11 @@ namespace Titanium static inline uint32 TitaniumToServerSlot(int16 titaniumSlot); static inline uint32 TitaniumToServerCorpseSlot(int16 titaniumCorpseSlot); - // server to client text link converter - static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink); + // server to client say link converter + static inline void ServerToTitaniumSayLink(std::string& titaniumSayLink, const std::string& serverSayLink); - // client to server text link converter - static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink); + // client to server say link converter + static inline void TitaniumToServerSayLink(std::string& serverSayLink, const std::string& titaniumSayLink); static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot); static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 itemlocation); @@ -164,11 +164,14 @@ namespace Titanium OUT(source); OUT(level); OUT(instrument_mod); - OUT(sequence); + OUT(force); + OUT(hit_heading); + OUT(hit_pitch); OUT(type); //OUT(damage); OUT(spell); - OUT(buff_unknown); // if this is 4, a buff icon is made + OUT(spell_level); + OUT(effect_flag); // if this is 4, a buff icon is made FINISH_ENCODE(); } @@ -290,7 +293,7 @@ namespace Titanium std::string old_message = emu->message; std::string new_message; - ServerToTitaniumTextLink(new_message, old_message); + ServerToTitaniumSayLink(new_message, old_message); in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; @@ -358,8 +361,8 @@ namespace Titanium OUT(spellid); OUT(damage); OUT(force); - OUT(meleepush_xy); - OUT(meleepush_z); + OUT(hit_heading); + OUT(hit_pitch); FINISH_ENCODE(); } @@ -532,7 +535,7 @@ namespace Titanium std::string old_message = emu->message; std::string new_message; - ServerToTitaniumTextLink(new_message, old_message); + ServerToTitaniumSayLink(new_message, old_message); //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) // new_message = new_message.substr(0, 512); @@ -574,7 +577,7 @@ namespace Titanium for (int i = 0; i < 9; ++i) { if (old_message_array[i].length() == 0) { break; } - ServerToTitaniumTextLink(new_message_array[i], old_message_array[i]); + ServerToTitaniumSayLink(new_message_array[i], old_message_array[i]); new_message_size += new_message_array[i].length() + 1; } @@ -1402,7 +1405,7 @@ namespace Titanium std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; - ServerToTitaniumTextLink(new_message, old_message); + ServerToTitaniumSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; in->size = strlen(emu->sayer) + new_message.length() + 25; @@ -1458,7 +1461,7 @@ namespace Titanium std::string old_message = InBuffer; // start 'Reward' as string std::string new_message; - ServerToTitaniumTextLink(new_message, old_message); + ServerToTitaniumSayLink(new_message, old_message); in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct) + sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct) + @@ -1789,6 +1792,17 @@ namespace Titanium FINISH_DIRECT_DECODE(); } + DECODE(OP_Bug) + { + DECODE_LENGTH_EXACT(structs::BugReport_Struct); + SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct); + + emu->category_id = EQEmu::bug::CategoryNameToCategoryID(eq->category_name); + memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct)); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); @@ -1808,7 +1822,7 @@ namespace Titanium std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)]; std::string new_message; - TitaniumToServerTextLink(new_message, old_message); + TitaniumToServerSayLink(new_message, old_message); __packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; __packet->pBuffer = new unsigned char[__packet->size]; @@ -1880,7 +1894,7 @@ namespace Titanium std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset std::string new_message; - TitaniumToServerTextLink(new_message, old_message); + TitaniumToServerSayLink(new_message, old_message); __packet->size = sizeof(Emote_Struct); __packet->pBuffer = new unsigned char[__packet->size]; @@ -2474,19 +2488,19 @@ namespace Titanium return titaniumCorpseSlot; } - static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink) + static inline void ServerToTitaniumSayLink(std::string& titaniumSayLink, const std::string& serverSayLink) { - if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { - titaniumTextLink = serverTextLink; + if ((constants::SayLinkBodySize == EQEmu::constants::SayLinkBodySize) || (serverSayLink.find('\x12') == std::string::npos)) { + titaniumSayLink = serverSayLink; return; } - auto segments = SplitString(serverTextLink, '\x12'); + auto segments = SplitString(serverSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { - titaniumTextLink.append(segments[segment_iter]); + if (segments[segment_iter].length() <= EQEmu::constants::SayLinkBodySize) { + titaniumSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -2496,37 +2510,37 @@ namespace Titanium // 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45) // Diff: ^^^^^ ^ ^^^^^ - titaniumTextLink.push_back('\x12'); - titaniumTextLink.append(segments[segment_iter].substr(0, 31)); - titaniumTextLink.append(segments[segment_iter].substr(36, 5)); + titaniumSayLink.push_back('\x12'); + titaniumSayLink.append(segments[segment_iter].substr(0, 31)); + titaniumSayLink.append(segments[segment_iter].substr(36, 5)); if (segments[segment_iter][41] == '0') - titaniumTextLink.push_back(segments[segment_iter][42]); + titaniumSayLink.push_back(segments[segment_iter][42]); else - titaniumTextLink.push_back('F'); + titaniumSayLink.push_back('F'); - titaniumTextLink.append(segments[segment_iter].substr(48)); - titaniumTextLink.push_back('\x12'); + titaniumSayLink.append(segments[segment_iter].substr(48)); + titaniumSayLink.push_back('\x12'); } else { - titaniumTextLink.append(segments[segment_iter]); + titaniumSayLink.append(segments[segment_iter]); } } } - static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink) + static inline void TitaniumToServerSayLink(std::string& serverSayLink, const std::string& titaniumSayLink) { - if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (titaniumTextLink.find('\x12') == std::string::npos)) { - serverTextLink = titaniumTextLink; + if ((EQEmu::constants::SayLinkBodySize == constants::SayLinkBodySize) || (titaniumSayLink.find('\x12') == std::string::npos)) { + serverSayLink = titaniumSayLink; return; } - auto segments = SplitString(titaniumTextLink, '\x12'); + auto segments = SplitString(titaniumSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { if (segments[segment_iter].length() <= constants::SayLinkBodySize) { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -2536,18 +2550,18 @@ namespace Titanium // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ ^^^^^ - serverTextLink.push_back('\x12'); - serverTextLink.append(segments[segment_iter].substr(0, 31)); - serverTextLink.append("00000"); - serverTextLink.append(segments[segment_iter].substr(31, 5)); - serverTextLink.push_back('0'); - serverTextLink.push_back(segments[segment_iter][36]); - serverTextLink.append("00000"); - serverTextLink.append(segments[segment_iter].substr(37)); - serverTextLink.push_back('\x12'); + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 31)); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(31, 5)); + serverSayLink.push_back('0'); + serverSayLink.push_back(segments[segment_iter][36]); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(37)); + serverSayLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); } } } diff --git a/common/patches/titanium_ops.h b/common/patches/titanium_ops.h index 9f77a7077..dafb8b903 100644 --- a/common/patches/titanium_ops.h +++ b/common/patches/titanium_ops.h @@ -78,6 +78,7 @@ D(OP_AdventureMerchantSell) D(OP_ApplyPoison) D(OP_AugmentItem) D(OP_Buff) +D(OP_Bug) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 56213854a..9f2d9423d 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -48,6 +48,23 @@ struct EnterWorld_Struct { /*068*/ uint32 return_home; // 01 on "Return Home", 00 if not }; +// yep, even tit had a version of the new inventory system, used by OP_MoveMultipleItems +struct InventorySlot_Struct +{ +/*000*/ int32 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Trade = 3, World = 4, Limbo = 5 +/*004*/ int32 Slot; +/*008*/ int32 SubIndex; // no aug index in Tit +/*012*/ int32 Unknown01; +}; + +// unsure if they have a version of this, completeness though +struct TypelessInventorySlot_Struct +{ +/*000*/ int32 Slot; +/*004*/ int32 SubIndex; // no aug index in Tit +/*008*/ int32 Unknown01; +}; + /* Name Approval Struct */ /* Len: */ /* Opcode: 0x8B20*/ @@ -310,7 +327,7 @@ union // horse: 0=brown, 1=white, 2=black, 3=tan }; /*0340*/ uint32 spawnId; // Spawn Id -/*0344*/ uint8 unknown0344[4]; +/*0344*/ float bounding_radius; // used in melee, overrides calc /*0348*/ TintProfile equipment_tint; /*0384*/ uint8 lfg; // 0=off, 1=lfg on /*0385*/ @@ -1102,20 +1119,18 @@ struct Action_Struct { /* 00 */ uint16 target; // id of target /* 02 */ uint16 source; // id of caster - /* 04 */ uint16 level; // level of caster - /* 06 */ uint16 instrument_mod; - /* 08 */ uint32 unknown08; - /* 12 */ uint16 unknown16; -// some kind of sequence that's the same in both actions -// as well as the combat damage, to tie em together? - /* 14 */ uint32 sequence; - /* 18 */ uint32 unknown18; - /* 22 */ uint8 type; // 231 (0xE7) for spells - /* 23 */ uint32 unknown23; + /* 04 */ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level + /* 06 */ uint32 instrument_mod; // OSX dump says base damage, spells use it for bard song (different from newer clients) + /* 10 */ float force; + /* 14 */ float hit_heading; + /* 18 */ float hit_pitch; + /* 22 */ uint8 type; // 231 (0xE7) for spells, skill + /* 23 */ uint16 unknown23; // OSX says min_damage + /* 25 */ uint16 unknown25; // OSX says tohit /* 27 */ uint16 spell; // spell id being cast - /* 29 */ uint8 unknown29; + /* 29 */ uint8 spell_level; // this field seems to be some sort of success flag, if it's 4 - /* 30 */ uint8 buff_unknown; // if this is 4, a buff icon is made + /* 30 */ uint8 effect_flag; // if this is 4, a buff icon is made /* 31 */ }; @@ -1126,12 +1141,12 @@ struct CombatDamage_Struct { /* 00 */ uint16 target; /* 02 */ uint16 source; -/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells +/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells, skill /* 05 */ uint16 spellid; /* 07 */ uint32 damage; /* 11 */ float force; -/* 15 */ float meleepush_xy; // see above notes in Action_Struct -/* 19 */ float meleepush_z; +/* 15 */ float hit_heading; // see above notes in Action_Struct +/* 19 */ float hit_pitch; /* 23 */ }; @@ -1329,6 +1344,19 @@ struct MoveItem_Struct /*0012*/ }; +struct MultiMoveItemSub_Struct +{ +/*0000*/ InventorySlot_Struct from_slot; +/*0016*/ uint32 number_in_stack; // so the amount we are moving from the source +/*0020*/ InventorySlot_Struct to_slot; +}; + +struct MultiMoveItem_Struct +{ +/*0000*/ uint32 count; +/*0004*/ MultiMoveItemSub_Struct moves[0]; +}; + // // from_slot/to_slot // -1 - destroy @@ -2541,21 +2569,32 @@ struct GuildMakeLeader{ char name[64]; char target[64]; }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; + +struct BugReport_Struct { +/*0000*/ char category_name[64]; +/*0064*/ char character_name[64]; +/*0128*/ char unused_0128[32]; +/*0160*/ char ui_path[128]; +/*0288*/ float pos_x; +/*0292*/ float pos_y; +/*0296*/ float pos_z; +/*0300*/ uint32 heading; +/*0304*/ uint32 unused_0304; +/*0308*/ uint32 time_played; +/*0312*/ char padding_0312[8]; +/*0320*/ uint32 target_id; +/*0324*/ char padding_0324[140]; +/*0464*/ uint32 unknown_0464; // seems to always be '0' +/*0468*/ char target_name[64]; +/*0532*/ uint32 optional_info_mask; + +// this looks like a butchered 8k buffer with 2 trailing dword fields +/*0536*/ char unused_0536[2052]; +/*2588*/ char bug_report[2050]; +/*4638*/ char system_info[4098]; +/*8736*/ }; + struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -2582,20 +2621,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; @@ -3523,6 +3563,21 @@ struct LFGuild_GuildToggle_Struct // char ScrollName; // '0' //}; +struct SayLinkBodyFrame_Struct { +/*000*/ char ActionID[1]; +/*001*/ char ItemID[5]; +/*006*/ char Augment1[5]; +/*011*/ char Augment2[5]; +/*016*/ char Augment3[5]; +/*021*/ char Augment4[5]; +/*026*/ char Augment5[5]; +/*031*/ char IsEvolving[1]; +/*032*/ char EvolveGroup[4]; +/*036*/ char EvolveLevel[1]; +/*037*/ char Hash[8]; +/*045*/ +}; + }; /*structs*/ }; /*Titanium*/ diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index cf0c17176..79fdca333 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -53,11 +53,11 @@ namespace UF static inline uint32 UFToServerSlot(uint32 ufSlot); static inline uint32 UFToServerCorpseSlot(uint32 ufCorpseSlot); - // server to client text link converter - static inline void ServerToUFTextLink(std::string& ufTextLink, const std::string& serverTextLink); + // server to client say link converter + static inline void ServerToUFSayLink(std::string& ufSayLink, const std::string& serverSayLink); - // client to server text link converter - static inline void UFToServerTextLink(std::string& serverTextLink, const std::string& ufTextLink); + // client to server say link converter + static inline void UFToServerSayLink(std::string& serverSayLink, const std::string& ufSayLink); static inline CastingSlot ServerToUFCastingSlot(EQEmu::CastingSlot slot); static inline EQEmu::CastingSlot UFToServerCastingSlot(CastingSlot slot); @@ -161,29 +161,20 @@ namespace UF OUT(source); OUT(level); eq->instrument_mod = 1.0f + (emu->instrument_mod - 10) / 10.0f; - eq->knockback_angle = emu->sequence; + OUT(force); + OUT(hit_heading); + OUT(hit_pitch); OUT(type); OUT(spell); - eq->level2 = eq->level; - eq->effect_flag = emu->buff_unknown; - eq->unknown37 = 0x01; - eq->unknown44 = 0xFFFFFFFF; - eq->unknown48 = 0xFFFFFFFF; - eq->unknown52 = 0xFFFFFFFF; - - /*OUT(target); - OUT(source); - OUT(level); - OUT(instrument_mod); - eq->sequence = emu->sequence; - OUT(type); - //OUT(damage); - OUT(spell); - eq->level2 = emu->level; - OUT(buff_unknown); // if this is 4, a buff icon is made - //eq->unknown0036 = -1; - //eq->unknown0040 = -1; - //eq->unknown0044 = -1;*/ + OUT(spell_level); + OUT(effect_flag); + eq->spell_gem = 0; + eq->slot[0] = -1; // type + eq->slot[1] = -1; // slot + eq->slot[2] = -1; // sub index + eq->slot[3] = -1; // aug index + eq->slot[4] = -1; // unknown + eq->item_cast_type = 0; FINISH_ENCODE(); } @@ -463,7 +454,7 @@ namespace UF std::string old_message = emu->message; std::string new_message; - ServerToUFTextLink(new_message, old_message); + ServerToUFSayLink(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; @@ -586,8 +577,8 @@ namespace UF OUT(spellid); OUT(damage); OUT(force); - OUT(meleepush_xy); - OUT(meleepush_z); + OUT(hit_heading); + OUT(hit_pitch); OUT(special); FINISH_ENCODE(); @@ -762,7 +753,7 @@ namespace UF std::string old_message = emu->message; std::string new_message; - ServerToUFTextLink(new_message, old_message); + ServerToUFSayLink(new_message, old_message); //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) // new_message = new_message.substr(0, 512); @@ -814,7 +805,7 @@ namespace UF for (int i = 0; i < 9; ++i) { if (old_message_array[i].length() == 0) { break; } - ServerToUFTextLink(new_message_array[i], old_message_array[i]); + ServerToUFSayLink(new_message_array[i], old_message_array[i]); new_message_size += new_message_array[i].length() + 1; } @@ -2469,7 +2460,7 @@ namespace UF std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; - ServerToUFTextLink(new_message, old_message); + ServerToUFSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; in->size = strlen(emu->sayer) + new_message.length() + 25; @@ -2539,7 +2530,7 @@ namespace UF std::string old_message = InBuffer; // start 'Reward' as string std::string new_message; - ServerToUFTextLink(new_message, old_message); + ServerToUFSayLink(new_message, old_message); in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ @@ -3287,7 +3278,7 @@ namespace UF std::string old_message = InBuffer; std::string new_message; - UFToServerTextLink(new_message, old_message); + UFToServerSayLink(new_message, old_message); //__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1; __packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1; @@ -3398,7 +3389,7 @@ namespace UF IN(type); IN(spellid); IN(damage); - IN(meleepush_xy); + IN(hit_heading); FINISH_DIRECT_DECODE(); } @@ -3421,7 +3412,7 @@ namespace UF std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset std::string new_message; - UFToServerTextLink(new_message, old_message); + UFToServerSayLink(new_message, old_message); __packet->size = sizeof(Emote_Struct); __packet->pBuffer = new unsigned char[__packet->size]; @@ -4290,19 +4281,19 @@ namespace UF return (ufCorpseSlot - 1); } - static inline void ServerToUFTextLink(std::string& ufTextLink, const std::string& serverTextLink) + static inline void ServerToUFSayLink(std::string& ufSayLink, const std::string& serverSayLink) { - if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { - ufTextLink = serverTextLink; + if ((constants::SayLinkBodySize == EQEmu::constants::SayLinkBodySize) || (serverSayLink.find('\x12') == std::string::npos)) { + ufSayLink = serverSayLink; return; } - auto segments = SplitString(serverTextLink, '\x12'); + auto segments = SplitString(serverSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { - ufTextLink.append(segments[segment_iter]); + if (segments[segment_iter].length() <= EQEmu::constants::SayLinkBodySize) { + ufSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -4312,37 +4303,37 @@ namespace UF // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // Diff: ^^^^^ ^ - ufTextLink.push_back('\x12'); - ufTextLink.append(segments[segment_iter].substr(0, 31)); - ufTextLink.append(segments[segment_iter].substr(36, 5)); + ufSayLink.push_back('\x12'); + ufSayLink.append(segments[segment_iter].substr(0, 31)); + ufSayLink.append(segments[segment_iter].substr(36, 5)); if (segments[segment_iter][41] == '0') - ufTextLink.push_back(segments[segment_iter][42]); + ufSayLink.push_back(segments[segment_iter][42]); else - ufTextLink.push_back('F'); + ufSayLink.push_back('F'); - ufTextLink.append(segments[segment_iter].substr(43)); - ufTextLink.push_back('\x12'); + ufSayLink.append(segments[segment_iter].substr(43)); + ufSayLink.push_back('\x12'); } else { - ufTextLink.append(segments[segment_iter]); + ufSayLink.append(segments[segment_iter]); } } } - static inline void UFToServerTextLink(std::string& serverTextLink, const std::string& ufTextLink) + static inline void UFToServerSayLink(std::string& serverSayLink, const std::string& ufSayLink) { - if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (ufTextLink.find('\x12') == std::string::npos)) { - serverTextLink = ufTextLink; + if ((EQEmu::constants::SayLinkBodySize == constants::SayLinkBodySize) || (ufSayLink.find('\x12') == std::string::npos)) { + serverSayLink = ufSayLink; return; } - auto segments = SplitString(ufTextLink, '\x12'); + auto segments = SplitString(ufSayLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { if (segments[segment_iter].length() <= constants::SayLinkBodySize) { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; } @@ -4352,16 +4343,16 @@ namespace UF // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ - serverTextLink.push_back('\x12'); - serverTextLink.append(segments[segment_iter].substr(0, 31)); - serverTextLink.append("00000"); - serverTextLink.append(segments[segment_iter].substr(31, 5)); - serverTextLink.push_back('0'); - serverTextLink.append(segments[segment_iter].substr(36)); - serverTextLink.push_back('\x12'); + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 31)); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(31, 5)); + serverSayLink.push_back('0'); + serverSayLink.append(segments[segment_iter].substr(36)); + serverSayLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter]); + serverSayLink.append(segments[segment_iter]); } } } diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index cc5564e11..dc66afd43 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -292,7 +292,7 @@ struct Spawn_Struct /*0000*/ //uint8 nullterm1; // hack to null terminate name /*0064*/ uint32 spawnId; /*0068*/ uint8 level; -/*0069*/ float unknown1; +/*0069*/ float bounding_radius; // used in melee, overrides calc /*0073*/ uint8 NPC; // 0=player,1=npc,2=pc corpse,3=npc corpse Spawn_Struct_Bitfields Bitfields; /*0000*/ uint8 otherData; // & 4 - has title, & 8 - has suffix, & 1 - it's a chest or untargetable @@ -1252,19 +1252,19 @@ struct Action_Struct { /*00*/ uint16 target; // id of target /*02*/ uint16 source; // id of caster -/*04*/ uint16 level; // level of caster - Seen 0 -/*06*/ uint32 unknown06; -/*10*/ uint16 instrument_focus; -/*12*/ uint16 unknown12; // seems to always be set to something and it doesn't change between casts except in special cases like changing instrument mods -/*14*/ uint32 unknown14; // seen 0 -/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again -/*22*/ uint32 unknown22; -/*26*/ uint8 type; -/*27*/ uint32 damage; -/*31*/ uint16 unknown31; +/*04*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*06*/ uint32 unknown06; // OSX dump says base_damage, was used for bard mod too, this is 0'd :( +/*10*/ float instrument_mod; +/*14*/ float force; +/*18*/ float hit_heading; +/*22*/ float hit_pitch; +/*26*/ uint8 type; // 231 (0xE7) for spells, skill +/*27*/ uint32 damage; // OSX says min_damage +/*31*/ uint16 unknown31; // OSX says tohit /*33*/ uint16 spell; // spell id being cast -/*35*/ uint8 level2; // level of caster again? Or maybe the castee +/*35*/ uint8 spell_level; // level of caster again? Or maybe the castee /*36*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? +/*37*/ }; @@ -1276,27 +1276,22 @@ struct ActionAlt_Struct { /*00*/ uint16 target; // id of target /*02*/ uint16 source; // id of caster -/*04*/ uint16 level; // level of caster - Seen 0 -/*06*/ uint32 unknown06; +/*04*/ uint16 level; // level of caster for spells, OSX dump says attack rating, guess spells use it for level +/*06*/ uint32 unknown06; // OSX dump says base_damage, was used for bard mod too, this is 0'd :( /*10*/ float instrument_mod; -/*14*/ uint32 unknown14; // seen 0 -/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again -/*22*/ uint32 unknown22; -/*26*/ uint8 type; -/*27*/ uint32 damage; -/*31*/ uint16 unknown31; +/*14*/ float force; +/*18*/ float hit_heading; +/*22*/ float hit_pitch; +/*26*/ uint8 type; // 231 (0xE7) for spells, skill +/*27*/ uint32 damage; // OSX says min_damage +/*31*/ uint16 unknown31; // OSX says tohit /*33*/ uint16 spell; // spell id being cast -/*35*/ uint8 level2; // level of caster again? Or maybe the castee +/*35*/ uint8 spell_level; // level of caster again? Or maybe the castee /*36*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? -/*37*/ uint32 unknown37; // New field to Underfoot - Seen 14 -/*41*/ uint8 unknown41; // New field to Underfoot - Seen 0 -/*42*/ uint8 unknown42; // New field to Underfoot - Seen 0 -/*43*/ uint8 unknown43; // New field to Underfoot - Seen 0 -/*44*/ uint32 unknown44; // New field to Underfoot - Seen 23 -/*48*/ uint32 unknown48; // New field to Underfoot - Seen -1 -/*52*/ uint32 unknown52; // New field to Underfoot - Seen -1 -/*56*/ uint32 unknown56; // New field to Underfoot - Seen 0 -/*60*/ uint32 unknown60; // New field to Underfoot - Seen 0 +/*37*/ uint8 spell_gem; +/*38*/ uint8 padding38[2]; +/*40*/ uint32 slot[5]; +/*60*/ uint32 item_cast_type; // ItemSpellTypes enum from MQ2 /*64*/ }; @@ -1311,9 +1306,9 @@ struct CombatDamage_Struct /* 05 */ uint16 spellid; /* 07 */ int32 damage; /* 11 */ float force; // cd cc cc 3d -/* 15 */ float meleepush_xy; // see above notes in Action_Struct -/* 19 */ float meleepush_z; -/* 23 */ uint8 unknown23; // was [9] +/* 15 */ float hit_heading; // see above notes in Action_Struct +/* 19 */ float hit_pitch; +/* 23 */ uint8 secondary; // 0 for primary hand, 1 for secondary /* 24 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 28 */ }; @@ -3060,23 +3055,6 @@ struct GuildMakeLeader{ char target[64]; }; - - -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3103,20 +3081,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; @@ -4505,6 +4484,22 @@ struct MercenaryAssign_Struct { /*0004*/ uint32 MercUnk01; // /*0008*/ uint32 MercUnk02; // /*0012*/ +}; + +struct SayLinkBodyFrame_Struct { +/*000*/ char ActionID[1]; +/*001*/ char ItemID[5]; +/*006*/ char Augment1[5]; +/*011*/ char Augment2[5]; +/*016*/ char Augment3[5]; +/*021*/ char Augment4[5]; +/*026*/ char Augment5[5]; +/*031*/ char IsEvolving[1]; +/*032*/ char EvolveGroup[4]; +/*036*/ char EvolveLevel[1]; +/*037*/ char OrnamentIcon[5]; +/*042*/ char Hash[8]; +/*050*/ }; }; /*structs*/ diff --git a/common/races.cpp b/common/races.cpp index 9d5fbdda0..1e4d88664 100644 --- a/common/races.cpp +++ b/common/races.cpp @@ -1488,6 +1488,122 @@ uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit) } } +float GetRaceGenderDefaultHeight(int race, int gender) +{ + static float male_height[] = { + 6.0f, 6.0f, 7.0f, 6.0f, 5.0f, 6.0f, 5.0f, 5.5f, 4.0f, 8.0f, 9.0f, 3.5f, 3.0f, 6.0f, 6.0f, + 2.0f, 8.5f, 8.0f, 21.0f, 20.0f, 6.0f, 6.0f, 3.5f, 3.0f, 6.0f, 2.0f, 5.0f, 5.0f, 6.0f, 6.0f, + 6.0f, 7.5f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 5.0f, 6.0f, 6.0f, 7.0f, 4.0f, 4.7f, 6.0f, + 8.0f, 3.0f, 12.0f, 5.0f, 21.0f, 6.0f, 6.0f, 3.0f, 9.0f, 6.0f, 6.0f, 2.0f, 6.0f, 3.0f, 6.0f, + 4.0f, 20.0f, 5.0f, 5.0f, 6.0f, 9.0f, 25.0f, 6.0f, 6.0f, 10.0f, 6.0f, 6.0f, 6.0f, 6.0f, 2.5f, + 7.0f, 6.0f, 5.0f, 6.0f, 1.5f, 1.0f, 3.5f, 7.0f, 6.0f, 6.0f, 6.0f, 6.0f, 7.0f, 3.0f, 3.0f, + 7.0f, 12.0f, 8.0f, 9.0f, 4.0f, 11.5f, 8.0f, 6.0f, 6.0f, 12.0f, 6.0f, 6.0f, 6.0f, 20.0f, 10.0f, + 6.5f, 6.0f, 17.0f, 1.0f, 4.0f, 6.0f, 8.0f, 5.0f, 1.0f, 6.0f, 6.0f, 5.0f, 5.0f, 5.0f, 9.0f, + 3.0f, 8.0f, 2.0f, 24.0f, 6.0f, 10.0f, 6.0f, 6.0f, 6.0f, 3.0f, 7.0f, 9.0f, 6.0f, 11.0f, 2.5f, + 14.0f, 8.0f, 7.0f, 12.0f, 6.0f, 27.0f, 6.0f, 6.0f, 6.0f, 6.0f, 2.0f, 9.0f, 9.0f, 6.0f, 9.0f, + 3.0f, 3.0f, 6.0f, 6.0f, 10.0f, 6.0f, 6.0f, 15.0f, 15.0f, 9.0f, 7.0f, 6.0f, 6.0f, 7.0f, 8.0f, + 3.0f, 3.0f, 6.0f, 7.0f, 13.0f, 6.0f, 6.0f, 9.0f, 5.0f, 7.0f, 9.0f, 6.0f, 6.0f, 8.0f, 6.0f, + 6.0f, 5.5f, 6.0f, 4.0f, 25.0f, 6.0f, 6.0f, 6.0f, 22.0f, 20.0f, 6.0f, 10.0f, 13.5f, 12.0f, 3.0f, + 30.0f, 6.0f, 6.0f, 35.0f, 1.5f, 8.0f, 3.0f, 6.0f, 2.0f, 6.0f, 6.0f, 5.0f, 2.0f, 7.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 4.0f, 6.0f, 6.0f, 6.0f, 8.0f, 8.0f, 7.0f, 8.0f, 6.0f, 7.0f, 6.0f, 7.0f, + 6.0f, 10.0f, 3.0f, 6.0f, 8.0f, 9.0f, 15.0f, 5.0f, 10.0f, 7.0f, 6.0f, 7.0f, 6.0f, 7.0f, 7.0f, + 12.0f, 6.0f, 4.0f, 6.0f, 5.0f, 3.0f, 30.0f, 30.0f, 15.0f, 20.0f, 6.0f, 10.0f, 6.0f, 14.0f, 14.0f, + 16.0f, 15.0f, 30.0f, 15.0f, 7.5f, 5.0f, 4.0f, 6.0f, 15.0f, 6.5f, 3.0f, 12.0f, 10.0f, 10.5f, 10.0f, + 7.5f, 6.0f, 6.0f, 12.5f, 9.0f, 20.0f, 2.0f, 10.0f, 25.0f, 8.0f, 6.0f, 6.0f, 10.0f, 18.0f, 45.0f, + 13.0f, 15.0f, 8.0f, 30.0f, 25.0f, 25.0f, 10.0f, 13.0f, 5.0f, 3.5f, 15.0f, 35.0f, 11.0f, 15.0f, 50.0f, + 13.0f, 6.0f, 7.0f, 6.0f, 60.0f, 6.0f, 22.0f, 22.0f, 21.0f, 22.0f, 15.0f, 25.0f, 23.0f, 8.0f, 15.0f, + 10.0f, 6.0f, 7.0f, 6.0f, 12.0f, 9.5f, 6.0f, 12.0f, 12.0f, 12.0f, 15.0f, 4.0f, 5.0f, 105.0f, 20.0f, + 5.0f, 10.0f, 10.0f, 10.0f, 20.0f, 13.5f, 8.0f, 10.0f, 3.0f, 5.0f, 9.0f, 6.0f, 6.0f, 6.0f, 10.0f, + 8.0f, 8.0f, 8.0f, 6.0f, 6.0f, 5.0f, 5.0f, 5.0f, 9.0f, 9.0f, 9.0f, 6.0f, 8.5f, 6.0f, 7.0f, + 8.0f, 7.0f, 11.0f, 6.0f, 7.0f, 9.0f, 8.0f, 6.0f, 8.0f, 6.0f, 6.0f, 6.0f, 6.0f, 9.0f, 10.0f, + 6.0f, 3.0f, 4.0f, 3.0f, 3.0f, 4.0f, 10.0f, 10.0f, 2.0f, 8.0f, 6.0f, 6.0f, 14.0f, 7.0f, 5.0f, + 9.0f, 7.0f, 7.0f, 10.0f, 10.0f, 12.0f, 9.0f, 7.0f, 12.0f, 13.0f, 16.0f, 6.0f, 9.0f, 6.0f, 6.0f, + 10.0f, 25.0f, 15.0f, 6.0f, 25.0f, 6.0f, 6.0f, 8.0f, 11.0f, 6.0f, 9.0f, 2.0f, 6.0f, 5.0f, 4.0f, + 8.5f, 6.0f, 6.0f, 6.0f, 4.0f, 6.0f, 15.0f, 1.0f, 2.0f, 6.0f, 40.0f, 8.0f, 12.0f, 3.0f, 8.0f, + 99.0f, 9.0f, 100.0f, 100.0f, 10.0f, 6.0f, 27.5f, 20.0f, 6.0f, 6.0f, 5.0f, 6.0f, 8.0f, 5.0f, 3.0f, + 11.5f, 25.0f, 80.0f, 20.0f, 9.0f, 8.0f, 5.0f, 4.0f, 7.0f, 10.0f, 6.0f, 11.0f, 8.0f, 5.0f, 6.0f, + 6.0f, 30.0f, 7.0f, 15.0f, 9.0f, 6.0f, 9.0f, 6.0f, 3.0f, 32.5f, 15.0f, 7.5f, 10.0f, 10.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 9.0f, 20.0f, 6.0f, 6.0f, 6.0f, 25.0f, 12.0f, 6.0f, 8.0f, 6.0f, + 6.0f, 20.0f, 10.0f, 8.0f, 12.0f, 8.0f, 2.0f, 6.0f, 3.0f, 6.0f, 7.0f, 1.5f, 6.0f, 3.0f, 3.0f, + 3.0f, 3.0f, 2.0f, 3.0f, 3.0f, 6.0f, 6.0f, 6.0f, 4.5f, 7.0f, 6.0f, 7.0f, 6.0f, 22.0f, 8.0f, + 15.0f, 22.0f, 8.0f, 15.0f, 6.0f, 80.0f, 150.0f, 7.0f, 6.0f, 6.0f, 6.0f, 12.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 35.0f, 20.0f, 9.0f, 6.0f, 6.0f, 6.0f, 20.0f, 20.0f, + 20.0f, 20.0f, 20.0f, 9.0f, 4.0f, 4.0f, 10.0f, 5.0f, 8.0f, 6.0f, 10.0f, 6.0f, 6.0f, 2.0f, 36.0f, + 14.0f, 7.0f, 250.0f, 6.0f, 9.0f, 6.0f, 7.0f, 4.0f, 6.0f, 8.0f, 6.0f, 23.0f, 6.0f, 6.0f, 6.0f, + 70.0f, 6.0f, 7.0f, 6.0f, 6.0f, 6.0f, 20.0f, 6.0f, 6.0f, 6.0f, 5.0f, 1.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 4.0f, 4.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 10.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 7.0f, 7.0f, 7.0f, 7.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 8.0f, + 6.0f, 6.0f, 6.0f, 7.0f, 6.0f, 6.0f, 6.0f, 7.5f, 6.0f, 6.0f, 4.0f, 6.0f, 3.0f, 6.0f, 6.0f, + 1.0f, 9.0f, 7.0f, 8.0f, 7.0f, 8.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 8.0f, + }; + + static float female_height[] = { + 6.0f, 6.0f, 7.0f, 6.0f, 5.0f, 6.0f, 5.0f, 5.5f, 4.0f, 8.0f, 9.0f, 3.5f, 3.0f, 6.0f, 6.0f, + 2.0f, 8.5f, 8.0f, 21.0f, 20.0f, 6.0f, 6.0f, 3.5f, 3.0f, 6.0f, 2.0f, 5.0f, 5.0f, 6.0f, 6.0f, + 6.0f, 7.5f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 5.0f, 6.0f, 6.0f, 7.0f, 4.0f, 4.7f, 6.0f, + 8.0f, 3.0f, 12.0f, 5.0f, 21.0f, 6.0f, 6.0f, 3.0f, 9.0f, 6.0f, 6.0f, 2.0f, 6.0f, 3.0f, 6.0f, + 4.0f, 20.0f, 5.0f, 5.0f, 6.0f, 9.0f, 25.0f, 6.0f, 6.0f, 10.0f, 6.0f, 6.0f, 6.0f, 6.0f, 2.5f, + 7.0f, 6.0f, 5.0f, 6.0f, 1.5f, 1.0f, 3.5f, 7.0f, 6.0f, 6.0f, 6.0f, 6.0f, 7.0f, 3.0f, 3.0f, + 7.0f, 12.0f, 8.0f, 9.0f, 4.0f, 11.5f, 8.0f, 6.0f, 6.0f, 12.0f, 6.0f, 6.0f, 6.0f, 20.0f, 10.0f, + 6.5f, 6.0f, 17.0f, 1.0f, 4.0f, 6.0f, 8.0f, 5.0f, 1.0f, 6.0f, 6.0f, 5.0f, 5.0f, 5.0f, 9.0f, + 3.0f, 8.0f, 2.0f, 24.0f, 6.0f, 10.0f, 6.0f, 6.0f, 6.0f, 3.0f, 7.0f, 9.0f, 6.0f, 11.0f, 2.5f, + 14.0f, 8.0f, 7.0f, 12.0f, 6.0f, 27.0f, 6.0f, 6.0f, 6.0f, 6.0f, 2.0f, 9.0f, 9.0f, 6.0f, 9.0f, + 3.0f, 3.0f, 6.0f, 6.0f, 10.0f, 6.0f, 6.0f, 15.0f, 15.0f, 9.0f, 7.0f, 6.0f, 6.0f, 7.0f, 8.0f, + 3.0f, 3.0f, 6.0f, 7.0f, 13.0f, 6.0f, 6.0f, 9.0f, 5.0f, 7.0f, 9.0f, 6.0f, 6.0f, 8.0f, 6.0f, + 6.0f, 5.5f, 6.0f, 4.0f, 25.0f, 6.0f, 6.0f, 6.0f, 22.0f, 20.0f, 6.0f, 10.0f, 13.5f, 12.0f, 3.0f, + 30.0f, 6.0f, 6.0f, 35.0f, 1.5f, 8.0f, 3.0f, 6.0f, 2.0f, 6.0f, 6.0f, 5.0f, 2.0f, 7.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 4.0f, 6.0f, 6.0f, 6.0f, 8.0f, 8.0f, 7.0f, 8.0f, 6.0f, 7.0f, 6.0f, 7.0f, + 6.0f, 10.0f, 3.0f, 6.0f, 8.0f, 9.0f, 15.0f, 5.0f, 10.0f, 7.0f, 6.0f, 7.0f, 6.0f, 7.0f, 7.0f, + 12.0f, 6.0f, 4.0f, 6.0f, 5.0f, 3.0f, 30.0f, 30.0f, 15.0f, 20.0f, 6.0f, 10.0f, 6.0f, 14.0f, 14.0f, + 16.0f, 15.0f, 30.0f, 15.0f, 7.5f, 5.0f, 4.0f, 6.0f, 15.0f, 6.5f, 3.0f, 12.0f, 10.0f, 10.5f, 10.0f, + 7.5f, 6.0f, 6.0f, 12.5f, 9.0f, 20.0f, 2.0f, 10.0f, 25.0f, 8.0f, 6.0f, 6.0f, 10.0f, 18.0f, 45.0f, + 13.0f, 15.0f, 8.0f, 30.0f, 25.0f, 25.0f, 10.0f, 13.0f, 5.0f, 3.5f, 15.0f, 35.0f, 11.0f, 15.0f, 50.0f, + 13.0f, 6.0f, 7.0f, 6.0f, 60.0f, 6.0f, 22.0f, 22.0f, 21.0f, 22.0f, 15.0f, 25.0f, 23.0f, 8.0f, 15.0f, + 10.0f, 6.0f, 7.0f, 6.0f, 12.0f, 9.5f, 6.0f, 12.0f, 12.0f, 12.0f, 15.0f, 4.0f, 5.0f, 105.0f, 20.0f, + 5.0f, 10.0f, 10.0f, 10.0f, 20.0f, 13.5f, 8.0f, 10.0f, 3.0f, 5.0f, 9.0f, 6.0f, 6.0f, 6.0f, 10.0f, + 8.0f, 8.0f, 8.0f, 6.0f, 6.0f, 5.0f, 5.0f, 5.0f, 9.0f, 9.0f, 9.0f, 6.0f, 8.5f, 6.0f, 7.0f, + 8.0f, 7.0f, 11.0f, 6.0f, 7.0f, 9.0f, 8.0f, 6.0f, 8.0f, 6.0f, 6.0f, 6.0f, 6.0f, 9.0f, 10.0f, + 6.0f, 3.0f, 4.0f, 3.0f, 3.0f, 4.0f, 10.0f, 10.0f, 2.0f, 8.0f, 6.0f, 6.0f, 14.0f, 7.0f, 5.0f, + 9.0f, 7.0f, 7.0f, 10.0f, 10.0f, 12.0f, 9.0f, 7.0f, 12.0f, 13.0f, 16.0f, 6.0f, 9.0f, 6.0f, 6.0f, + 10.0f, 25.0f, 15.0f, 6.0f, 25.0f, 6.0f, 6.0f, 8.0f, 11.0f, 6.0f, 9.0f, 2.0f, 6.0f, 5.0f, 4.0f, + 8.5f, 6.0f, 6.0f, 6.0f, 4.0f, 6.0f, 15.0f, 1.0f, 2.0f, 6.0f, 40.0f, 8.0f, 12.0f, 3.0f, 8.0f, + 99.0f, 9.0f, 100.0f, 100.0f, 10.0f, 6.0f, 27.5f, 20.0f, 6.0f, 6.0f, 5.0f, 6.0f, 8.0f, 5.0f, 3.0f, + 11.5f, 25.0f, 80.0f, 20.0f, 9.0f, 8.0f, 5.0f, 4.0f, 7.0f, 10.0f, 6.0f, 11.0f, 8.0f, 5.0f, 6.0f, + 6.0f, 30.0f, 7.0f, 15.0f, 9.0f, 6.0f, 9.0f, 6.0f, 3.0f, 32.5f, 15.0f, 7.5f, 10.0f, 10.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 9.0f, 20.0f, 6.0f, 6.0f, 6.0f, 25.0f, 12.0f, 6.0f, 8.0f, 6.0f, + 6.0f, 20.0f, 9.0f, 8.0f, 12.0f, 8.0f, 2.0f, 6.0f, 3.0f, 6.0f, 7.0f, 1.5f, 6.0f, 3.0f, 3.0f, + 3.0f, 3.0f, 2.0f, 3.0f, 3.0f, 6.0f, 6.0f, 6.0f, 4.5f, 7.0f, 6.0f, 7.0f, 5.7f, 22.0f, 8.0f, + 15.0f, 22.0f, 8.0f, 15.0f, 6.0f, 80.0f, 150.0f, 7.0f, 6.0f, 6.0f, 6.0f, 12.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 35.0f, 20.0f, 9.0f, 6.0f, 6.0f, 6.0f, 20.0f, 20.0f, + 20.0f, 20.0f, 20.0f, 9.0f, 4.0f, 4.0f, 10.0f, 5.0f, 8.0f, 6.0f, 10.0f, 5.7f, 6.0f, 2.0f, 36.0f, + 14.0f, 7.0f, 250.0f, 6.0f, 9.0f, 6.0f, 7.0f, 4.0f, 6.0f, 8.0f, 6.0f, 23.0f, 6.0f, 6.0f, 6.0f, + 70.0f, 6.0f, 7.0f, 6.0f, 6.0f, 6.0f, 20.0f, 6.0f, 6.0f, 6.0f, 5.0f, 1.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 4.0f, 4.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 10.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, + 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 7.0f, 7.0f, 7.0f, 7.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 8.0f, + 6.0f, 6.0f, 6.0f, 7.0f, 6.0f, 6.0f, 6.0f, 7.5f, 6.0f, 6.0f, 4.0f, 6.0f, 3.0f, 6.0f, 6.0f, + 1.0f, 9.0f, 7.0f, 8.0f, 7.0f, 8.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 8.0f, + }; + + const auto size = sizeof(male_height) / sizeof(male_height[0]); + + if (race > size) + return 6.0f; + + if (gender == 1) + return female_height[race]; + + return male_height[race]; +} // PlayerAppearance prep #define HUMAN_MALE ((HUMAN << 8) | MALE) diff --git a/common/races.h b/common/races.h index 04fdbbd32..4f4eea1cc 100644 --- a/common/races.h +++ b/common/races.h @@ -858,6 +858,8 @@ uint32 GetPlayerRaceBit(uint16 race_id); uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value); uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit); +float GetRaceGenderDefaultHeight(int race, int gender); + // player race-/gender-based model feature validators namespace PlayerAppearance diff --git a/common/ruletypes.h b/common/ruletypes.h index c3a8fd5dc..6484a8586 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -44,6 +44,7 @@ RULE_INT(Character, DeathExpLossMaxLevel, 255) // Any level greater than this wi RULE_INT(Character, DeathItemLossLevel, 10) RULE_INT(Character, DeathExpLossMultiplier, 3) //Adjust how much exp is lost RULE_BOOL(Character, UseDeathExpLossMult, false) //Adjust to use the above multiplier or to use code default. +RULE_BOOL(Character, UseOldRaceRezEffects, false) // older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore RULE_INT(Character, CorpseDecayTimeMS, 10800000) RULE_INT(Character, CorpseResTimeMS, 10800000) // time before cant res corpse(3 hours) RULE_BOOL(Character, LeaveCorpses, true) @@ -155,6 +156,7 @@ RULE_BOOL(Character, UseOldBindWound, false) // Uses the original bind wound beh RULE_BOOL(Character, GrantHoTTOnCreate, false) // Grant Health of Target's Target leadership AA on character creation RULE_BOOL(Character, UseOldConSystem, false) // Grant Health of Target's Target leadership AA on character creation RULE_BOOL(Character, OPClientUpdateVisualDebug, false) // Shows a pulse and forward directional particle each time the client sends its position to server +RULE_BOOL(Character, PetsUseReagents, true) //Pets use reagent on spells RULE_CATEGORY_END() RULE_CATEGORY(Mercs) @@ -197,6 +199,7 @@ RULE_CATEGORY(Pets) RULE_REAL(Pets, AttackCommandRange, 150) RULE_BOOL(Pets, UnTargetableSwarmPet, false) RULE_REAL(Pets, PetPowerLevelCap, 10) // Max number of levels your pet can go up with pet power +RULE_BOOL(Pets, CanTakeNoDrop, false) // Can everyone trade nodrop gear to pets RULE_CATEGORY_END() RULE_CATEGORY(GM) @@ -231,6 +234,7 @@ RULE_INT(World, TitaniumStartZoneID, -1) //Sets the Starting Zone for Titanium C RULE_INT(World, ExpansionSettings, 16383) // Sets the expansion settings for the server, This is sent on login to world and affects client expansion settings. Defaults to all expansions enabled up to TSS. RULE_BOOL(World, UseClientBasedExpansionSettings, true) // if true it will overrule World, ExpansionSettings and set someone's expansion based on the client they're using RULE_INT(World, PVPSettings, 0) // Sets the PVP settings for the server, 1 = Rallos Zek RuleSet, 2 = Tallon/Vallon Zek Ruleset, 4 = Sullon Zek Ruleset, 6 = Discord Ruleset, anything above 6 is the Discord Ruleset without the no-drop restrictions removed. TODO: Edit IsAttackAllowed in Zone to accomodate for these rules. +RULE_INT(World, PVPMinLevel, 0) // minimum level to pvp RULE_BOOL (World, IsGMPetitionWindowEnabled, false) RULE_INT (World, FVNoDropFlag, 0) // Sets the Firiona Vie settings on the client. If set to 2, the flag will be set for GMs only, allowing trading of no-drop items. RULE_BOOL (World, IPLimitDisconnectAll, false) @@ -273,17 +277,10 @@ RULE_INT(Zone, GlobalLootMultiplier, 1) // Sets Global Loot drop multiplier for RULE_CATEGORY_END() RULE_CATEGORY(Map) -//enable these to help prevent mob hopping when they are pathing -RULE_BOOL(Map, FixPathingZWhenLoading, true) //increases zone boot times a bit to reduce hopping. -RULE_BOOL(Map, FixPathingZAtWaypoints, false) //alternative to `WhenLoading`, accomplishes the same thing but does it at each waypoint instead of once at boot time. -RULE_BOOL(Map, FixPathingZWhenMoving, false) //very CPU intensive, but helps hopping with widely spaced waypoints. RULE_BOOL(Map, FixPathingZOnSendTo, false) //try to repair Z coords in the SendTo routine as well. RULE_BOOL(Map, FixZWhenMoving, true) // Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor) RULE_BOOL(Map, MobZVisualDebug, false) // Displays spell effects determining whether or not NPC is hitting Best Z calcs (blue for hit, red for miss) -RULE_REAL(Map, FixPathingZMaxDeltaMoving, 20) //at runtime while pathing: max change in Z to allow the BestZ code to apply. -RULE_REAL(Map, FixPathingZMaxDeltaWaypoint, 20) //at runtime at each waypoint: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20) //at runtime in SendTo: max change in Z to allow the BestZ code to apply. -RULE_REAL(Map, FixPathingZMaxDeltaLoading, 45) //while loading each waypoint: max change in Z to allow the BestZ code to apply. RULE_INT(Map, FindBestZHeightAdjust, 1) // Adds this to the current Z before seeking the best Z position RULE_CATEGORY_END() @@ -405,6 +402,7 @@ RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spr RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target. RULE_BOOL(Spells, OldRainTargets, false) // use old incorrectly implemented max targets for rains +RULE_BOOL(Spells, NPCSpellPush, false) // enable spell push on NPCs RULE_CATEGORY_END() RULE_CATEGORY(Combat) @@ -507,6 +505,7 @@ RULE_INT(Combat, NPCAssistCapTimer, 6000) // Time in milliseconds a NPC will tak RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF RULE_BOOL(Combat, ClassicMasterWu, false) // classic master wu uses a random special, modern doesn't RULE_INT(Combat, LevelToStopDamageCaps, 0) // 1 will effectively disable them, 20 should give basically same results as old incorrect system +RULE_BOOL(Combat, ClassicNPCBackstab, false) // true disables npc facestab - npcs get normal attack if not behind RULE_CATEGORY_END() RULE_CATEGORY(NPC) @@ -673,6 +672,12 @@ RULE_CATEGORY_END() RULE_CATEGORY(AA) RULE_INT(AA, ExpPerPoint, 23976503) //Amount of exp per AA. Is the same as the amount of exp to go from level 51 to level 52. RULE_BOOL(AA, Stacking, true) //Allow AA that belong to the same group to stack on SOF+ clients. +RULE_BOOL(AA, NormalizedAAEnabled, false) // TSS+ change to AA that normalizes AA XP to a fixed # of white con kills independent of level. +RULE_INT(AA, NormalizedAANumberOfWhiteConPerAA, 25) // The number of white con kills per AA point. +RULE_BOOL(AA, ModernAAScalingEnabled, false) // Are we linearly scaling AA XP based on total # of earned AA? +RULE_REAL(AA, ModernAAScalingStartPercent, 1000) // 1000% or 10x AA XP at the start of the scaling range +RULE_INT(AA, ModernAAScalingAAMinimum, 0) // The minimum number of earned AA before AA XP scaling begins. +RULE_INT(AA, ModernAAScalingAALimit, 4000) // The number of earned AA when AA XP scaling ends RULE_CATEGORY_END() RULE_CATEGORY(Console) @@ -718,6 +723,12 @@ RULE_BOOL(Client, UseLiveFactionMessage, false) // Allows players to see faction RULE_BOOL(Client, UseLiveBlockedMessage, false) // Allows players to see faction adjustments like Live RULE_CATEGORY_END() +RULE_CATEGORY(Bugs) +RULE_BOOL(Bugs, ReportingSystemActive, true) // Activates bug reporting +RULE_BOOL(Bugs, UseOldReportingMethod, true) // Forces the use of the old bug reporting system +RULE_BOOL(Bugs, DumpTargetEntity, false) // Dumps the target entity, if one is provided +RULE_CATEGORY_END() + #undef RULE_CATEGORY #undef RULE_INT #undef RULE_REAL diff --git a/common/say_link.cpp b/common/say_link.cpp index 923e53407..e2b43c107 100644 --- a/common/say_link.cpp +++ b/common/say_link.cpp @@ -29,10 +29,10 @@ bool EQEmu::saylink::DegenerateLinkBody(SayLinkBody_Struct& say_link_body_struct, const std::string& say_link_body) { memset(&say_link_body_struct, 0, sizeof(say_link_body_struct)); - if (say_link_body.length() != EQEmu::legacy::TEXT_LINK_BODY_LENGTH) + if (say_link_body.length() != EQEmu::constants::SayLinkBodySize) return false; - say_link_body_struct.unknown_1 = (uint8)strtol(say_link_body.substr(0, 1).c_str(), nullptr, 16); + say_link_body_struct.action_id = (uint8)strtol(say_link_body.substr(0, 1).c_str(), nullptr, 16); say_link_body_struct.item_id = (uint32)strtol(say_link_body.substr(1, 5).c_str(), nullptr, 16); say_link_body_struct.augment_1 = (uint32)strtol(say_link_body.substr(6, 5).c_str(), nullptr, 16); say_link_body_struct.augment_2 = (uint32)strtol(say_link_body.substr(11, 5).c_str(), nullptr, 16); @@ -44,7 +44,7 @@ bool EQEmu::saylink::DegenerateLinkBody(SayLinkBody_Struct& say_link_body_struct say_link_body_struct.evolve_group = (uint32)strtol(say_link_body.substr(37, 4).c_str(), nullptr, 16); say_link_body_struct.evolve_level = (uint8)strtol(say_link_body.substr(41, 2).c_str(), nullptr, 16); say_link_body_struct.ornament_icon = (uint32)strtol(say_link_body.substr(43, 5).c_str(), nullptr, 16); - say_link_body_struct.hash = (int)strtol(say_link_body.substr(48, 8).c_str(), nullptr, 16); + say_link_body_struct.hash = (uint32)strtol(say_link_body.substr(48, 8).c_str(), nullptr, 16); return true; } @@ -53,7 +53,7 @@ bool EQEmu::saylink::GenerateLinkBody(std::string& say_link_body, const SayLinkB { say_link_body = StringFormat( "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X", - (0x0F & say_link_body_struct.unknown_1), + (0x0F & say_link_body_struct.action_id), (0x000FFFFF & say_link_body_struct.item_id), (0x000FFFFF & say_link_body_struct.augment_1), (0x000FFFFF & say_link_body_struct.augment_2), @@ -68,7 +68,7 @@ bool EQEmu::saylink::GenerateLinkBody(std::string& say_link_body, const SayLinkB (0xFFFFFFFF & say_link_body_struct.hash) ); - if (say_link_body.length() != EQEmu::legacy::TEXT_LINK_BODY_LENGTH) + if (say_link_body.length() != EQEmu::constants::SayLinkBodySize) return false; return true; @@ -79,7 +79,7 @@ EQEmu::SayLinkEngine::SayLinkEngine() Reset(); } -std::string EQEmu::SayLinkEngine::GenerateLink() +const std::string& EQEmu::SayLinkEngine::GenerateLink() { m_Link.clear(); m_LinkBody.clear(); @@ -88,18 +88,26 @@ std::string EQEmu::SayLinkEngine::GenerateLink() generate_body(); generate_text(); - if ((m_LinkBody.length() == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) { + if ((m_LinkBody.length() == EQEmu::constants::SayLinkBodySize) && (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)) { + if ((m_Link.length() == 0) || (m_Link.length() > (EQEmu::constants::SayLinkMaximumSize))) { m_Error = true; m_Link = ""; - Log(Logs::General, Logs::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()); + Log(Logs::General, Logs::Error, "SayLinkEngine::GenerateLink() failed to generate a useable say link"); + Log(Logs::General, Logs::Error, ">> LinkType: %i, Lengths: {link: %u(%u), body: %u(%u), text: %u(%u)}", + m_LinkType, + m_Link.length(), + EQEmu::constants::SayLinkMaximumSize, + m_LinkBody.length(), + EQEmu::constants::SayLinkBodySize, + m_LinkText.length(), + EQEmu::constants::SayLinkTextSize + ); Log(Logs::General, Logs::Error, ">> LinkBody: %s", m_LinkBody.c_str()); Log(Logs::General, Logs::Error, ">> LinkText: %s", m_LinkText.c_str()); } @@ -113,20 +121,10 @@ void EQEmu::SayLinkEngine::Reset() m_ItemData = nullptr; m_LootData = nullptr; m_ItemInst = nullptr; - m_Proxy_unknown_1 = 0; - m_ProxyItemID = 0; - m_ProxyAugment1ID = 0; - m_ProxyAugment2ID = 0; - m_ProxyAugment3ID = 0; - m_ProxyAugment4ID = 0; - m_ProxyAugment5ID = 0; - m_ProxyAugment6ID = 0; - m_ProxyIsEvolving = 0; - m_ProxyEvolveGroup = 0; - m_ProxyEvolveLevel = 0; - m_ProxyOrnamentIcon = 0; - m_ProxyHash = 0; - m_ProxyText = nullptr; + + memset(&m_LinkBodyStruct, 0, sizeof(SayLinkBody_Struct)); + memset(&m_LinkProxyStruct, 0, sizeof(SayLinkProxy_Struct)); + m_TaskUse = false; m_Link.clear(); m_LinkBody.clear(); @@ -194,32 +192,32 @@ void EQEmu::SayLinkEngine::generate_body() break; } - if (m_Proxy_unknown_1) - m_LinkBodyStruct.unknown_1 = m_Proxy_unknown_1; - if (m_ProxyItemID) - m_LinkBodyStruct.item_id = m_ProxyItemID; - if (m_ProxyAugment1ID) - m_LinkBodyStruct.augment_1 = m_ProxyAugment1ID; - if (m_ProxyAugment2ID) - m_LinkBodyStruct.augment_2 = m_ProxyAugment2ID; - if (m_ProxyAugment3ID) - m_LinkBodyStruct.augment_3 = m_ProxyAugment3ID; - if (m_ProxyAugment4ID) - m_LinkBodyStruct.augment_4 = m_ProxyAugment4ID; - if (m_ProxyAugment5ID) - m_LinkBodyStruct.augment_5 = m_ProxyAugment5ID; - if (m_ProxyAugment6ID) - m_LinkBodyStruct.augment_6 = m_ProxyAugment6ID; - if (m_ProxyIsEvolving) - m_LinkBodyStruct.is_evolving = m_ProxyIsEvolving; - if (m_ProxyEvolveGroup) - m_LinkBodyStruct.evolve_group = m_ProxyEvolveGroup; - if (m_ProxyEvolveLevel) - m_LinkBodyStruct.evolve_level = m_ProxyEvolveLevel; - if (m_ProxyOrnamentIcon) - m_LinkBodyStruct.ornament_icon = m_ProxyOrnamentIcon; - if (m_ProxyHash) - m_LinkBodyStruct.hash = m_ProxyHash; + if (m_LinkProxyStruct.action_id) + m_LinkBodyStruct.action_id = m_LinkProxyStruct.action_id; + if (m_LinkProxyStruct.item_id) + m_LinkBodyStruct.item_id = m_LinkProxyStruct.item_id; + if (m_LinkProxyStruct.augment_1) + m_LinkBodyStruct.augment_1 = m_LinkProxyStruct.augment_1; + if (m_LinkProxyStruct.augment_2) + m_LinkBodyStruct.augment_2 = m_LinkProxyStruct.augment_2; + if (m_LinkProxyStruct.augment_3) + m_LinkBodyStruct.augment_3 = m_LinkProxyStruct.augment_3; + if (m_LinkProxyStruct.augment_4) + m_LinkBodyStruct.augment_4 = m_LinkProxyStruct.augment_4; + if (m_LinkProxyStruct.augment_5) + m_LinkBodyStruct.augment_5 = m_LinkProxyStruct.augment_5; + if (m_LinkProxyStruct.augment_6) + m_LinkBodyStruct.augment_6 = m_LinkProxyStruct.augment_6; + if (m_LinkProxyStruct.is_evolving) + m_LinkBodyStruct.is_evolving = m_LinkProxyStruct.is_evolving; + if (m_LinkProxyStruct.evolve_group) + m_LinkBodyStruct.evolve_group = m_LinkProxyStruct.evolve_group; + if (m_LinkProxyStruct.evolve_level) + m_LinkBodyStruct.evolve_level = m_LinkProxyStruct.evolve_level; + if (m_LinkProxyStruct.ornament_icon) + m_LinkBodyStruct.ornament_icon = m_LinkProxyStruct.ornament_icon; + if (m_LinkProxyStruct.hash) + m_LinkBodyStruct.hash = m_LinkProxyStruct.hash; if (m_TaskUse) @@ -227,7 +225,7 @@ void EQEmu::SayLinkEngine::generate_body() m_LinkBody = StringFormat( "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X", - (0x0F & m_LinkBodyStruct.unknown_1), + (0x0F & m_LinkBodyStruct.action_id), (0x000FFFFF & m_LinkBodyStruct.item_id), (0x000FFFFF & m_LinkBodyStruct.augment_1), (0x000FFFFF & m_LinkBodyStruct.augment_2), @@ -245,8 +243,8 @@ void EQEmu::SayLinkEngine::generate_body() void EQEmu::SayLinkEngine::generate_text() { - if (m_ProxyText != nullptr) { - m_LinkText = m_ProxyText; + if (m_LinkProxyStruct.text != nullptr) { + m_LinkText = m_LinkProxyStruct.text; return; } diff --git a/common/say_link.h b/common/say_link.h index 6bc3e5535..55e3a8237 100644 --- a/common/say_link.h +++ b/common/say_link.h @@ -47,7 +47,7 @@ namespace EQEmu } /*saylink*/ struct SayLinkBody_Struct { - uint8 unknown_1; /* %1X */ + uint8 action_id; /* %1X */ uint32 item_id; /* %05X */ uint32 augment_1; /* %05X */ uint32 augment_2; /* %05X */ @@ -56,13 +56,18 @@ namespace EQEmu uint32 augment_5; /* %05X */ uint32 augment_6; /* %05X */ uint8 is_evolving; /* %1X */ - uint32 evolve_group; /* %05X */ + uint32 evolve_group; /* %04X */ uint8 evolve_level; /* %02X */ uint32 ornament_icon; /* %05X */ - int hash; /* %08X */ + uint32 hash; /* %08X */ + }; + + struct SayLinkProxy_Struct : SayLinkBody_Struct { + const char* text; }; class SayLinkEngine { + // TODO: consider methods for direct 'saylink' assignments public: SayLinkEngine(); @@ -72,29 +77,29 @@ namespace EQEmu void SetItemInst(const ItemInstance* item_inst) { m_ItemInst = item_inst; } // mainly for saylinks..but, not limited to - void SetProxyUnknown1(uint8 proxy_unknown_1) { m_Proxy_unknown_1 = proxy_unknown_1; } - void SetProxyItemID(uint32 proxy_item_id) { m_ProxyItemID = proxy_item_id; } - void SetProxyAugment1ID(uint32 proxy_augment_id) { m_ProxyAugment1ID = proxy_augment_id; } - void SetProxyAugment2ID(uint32 proxy_augment_id) { m_ProxyAugment2ID = proxy_augment_id; } - void SetProxyAugment3ID(uint32 proxy_augment_id) { m_ProxyAugment3ID = proxy_augment_id; } - void SetProxyAugment4ID(uint32 proxy_augment_id) { m_ProxyAugment4ID = proxy_augment_id; } - void SetProxyAugment5ID(uint32 proxy_augment_id) { m_ProxyAugment5ID = proxy_augment_id; } - void SetProxyAugment6ID(uint32 proxy_augment_id) { m_ProxyAugment6ID = proxy_augment_id; } - void SetProxyIsEvolving(uint8 proxy_is_evolving) { m_ProxyIsEvolving = proxy_is_evolving; } - void SetProxyEvolveGroup(uint32 proxy_evolve_group) { m_ProxyEvolveGroup = proxy_evolve_group; } - void SetProxyEvolveLevel(uint8 proxy_evolve_level) { m_ProxyEvolveLevel = proxy_evolve_level; } - void SetProxyOrnamentIcon(uint32 proxy_ornament_icon) { m_ProxyOrnamentIcon = proxy_ornament_icon; } - void SetProxyHash(int proxy_hash) { m_ProxyHash = proxy_hash; } + void SetProxyActionID(uint8 proxy_action_id) { m_LinkProxyStruct.action_id = proxy_action_id; } // should always be '0' + void SetProxyItemID(uint32 proxy_item_id) { m_LinkProxyStruct.item_id = proxy_item_id; } + void SetProxyAugment1ID(uint32 proxy_augment_id) { m_LinkProxyStruct.augment_1 = proxy_augment_id; } + void SetProxyAugment2ID(uint32 proxy_augment_id) { m_LinkProxyStruct.augment_2 = proxy_augment_id; } + void SetProxyAugment3ID(uint32 proxy_augment_id) { m_LinkProxyStruct.augment_3 = proxy_augment_id; } + void SetProxyAugment4ID(uint32 proxy_augment_id) { m_LinkProxyStruct.augment_4 = proxy_augment_id; } + void SetProxyAugment5ID(uint32 proxy_augment_id) { m_LinkProxyStruct.augment_5 = proxy_augment_id; } + void SetProxyAugment6ID(uint32 proxy_augment_id) { m_LinkProxyStruct.augment_6 = proxy_augment_id; } + void SetProxyIsEvolving(uint8 proxy_is_evolving) { m_LinkProxyStruct.is_evolving = proxy_is_evolving; } + void SetProxyEvolveGroup(uint32 proxy_evolve_group) { m_LinkProxyStruct.evolve_group = proxy_evolve_group; } + void SetProxyEvolveLevel(uint8 proxy_evolve_level) { m_LinkProxyStruct.evolve_level = proxy_evolve_level; } + void SetProxyOrnamentIcon(uint32 proxy_ornament_icon) { m_LinkProxyStruct.ornament_icon = proxy_ornament_icon; } + void SetProxyHash(uint32 proxy_hash) { m_LinkProxyStruct.hash = proxy_hash; } - void SetProxyText(const char* proxy_text) { m_ProxyText = proxy_text; } // overrides standard text use + void SetProxyText(const char* proxy_text) { m_LinkProxyStruct.text = proxy_text; } // overrides standard text use void SetTaskUse() { m_TaskUse = true; } - std::string GenerateLink(); + const std::string& GenerateLink(); bool LinkError() { return m_Error; } - std::string Link() { return m_Link; } // contains full string format: '/12x' '' '' '/12x' - std::string LinkBody() { return m_LinkBody; } // contains string format: '' - std::string LinkText() { return m_LinkText; } // contains string format: '' + const std::string& Link() { return m_Link; } // contains full string format: '\x12' '' '' '\x12' + const std::string& LinkBody() { return m_LinkBody; } // contains string format: '' + const std::string& LinkText() { return m_LinkText; } // contains string format: '' void Reset(); @@ -106,23 +111,9 @@ namespace EQEmu const ItemData* m_ItemData; const ServerLootItem_Struct* m_LootData; const ItemInstance* m_ItemInst; - - uint8 m_Proxy_unknown_1; - uint32 m_ProxyItemID; - uint32 m_ProxyAugment1ID; - uint32 m_ProxyAugment2ID; - uint32 m_ProxyAugment3ID; - uint32 m_ProxyAugment4ID; - uint32 m_ProxyAugment5ID; - uint32 m_ProxyAugment6ID; - uint8 m_ProxyIsEvolving; - uint32 m_ProxyEvolveGroup; - uint8 m_ProxyEvolveLevel; - uint32 m_ProxyOrnamentIcon; - int m_ProxyHash; - const char* m_ProxyText; - bool m_TaskUse; SayLinkBody_Struct m_LinkBodyStruct; + SayLinkProxy_Struct m_LinkProxyStruct; + bool m_TaskUse; std::string m_Link; std::string m_LinkBody; std::string m_LinkText; diff --git a/common/servertalk.h b/common/servertalk.h index f5965cd74..e1d019fc4 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -190,6 +190,8 @@ #define ServerOP_ReloadLogs 0x4010 #define ServerOP_ReloadPerlExportSettings 0x4011 #define ServerOP_CZSetEntityVariableByClientName 0x4012 +#define ServerOP_UCSServerStatusRequest 0x4013 +#define ServerOP_UCSServerStatusReply 0x4014 /* Query Server OP Codes */ #define ServerOP_QSPlayerLogTrades 0x5010 #define ServerOP_QSPlayerLogHandins 0x5011 @@ -1278,6 +1280,17 @@ struct ServerRequestTellQueue_Struct { char name[64]; }; +struct UCSServerStatus_Struct { + uint8 available; // non-zero=true, 0=false + union { + struct { + uint16 port; + uint16 unused; + }; + uint32 timestamp; + }; +}; + #pragma pack() #endif diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 09c936425..a4c6e54d1 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -110,6 +110,41 @@ uint32 SharedDatabase::GetTotalTimeEntitledOnAccount(uint32 AccountID) { return EntitledTime; } +void SharedDatabase::SetMailKey(int CharID, int IPAddress, int MailKey) +{ + char MailKeyString[17]; + + if (RuleB(Chat, EnableMailKeyIPVerification) == true) + sprintf(MailKeyString, "%08X%08X", IPAddress, MailKey); + else + sprintf(MailKeyString, "%08X", MailKey); + + std::string query = StringFormat("UPDATE character_data SET mailkey = '%s' WHERE id = '%i'", + MailKeyString, CharID); + auto results = QueryDatabase(query); + if (!results.Success()) + Log(Logs::General, Logs::Error, "SharedDatabase::SetMailKey(%i, %s) : %s", CharID, MailKeyString, results.ErrorMessage().c_str()); + +} + +std::string SharedDatabase::GetMailKey(int CharID, bool key_only) +{ + std::string query = StringFormat("SELECT `mailkey` FROM `character_data` WHERE `id`='%i' LIMIT 1", CharID); + auto results = QueryDatabase(query); + if (!results.Success()) { + Log(Logs::Detail, Logs::MySQLError, "Error retrieving mailkey from database: %s", results.ErrorMessage().c_str()); + return std::string(); + } + + auto row = results.begin(); + std::string mail_key = row[0]; + + if (mail_key.length() > 8 && key_only) + return mail_key.substr(8); + else + return mail_key; +} + bool SharedDatabase::SaveCursor(uint32 char_id, std::list::const_iterator &start, std::list::const_iterator &end) { // Delete cursor items diff --git a/common/shareddb.h b/common/shareddb.h index d3d8020a1..bbd8dc9a0 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -72,6 +72,8 @@ class SharedDatabase : public Database void SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* message); bool GetCommandSettings(std::map>> &command_settings); uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID); + void SetMailKey(int CharID, int IPAddress, int MailKey); + std::string GetMailKey(int CharID, bool key_only = false); /* Character InventoryProfile diff --git a/common/spdat.h b/common/spdat.h index 0f9e7a47a..c6aab7e7e 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -73,6 +73,8 @@ enum SpellTypes : uint32 SpellTypes_Detrimental = (SpellType_Nuke | SpellType_Root | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Charm | SpellType_Debuff | SpellType_Slow), SpellTypes_Beneficial = (SpellType_Heal | SpellType_Buff | SpellType_Escape | SpellType_Pet | SpellType_InCombatBuff | SpellType_Cure | SpellType_HateRedux | SpellType_InCombatBuffSong | SpellType_OutOfCombatBuffSong | SpellType_PreCombatBuff | SpellType_PreCombatBuffSong), + SpellTypes_Innate = (SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root), + SpellType_Any = 0xFFFFFFFF }; @@ -970,7 +972,6 @@ bool IsCastWhileInvis(uint16 spell_id); bool IsEffectIgnoredInStacking(int spa); int CalcPetHp(int levelb, int classb, int STA = 75); -const char *GetRandPetName(); int GetSpellEffectDescNum(uint16 spell_id); DmgShieldType GetDamageShieldType(uint16 spell_id, int32 DSType = 0); bool DetrimentalSpellAllowsRest(uint16 spell_id); diff --git a/common/version.h b/common/version.h index 108ce784b..e003dc33f 100644 --- a/common/version.h +++ b/common/version.h @@ -30,9 +30,9 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9115 +#define CURRENT_BINARY_DATABASE_VERSION 9122 #ifdef BOTS - #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017 + #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9018 #else #define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0 #endif diff --git a/libs/format/fmt/format.h b/libs/format/fmt/format.h index 47a8b74d8..9c2827d46 100644 --- a/libs/format/fmt/format.h +++ b/libs/format/fmt/format.h @@ -1719,6 +1719,8 @@ FMT_DEFINE_INT_FORMATTERS(unsigned long) FMT_DEFINE_INT_FORMATTERS(LongLong) FMT_DEFINE_INT_FORMATTERS(ULongLong) +#define CHAR_WIDTH 1 + /** \rst Returns a string formatter that pads the formatted argument with the fill @@ -1823,7 +1825,7 @@ class ArgFormatterBase : public ArgVisitor { typedef typename BasicWriter::CharPtr CharPtr; Char fill = internal::CharTraits::cast(spec_.fill()); CharPtr out = CharPtr(); - const unsigned CHAR_WIDTH = 1; + if (spec_.width_ > CHAR_WIDTH) { out = writer_.grow_buffer(spec_.width_); if (spec_.align_ == ALIGN_RIGHT) { diff --git a/queryserv/queryservconfig.h b/queryserv/queryservconfig.h index b48ecdecd..9878493f7 100644 --- a/queryserv/queryservconfig.h +++ b/queryserv/queryservconfig.h @@ -46,7 +46,7 @@ public: _chat_config=new queryservconfig; _config=_chat_config; - return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server"); + return _config->parseFile(); } }; diff --git a/ucs/chatchannel.cpp b/ucs/chatchannel.cpp index 16403c295..11a000712 100644 --- a/ucs/chatchannel.cpp +++ b/ucs/chatchannel.cpp @@ -28,6 +28,10 @@ extern Database database; extern uint32 ChatMessagesSent; +void ServerToClient45SayLink(std::string& clientSayLink, const std::string& serverSayLink); +void ServerToClient50SayLink(std::string& clientSayLink, const std::string& serverSayLink); +void ServerToClient55SayLink(std::string& clientSayLink, const std::string& serverSayLink); + ChatChannel::ChatChannel(std::string inName, std::string inOwner, std::string inPassword, bool inPermanent, int inMinimumStatus) : DeleteTimer(0) { @@ -384,6 +388,8 @@ void ChatChannel::SendMessageToChannel(std::string Message, Client* Sender) { if(!Sender) return; + std::string cv_messages[EQEmu::versions::ClientVersionCount]; + ChatMessagesSent++; LinkedListIterator iterator(ClientsInChannel); @@ -398,7 +404,28 @@ void ChatChannel::SendMessageToChannel(std::string Message, Client* Sender) { { Log(Logs::Detail, Logs::UCS_Server, "Sending message to %s from %s", ChannelClient->GetName().c_str(), Sender->GetName().c_str()); - ChannelClient->SendChannelMessage(Name, Message, Sender); + + if (cv_messages[static_cast(ChannelClient->GetClientVersion())].length() == 0) { + switch (ChannelClient->GetClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + ServerToClient45SayLink(cv_messages[static_cast(ChannelClient->GetClientVersion())], Message); + break; + case EQEmu::versions::ClientVersion::SoF: + case EQEmu::versions::ClientVersion::SoD: + case EQEmu::versions::ClientVersion::UF: + ServerToClient50SayLink(cv_messages[static_cast(ChannelClient->GetClientVersion())], Message); + break; + case EQEmu::versions::ClientVersion::RoF: + ServerToClient55SayLink(cv_messages[static_cast(ChannelClient->GetClientVersion())], Message); + break; + case EQEmu::versions::ClientVersion::RoF2: + default: + cv_messages[static_cast(ChannelClient->GetClientVersion())] = Message; + break; + } + } + + ChannelClient->SendChannelMessage(Name, cv_messages[static_cast(ChannelClient->GetClientVersion())], Sender); } iterator.Advance(); @@ -655,3 +682,118 @@ std::string CapitaliseName(std::string inString) { return NormalisedName; } +void ServerToClient45SayLink(std::string& clientSayLink, const std::string& serverSayLink) { + if (serverSayLink.find('\x12') == std::string::npos) { + clientSayLink = serverSayLink; + return; + } + + auto segments = SplitString(serverSayLink, '\x12'); + + for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { + if (segment_iter & 1) { + if (segments[segment_iter].length() <= 56) { + clientSayLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } + + // 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: ^^^^^ ^ ^^^^^ + + clientSayLink.push_back('\x12'); + clientSayLink.append(segments[segment_iter].substr(0, 31)); + clientSayLink.append(segments[segment_iter].substr(36, 5)); + + if (segments[segment_iter][41] == '0') + clientSayLink.push_back(segments[segment_iter][42]); + else + clientSayLink.push_back('F'); + + clientSayLink.append(segments[segment_iter].substr(48)); + clientSayLink.push_back('\x12'); + } + else { + clientSayLink.append(segments[segment_iter]); + } + } +} + +void ServerToClient50SayLink(std::string& clientSayLink, const std::string& serverSayLink) { + if (serverSayLink.find('\x12') == std::string::npos) { + clientSayLink = serverSayLink; + return; + } + + auto segments = SplitString(serverSayLink, '\x12'); + + for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { + if (segment_iter & 1) { + if (segments[segment_iter].length() <= 56) { + clientSayLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } + + // 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: ^^^^^ ^ + + clientSayLink.push_back('\x12'); + clientSayLink.append(segments[segment_iter].substr(0, 31)); + clientSayLink.append(segments[segment_iter].substr(36, 5)); + + if (segments[segment_iter][41] == '0') + clientSayLink.push_back(segments[segment_iter][42]); + else + clientSayLink.push_back('F'); + + clientSayLink.append(segments[segment_iter].substr(43)); + clientSayLink.push_back('\x12'); + } + else { + clientSayLink.append(segments[segment_iter]); + } + } +} + +void ServerToClient55SayLink(std::string& clientSayLink, const std::string& serverSayLink) { + if (serverSayLink.find('\x12') == std::string::npos) { + clientSayLink = serverSayLink; + return; + } + + auto segments = SplitString(serverSayLink, '\x12'); + + for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { + if (segment_iter & 1) { + if (segments[segment_iter].length() <= 56) { + clientSayLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } + + // 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: ^ + + clientSayLink.push_back('\x12'); + clientSayLink.append(segments[segment_iter].substr(0, 41)); + + if (segments[segment_iter][41] == '0') + clientSayLink.push_back(segments[segment_iter][42]); + else + clientSayLink.push_back('F'); + + clientSayLink.append(segments[segment_iter].substr(43)); + clientSayLink.push_back('\x12'); + } + else { + clientSayLink.append(segments[segment_iter]); + } + } +} diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp index 998410ec1..130914952 100644 --- a/ucs/clientlist.cpp +++ b/ucs/clientlist.cpp @@ -513,6 +513,7 @@ Client::Client(std::shared_ptr eqs) { GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS)); TypeOfConnection = ConnectionTypeUnknown; + ClientVersion_ = EQEmu::versions::ClientVersion::Unknown; UnderfootOrLater = false; } @@ -681,6 +682,7 @@ void Clientlist::Process() it = ClientChatConnections.erase(it); continue; } + ++it; } } @@ -2134,34 +2136,62 @@ void Client::SetConnectionType(char c) { switch (c) { - case 'S': - { - TypeOfConnection = ConnectionTypeCombined; - Log(Logs::Detail, Logs::UCS_Server, "Connection type is Combined (SoF/SoD)"); - break; - } - case 'U': - { - TypeOfConnection = ConnectionTypeCombined; - UnderfootOrLater = true; - Log(Logs::Detail, Logs::UCS_Server, "Connection type is Combined (Underfoot+)"); - break; - } - case 'M': - { - TypeOfConnection = ConnectionTypeMail; - Log(Logs::Detail, Logs::UCS_Server, "Connection type is Mail (6.2 or Titanium client)"); - break; - } - case 'C': + case EQEmu::versions::ucsTitaniumChat: { TypeOfConnection = ConnectionTypeChat; - Log(Logs::Detail, Logs::UCS_Server, "Connection type is Chat (6.2 or Titanium client)"); + ClientVersion_ = EQEmu::versions::ClientVersion::Titanium; + Log(Logs::Detail, Logs::UCS_Server, "Connection type is Chat (Titanium)"); + break; + } + case EQEmu::versions::ucsTitaniumMail: + { + TypeOfConnection = ConnectionTypeMail; + ClientVersion_ = EQEmu::versions::ClientVersion::Titanium; + Log(Logs::Detail, Logs::UCS_Server, "Connection type is Mail (Titanium)"); + break; + } + case EQEmu::versions::ucsSoFCombined: + { + TypeOfConnection = ConnectionTypeCombined; + ClientVersion_ = EQEmu::versions::ClientVersion::SoF; + Log(Logs::Detail, Logs::UCS_Server, "Connection type is Combined (SoF)"); + break; + } + case EQEmu::versions::ucsSoDCombined: + { + TypeOfConnection = ConnectionTypeCombined; + ClientVersion_ = EQEmu::versions::ClientVersion::SoD; + Log(Logs::Detail, Logs::UCS_Server, "Connection type is Combined (SoD)"); + break; + } + case EQEmu::versions::ucsUFCombined: + { + TypeOfConnection = ConnectionTypeCombined; + ClientVersion_ = EQEmu::versions::ClientVersion::UF; + UnderfootOrLater = true; + Log(Logs::Detail, Logs::UCS_Server, "Connection type is Combined (Underfoot)"); + break; + } + case EQEmu::versions::ucsRoFCombined: + { + TypeOfConnection = ConnectionTypeCombined; + ClientVersion_ = EQEmu::versions::ClientVersion::RoF; + UnderfootOrLater = true; + Log(Logs::Detail, Logs::UCS_Server, "Connection type is Combined (RoF)"); + break; + } + case EQEmu::versions::ucsRoF2Combined: + { + TypeOfConnection = ConnectionTypeCombined; + ClientVersion_ = EQEmu::versions::ClientVersion::RoF2; + UnderfootOrLater = true; + Log(Logs::Detail, Logs::UCS_Server, "Connection type is Combined (RoF2)"); break; } default: { TypeOfConnection = ConnectionTypeUnknown; + ClientVersion_ = EQEmu::versions::ClientVersion::Unknown; Log(Logs::Detail, Logs::UCS_Server, "Connection type is unknown."); } } diff --git a/ucs/clientlist.h b/ucs/clientlist.h index 9b72df51a..6021c5c0e 100644 --- a/ucs/clientlist.h +++ b/ucs/clientlist.h @@ -139,8 +139,11 @@ public: std::string MailBoxName(); int GetMailBoxNumber() { return CurrentMailBox; } int GetMailBoxNumber(std::string CharacterName); + void SetConnectionType(char c); ConnectionType GetConnectionType() { return TypeOfConnection; } + EQEmu::versions::ClientVersion GetClientVersion() { return ClientVersion_; } + inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); } void SendNotification(int MailBoxNumber, std::string From, std::string Subject, int MessageID); void ChangeMailBox(int NewMailBox); @@ -167,7 +170,9 @@ private: Timer *GlobalChatLimiterTimer; //60 seconds int AttemptedMessages; bool ForceDisconnect; + ConnectionType TypeOfConnection; + EQEmu::versions::ClientVersion ClientVersion_; bool UnderfootOrLater; }; @@ -183,7 +188,6 @@ public: void ProcessOPMailCommand(Client *c, std::string CommandString); private: - EQ::Net::EQStreamManager *chatsf; std::list ClientChatConnections; diff --git a/ucs/ucsconfig.h b/ucs/ucsconfig.h index 23bc82a4f..5424dfeb5 100644 --- a/ucs/ucsconfig.h +++ b/ucs/ucsconfig.h @@ -46,7 +46,7 @@ public: _chat_config=new ucsconfig; _config=_chat_config; - return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server"); + return _config->parseFile(); } }; diff --git a/ucs/worldserver.cpp b/ucs/worldserver.cpp index 141211032..b3df5d99d 100644 --- a/ucs/worldserver.cpp +++ b/ucs/worldserver.cpp @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../common/misc_functions.h" #include "../common/packet_functions.h" #include "../common/md5.h" +#include "../common/string_util.h" #include "worldserver.h" #include "clientlist.h" #include "ucsconfig.h" @@ -41,6 +42,10 @@ extern Database database; void ProcessMailTo(Client *c, std::string from, std::string subject, std::string message); +void Client45ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink); +void Client50ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink); +void Client55ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink); + WorldServer::WorldServer() { m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "UCS", Config->SharedKey)); @@ -94,7 +99,26 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p) if (Message[0] == ';') { - c->SendChannelMessageByNumber(Message.substr(1, std::string::npos)); + std::string new_message; + switch (c->GetClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + Client45ToServerSayLink(new_message, Message.substr(1, std::string::npos)); + break; + case EQEmu::versions::ClientVersion::SoF: + case EQEmu::versions::ClientVersion::SoD: + case EQEmu::versions::ClientVersion::UF: + Client50ToServerSayLink(new_message, Message.substr(1, std::string::npos)); + break; + case EQEmu::versions::ClientVersion::RoF: + Client55ToServerSayLink(new_message, Message.substr(1, std::string::npos)); + break; + case EQEmu::versions::ClientVersion::RoF2: + default: + new_message = Message.substr(1, std::string::npos); + break; + } + + c->SendChannelMessageByNumber(new_message); } else if (Message[0] == '[') { @@ -116,3 +140,108 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p) } } } + +void Client45ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink) { + if (clientSayLink.find('\x12') == std::string::npos) { + serverSayLink = clientSayLink; + return; + } + + auto segments = SplitString(clientSayLink, '\x12'); + + for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { + if (segment_iter & 1) { + if (segments[segment_iter].length() <= 45) { + serverSayLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } + + // 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: ^^^^^ ^ ^^^^^ + + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 31)); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(31, 5)); + serverSayLink.push_back('0'); + serverSayLink.push_back(segments[segment_iter][36]); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(37)); + serverSayLink.push_back('\x12'); + } + else { + serverSayLink.append(segments[segment_iter]); + } + } +} + +void Client50ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink) { + if (clientSayLink.find('\x12') == std::string::npos) { + serverSayLink = clientSayLink; + return; + } + + auto segments = SplitString(clientSayLink, '\x12'); + + for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { + if (segment_iter & 1) { + if (segments[segment_iter].length() <= 50) { + serverSayLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } + + // 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: ^^^^^ ^ + + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 31)); + serverSayLink.append("00000"); + serverSayLink.append(segments[segment_iter].substr(31, 5)); + serverSayLink.push_back('0'); + serverSayLink.append(segments[segment_iter].substr(36)); + serverSayLink.push_back('\x12'); + } + else { + serverSayLink.append(segments[segment_iter]); + } + } +} + +void Client55ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink) { + if (clientSayLink.find('\x12') == std::string::npos) { + serverSayLink = clientSayLink; + return; + } + + auto segments = SplitString(clientSayLink, '\x12'); + + for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { + if (segment_iter & 1) { + if (segments[segment_iter].length() <= 55) { + serverSayLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } + + // 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: ^ + + serverSayLink.push_back('\x12'); + serverSayLink.append(segments[segment_iter].substr(0, 41)); + serverSayLink.push_back('0'); + serverSayLink.append(segments[segment_iter].substr(41)); + serverSayLink.push_back('\x12'); + } + else { + serverSayLink.append(segments[segment_iter]); + } + } +} diff --git a/utils/defaults/eqemu_config.json b/utils/defaults/eqemu_config.json new file mode 100755 index 000000000..73930ab9f --- /dev/null +++ b/utils/defaults/eqemu_config.json @@ -0,0 +1,8 @@ +{ + "server": { + "world": { + "shortname": "setme", + "longname": "I Forgot To Edit My Config" + } + } +} diff --git a/utils/defaults/eqemu_config.json.full b/utils/defaults/eqemu_config.json.full new file mode 100755 index 000000000..49cb9a5c6 --- /dev/null +++ b/utils/defaults/eqemu_config.json.full @@ -0,0 +1,54 @@ +{ + "server": { + "zones": { + "defaultstatus": "20", + "ports": { + "low": "7000", + "high": "7100" + } + }, + "database": { + "password": "eq", + "db": "eq", + "host": "127.0.0.1", + "port": "3306", + "username": "eq" + }, + "world": { + "shortname": "setme", + "longname": "I Forgot To Edit My Config", + "loginserver": { + "password": "", + "host": "login.eqemulator.net", + "port": "5998", + "account": "" + }, + "tcp": { + "port": "9000", + "telnet": "disable", + "ip": "127.0.0.1" + }, + "key": "some long random string", + "http": { + "mimefile": "mime.types", + "port": "9080", + "enabled": "false" + } + }, + "mailserver": { + "host": "channels.eqemulator.net", + "port": "7778" + }, + "chatserver": { + "host": "channels.eqemulator.net", + "port": "7778" + }, + "qsdatabase": { + "host": "127.0.0.1", + "port": "3306", + "username": "eq", + "password": "eq", + "db": "eq" + } + } +} diff --git a/utils/doc_scripts/perlparse/main.go b/utils/doc_scripts/perlparse/main.go new file mode 100644 index 000000000..0178a4cf5 --- /dev/null +++ b/utils/doc_scripts/perlparse/main.go @@ -0,0 +1,355 @@ +//Parses perl scripts +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "regexp" + "strings" + + "github.com/pkg/errors" +) + +func main() { + path := "../../../zone/embparser_api.cpp" + err := readFile(path) + if err != nil { + log.Panicf("Failed to read file: %s", err.Error()) + } +} + +type API struct { + Function string + Arguments []*Argument +} + +type Argument struct { + Name string + Type string + API *API +} + +func readFile(path string) (err error) { + inFile, err := os.Open(path) + if err != nil { + err = errors.Wrap(err, "Failed to open file") + } + defer inFile.Close() + scanner := bufio.NewScanner(inFile) + scanner.Split(bufio.ScanLines) + + arguments := map[string][]*Argument{} + functions := []*API{} + reg, err := regexp.Compile(`\]+|\[+|\?+|[...]+`) + if err != nil { + err = errors.Wrap(err, "Failed to compile regex") + return + } + regType, err := regexp.Compile(`(unsigned long|long|int32|bool|uint[0-9]+|int|auto|float|unsigned int|char[ \*]).+([. a-zA-Z]+=)`) + if err != nil { + err = errors.Wrap(err, "Failed to compile type regex") + return + } + + lastArguments := []*Argument{} + lastAPI := &API{} + lineNum := 0 + for scanner.Scan() { + lineNum++ + key := "" + line := scanner.Text() + if len(line) < 1 { + continue + } + if len(lastArguments) > 0 { //existing args to parse + for i, argument := range lastArguments { + key = fmt.Sprintf("ST(%d)", i) + if strings.Contains(line, key) { + //We found a definition argument line + if argument.Type != "" { + continue + } + + match := regType.FindStringSubmatch(line) + if len(match) < 2 { + continue + } + + //key = `int` + //function = line[strings.Index(line, key)+len(key):] + newType := "" + + switch v := strings.TrimSpace(match[1]); v { + case "int": + newType = "int" + case "int32": + newType = "int" + case "float": + newType = "float" + case "unsigned int": + newType = "uint" + case "uint32": + newType = "uint" + case "uint8": + newType = "uint" + case "uint": + newType = "uint" + case "bool": + newType = "bool" + case "uint16": + newType = "uint" + case "long": + newType = "long" + case "unsigned long": + newType = "unsigned long" + case "char": + newType = "string" + case "auto": + //Auto is tricky + if strings.Contains(line, "glm::vec4") { + newType = "float" + } + + default: + log.Printf(`Unknown type: "%s" on line %d`, v, lineNum) + } + //log.Println("Found arg type", newType, "on index", i, argument.Name) + lastArguments[i].Type = newType + } + } + } + + function := "" + + argLine := "" + args := []string{} + //Find line + key = `Perl_croak(aTHX_ "Usage:` + if strings.Contains(line, key) { + function = line[strings.Index(line, key)+len(key):] + } + + for _, argument := range lastArguments { + arguments[argument.Name] = append(arguments[argument.Name], argument) + } + + lastArguments = []*Argument{} + + //Trim off the endings + key = `");` + if strings.Contains(function, key) { + function = function[0:strings.Index(function, key)] + } + //Strip out the arguments + key = `(` + if strings.Contains(function, key) { + argLine = function[strings.Index(function, key)+len(key):] + function = function[0:strings.Index(function, key)] + key = `)` + if strings.Contains(argLine, key) { + argLine = argLine[:strings.Index(argLine, key)] + } + key = `=` + if strings.Contains(argLine, key) { + argLine = argLine[:strings.Index(argLine, key)] + } + argLine = reg.ReplaceAllString(argLine, "") + } + key = `,` + argLine = strings.TrimSpace(argLine) + + if strings.Contains(argLine, key) { + args = strings.Split(argLine, key) + } + + if len(function) < 1 { + continue + } + + newArgs := []string{} + for j, _ := range args { + args[j] = strings.TrimSpace(args[j]) + if len(args[j]) == 0 { + continue + } + newArgs = append(newArgs, args[j]) + } + + lastAPI = &API{ + Function: function, + } + + for _, arg := range newArgs { + argType, _ := knownTypes[arg] + argument := &Argument{ + Name: arg, + Type: argType, + API: lastAPI, + } + lastArguments = append(lastArguments, argument) + } + lastAPI.Arguments = lastArguments + + functions = append(functions, lastAPI) + } + + foundCount := 0 + failCount := 0 + for key, val := range arguments { + isMissing := false + line := "" + line = fmt.Sprintf("%s used by %d functions:", key, len(val)) + for _, fnc := range val { + line += fmt.Sprintf("%s(%s %s), ", fnc.API.Function, fnc.Type, key) + if fnc.Type == "" { + isMissing = true + } + } + if isMissing { + fmt.Println(line) + failCount++ + } else { + foundCount++ + } + } + log.Println(foundCount, "functions properly identified,", failCount, "have errors") + + line := "" + for _, api := range functions { + line += fmt.Sprintf("void %s(", strings.TrimSpace(api.Function)) + for _, argument := range api.Arguments { + line += fmt.Sprintf("%s %s, ", argument.Type, argument.Name) + } + if len(api.Arguments) > 0 { + line = line[0 : len(line)-2] + } + line += ")\n" + } + fmt.Println(line) + return +} + +var knownTypes = map[string]string{ + "activity_id": "uint", + "alt_mode": "bool", + "anim_num": "int", + "best_z": "float", + "buttons": "int", + "channel_id": "int", + "char_id": "int", + "charges": "int", + "class_id": "int", + "client_name": "string", + "color": "int", + "color_id": "int", + "condition_id": "int", + "copper": "int", + "count": "int", + "debug_level": "int", + "decay_time": "int", + "dest_heading": "float", + "dest_x": "float", + "dest_y": "float", + "dest_z": "float", + "distance": "int", + "door_id": "int", + "doorid": "uint", + "duration": "int", + "effect_id": "int", + "elite_material_id": "int", + "enforce_level_requirement": "bool", + "explore_id": "uint", + "faction_value": "int", + "fade_in": "int", + "fade_out": "int", + "fadeout": "uint", + "firstname": "string", + "from": "string", + "gender_id": "int", + "gold": "int", + "grid_id": "int", + "guild_rank_id": "int", + "heading": "float", + "hero_forge_model_id": "int", + "ignore_quest_update": "bool", + "instance_id": "int", + "int_unused": "int", + "int_value": "int", + "is_enabled": "bool", + "is_strict": "bool", + "item_id": "int", + "key": "string", + "language_id": "int", + "lastname": "string", + "leader_name": "string", + "level": "int", + "link_name": "string", + "macro_id": "int", + "max_level": "int", + "max_x": "float", + "max_y": "float", + "max_z": "float", + "message": "string", + "milliseconds": "int", + "min_level": "int", + "min_x": "float", + "min_y": "float", + "min_z": "float", + "name": "string", + "new_hour": "int", + "new_min": "int", + "node1": "int", + "node2": "int", + "npc_id": "int", + "npc_type_id": "int", + "object_type": "int", + "options": "int", + "platinum": "int", + "popup_id": "int", + "priority": "int", + "quantity": "int", + "race_id": "int", + "remove_item": "bool", + "requested_id": "int", + "reset_base": "bool", + "saveguard": "bool", + "seconds": "int", + "send_to_world": "bool", + "signal_id": "int", + "silent": "bool", + "silver": "int", + "size": "int", + "stat_id": "int", + "str_value": "string", + "subject": "string", + "target_enum": "string", + "target_id": "int", + "task": "int", + "task_id": "uint", + "task_id1": "int", + "task_id10": "int", + "task_id2": "int", + "task_set": "int", + "taskid": "int", + "taskid1": "int", + "taskid2": "int", + "taskid3": "int", + "taskid4": "int", + "teleport": "int", + "temp": "int", + "texture_id": "int", + "theme_id": "int", + "update_world": "int", + "updated_time_till_repop": "uint", + "version": "int", + "wait_ms": "int", + "window_title": "string", + "x": "float", + "y": "float", + "z": "float", + "zone_id": "int", + "zone_short": "string", + `task_id%i`: "int", +} diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index f3d4249c0..b348ea1ad 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -165,6 +165,7 @@ OP_GMNameChange=0x3077 # Was 0x4434 OP_GMLastName=0x4dd7 # Was 0x3077 # Misc Opcodes +OP_QueryUCSServerStatus=0x6964 OP_InspectRequest=0x23f1 OP_InspectAnswer=0x5794 OP_InspectMessageUpdate=0x3064 @@ -248,6 +249,7 @@ OP_AutoAttack=0x0d14 OP_AutoAttack2=0x3912 OP_Consume=0x4692 OP_MoveItem=0x62a2 +OP_MoveMultipleItems=0x55ef OP_DeleteItem=0x3eb5 OP_DeleteCharge=0x2d5b OP_ItemPacket=0x5e0e diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 420fcec70..9bd507bc1 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -164,6 +164,7 @@ OP_GMNameChange=0x035f OP_GMLastName=0x46ce # Misc Opcodes +OP_QueryUCSServerStatus=0x398f OP_InspectRequest=0x57bc OP_InspectAnswer=0x71ac OP_InspectMessageUpdate=0x4d25 @@ -247,6 +248,7 @@ OP_AutoAttack=0x109d OP_AutoAttack2=0x3526 OP_Consume=0x4b70 OP_MoveItem=0x32ee +OP_MoveMultipleItems=0x5623 OP_DeleteItem=0x18ad OP_DeleteCharge=0x01b8 OP_ItemPacket=0x368e diff --git a/utils/patches/patch_SoD.conf b/utils/patches/patch_SoD.conf index 0e8e36e02..ab8267a8a 100644 --- a/utils/patches/patch_SoD.conf +++ b/utils/patches/patch_SoD.conf @@ -165,6 +165,7 @@ OP_GMKill=0x6685 # C OP_GMNameChange=0x565d # C OP_GMLastName=0x3563 # C +OP_QueryUCSServerStatus=0x4036 OP_InspectAnswer=0x4938 # C OP_Action2=0x7e4d # C OP_Damage? OP_BeginCast=0x0d5a # C @@ -241,6 +242,7 @@ OP_AutoAttack=0x3d86 # C OP_AutoAttack2=0x4ca1 # C OP_Consume=0x7ce4 # C OP_MoveItem=0x7f56 # C +OP_MoveMultipleItems=0x4572 OP_DeleteItem=0x36f8 # C OP_DeleteCharge=0x1df9 # C OP_ItemPacket=0x34f8 # C diff --git a/utils/patches/patch_SoF.conf b/utils/patches/patch_SoF.conf index cae177bfc..6360617a2 100644 --- a/utils/patches/patch_SoF.conf +++ b/utils/patches/patch_SoF.conf @@ -237,6 +237,7 @@ OP_AutoAttack=0x3427 #Trevius 01/20/09 OP_AutoAttack2=0x6017 #Trevius 01/20/09 OP_Consume=0x729a #Trevius 02/08/09 OP_MoveItem=0x14B3 #Trevius 02/08/09 +OP_MoveMultipleItems=0x2d3e OP_DeleteItem=0x7DD4 #Xinu 03/08/09 0x41EE 0x018E 0x070C OP_DeleteCharge=0x32e2 #Trevius 03/23/09 OP_ItemPacket=0x78Cd #Trevius 02/08/09 diff --git a/utils/patches/patch_Titanium.conf b/utils/patches/patch_Titanium.conf index 23f07109f..27aa18376 100644 --- a/utils/patches/patch_Titanium.conf +++ b/utils/patches/patch_Titanium.conf @@ -198,6 +198,7 @@ OP_Split=0x4848 # ShowEQ 10/27/05 OP_Surname=0x4668 # ShowEQ 10/27/05 OP_ClearSurname=0x6cdb OP_MoveItem=0x420f # ShowEQ 10/27/05 +OP_MoveMultipleItems=0x463b OP_FaceChange=0x0f8e # ShowEQ 10/27/05 OP_ItemPacket=0x3397 # ShowEQ 10/27/05 OP_ItemLinkResponse=0x667c # ShowEQ 10/27/05 diff --git a/utils/patches/patch_UF.conf b/utils/patches/patch_UF.conf index 6d8064029..c08edbca3 100644 --- a/utils/patches/patch_UF.conf +++ b/utils/patches/patch_UF.conf @@ -168,6 +168,7 @@ OP_GMKill=0x799c # C OP_GMNameChange=0x0f48 # C OP_GMLastName=0x7bfb # C +OP_QueryUCSServerStatus=0x4481 OP_InspectAnswer=0x0c2b # C OP_BeginCast=0x0d5a # C OP_ColoredText=0x71bf # C @@ -251,6 +252,7 @@ OP_AutoAttack=0x1df9 # C OP_AutoAttack2=0x517b # C OP_Consume=0x24c5 # V OP_MoveItem=0x2641 # C +OP_MoveMultipleItems=0x40e8 OP_DeleteItem=0x66e0 # C OP_DeleteCharge=0x4ca1 # C OP_ItemPacket=0x7b6e # C diff --git a/utils/scripts/database_dumper.pl b/utils/scripts/database_dumper.pl new file mode 100644 index 000000000..51b16eabc --- /dev/null +++ b/utils/scripts/database_dumper.pl @@ -0,0 +1,252 @@ +#!/usr/bin/perl + +############################################################ +#::: Script: db_dumper.pl +#::: Purpose: Utility to easily manage database backups and compress. +#::: Export Individual DB Tables... +#::: Export specific databases... +#::: Built for both Windows and Linux +#::: Windows uses WinRar or 7-Zip for compression +#::: Linux uses tar for compression +#::: Author: Akkadius +############################################################ + +$localdrive = "C:"; #::: Where Windows and all Install Programs are... +$linesep = "---------------------------------------"; + +use POSIX qw(strftime); +my $date = strftime "%m_%d_%Y", localtime; +print "\nTodays Date: " . $date . "\n"; + +use Config; +print "Operating System is: $Config{osname}\n"; +if($Config{osname}=~/linux/i){ $OS = "Linux"; } +if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } + +if(!$ARGV[0]){ + print "\nERROR! Need arguments\n"; + print "#::: Help :::#\n"; + print "######################################################\n"; + print "Arguments\n"; + print " loc=\"C:\\File Location\" - File path location to backup...\n"; + print " database=\"dbname\" - Manually specify databasename, default is database in eqemu_config.xml\n"; + print " tables=\"table1,table2,table3\" - Manually specify tables, default is to dump all tables from database\n"; + print " compress - Compress Database with 7-ZIP, will fallback to WinRAR depending on what is installed (Must be installed to default program dir)...\n"; + print " nolock - Does not lock tables, meant for backuping while the server is running..\n"; + print " backup_name=\"name\" - Sets database backup prefix name\n"; + print ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n"; + print "######################################################\n"; + exit; +} + +sub read_eqemu_config_json { + use JSON; + my $json = new JSON(); + + my $content; + open(my $fh, '<', "eqemu_config.json") or die "Unable to open config: eqemu_config.json - This must be in your EQEmu Server Folder\n"; { + local $/; + $content = <$fh>; + } + close($fh); + + $config = $json->decode($content); + + $db = $config->{"server"}{"database"}{"db"}; + $host = $config->{"server"}{"database"}{"host"}; + $user = $config->{"server"}{"database"}{"username"}; + $pass = $config->{"server"}{"database"}{"password"}; + $long_name = $config->{"server"}{"world"}{"longname"}; + +} + +read_eqemu_config_json(); + +$Debug = 0; +print "[db_dumper.pl] Arguments\n" if $Debug; +$n = 0; +while($ARGV[$n]){ + print $n . ': ' . $ARGV[$n] . "\n" if $Debug; + if($ARGV[$n]=~/nolock/i){ + $no_lock = 1; + } + if($ARGV[$n]=~/compress/i){ + print "[db_dumper.pl] Compression SET\n"; + $Compress = 1; + } + if($ARGV[$n]=~/database=/i){ + @DB_NAME = split('=', $ARGV[$n]); + print "[db_dumper.pl] Database is " . $DB_NAME[1] . "\n"; + $db = $DB_NAME[1]; + } + if($ARGV[$n]=~/backup_name=/i){ + @data = split('=', $ARGV[$n]); + print "[db_dumper.pl] Backup Name is " . $data[1] . "\n"; + $backup_name = $data[1]; + } + if($ARGV[$n]=~/loc=/i){ + @backup_location = split('=', $ARGV[$n]); + print "[db_dumper.pl] Backup Directory: " . $backup_location[1] . "\n"; + } + if($ARGV[$n]=~/tables=/i){ + @Tables = split('=', $ARGV[$n]); @TList = split(',', $Tables[1]); + foreach my $tables (@TList){ + $t_tables .= $tables . " "; + $t_tables_l .= $tables . "_"; + $t_tables_p .= $tables . "\n"; + } + print "[db_dumper.pl] Backing up tables: \n############################\n" . $t_tables_p . "############################\n"; + } + $n++; +} + +#::: Check for Backup Directory existence, if doesn't exist then create... +if (-d $backup_location[1]) { + print "[db_dumper.pl] Directory currently exists... Adding files to it...\n"; +} +elsif($backup_location[1] ne ""){ + print "[db_dumper.pl] Directory does NOT exist! Creating...\n"; + mkdir($backup_location[1]) or die 'Failed to create folder, maybe created the folder manually at "' . $backup_location[1]. '" ?'; +} +else{ + print "[db_dumper.pl] No save location specified... Saving to folder script is running in...\n"; +} +if($backup_location[1] ne ""){ + if($OS eq "Windows"){ $file_app = "\\"; } + if($OS eq "Linux"){ $file_app = "/"; } +} +else { + $file_app = ""; +} + +if($t_tables ne ""){ + $tables_f_l = substr($t_tables_l, 0, 20) . '-'; + if($backup_name){ + $target_file = $backup_name . '_' . $date . ''; + } + else { + $target_file = '' . $tables_f_l . '_' . $date . ''; + } + + print "[db_dumper.pl] Performing table based backup...\n"; + #::: Backup Database... + print "[db_dumper.pl] Backing up Database " . $db . "... \n"; + if($no_lock == 1){ + $added_parameters .= " --skip-lock-tables "; + } + $cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' ' . $t_tables . ' > "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql"'; + printcmd($cmd); + system($cmd); +} +else{ #::: Entire DB Backup + + if($backup_name){ + $target_file = $backup_name . '_' . $db . '_' . $date . ''; + } + else { + $target_file = '' . $db . '_' . $date . ''; + } + + #::: Backup Database... + print "[db_dumper.pl] Backing up Database " . $db . "... \n"; + if($no_lock == 1){ + $added_parameters .= " --skip-lock-tables "; + } + $cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' > "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql"'; + printcmd($cmd); + system($cmd); +} + +#::: Get File Size +$fileloc = '' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql'; +$filesize = -s $fileloc; +if($filesize < 1000){ print "[db_dumper.pl] " . 'Error occurred... exiting...' . "\n"; exit; } +print "[db_dumper.pl] Backup DONE... DB Backup File Size '" . $filesize . "' (" . get_filesize_str($fileloc) . ")\n"; + +#::: WinRar Get, check compression flag +if($Compress == 1){ + if($OS eq "Windows"){ + if(-d $localdrive . "\\Program Files\\7-Zip"){ + print "[db_dumper.pl] ::: You have 7-Zip installed as 64 Bit...\n"; + $S_ZIP = $localdrive . "\\Program Files\\7-Zip"; + } + elsif(-d $localdrive . "\\Program Files (x86)\\7-Zip"){ + print "[db_dumper.pl] ::: You have 7-Zip installed as 32 Bit...\n"; + $S_ZIP = $localdrive . "\\Program Files (x86)\\7-Zip"; + } + elsif(-d $localdrive . "\\Program Files (x86)\\WinRAR"){ + print "[db_dumper.pl] ::: You have WinRAR installed as 32 Bit...\n"; + $WinRar = $localdrive . "\\Program Files (x86)\\WinRAR"; + } + elsif(-d $localdrive . "\\Program Files\\WinRAR"){ + print "[db_dumper.pl] ::: You have WinRAR installed as 64 Bit...\n"; + $WinRar = $localdrive . "\\Program Files\\WinRAR"; + } + else{ + print "[db_dumper.pl] No WinRAR installed... Will not compress...\n"; + } + if($S_ZIP ne ""){ + print "[db_dumper.pl] Compressing Database with 7-ZIP... \n"; + $cmd = '"' . $S_ZIP . '\\7z" a -t7z -m0=lzma -mx=9 "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.7z" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" '; + printcmd($cmd); + system($cmd); + print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n"; + $cmd = 'del "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" '; + printcmd($cmd); + system($cmd); + $final_file = $target_file . ".7z"; + } + elsif($WinRar ne ""){ + print "[db_dumper.pl] Compressing Database with WinRAR... \n"; + $cmd = '"' . $WinRar . '\\rar" a "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.rar" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" '; + printcmd($cmd); + system($cmd); + print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n"; + $cmd = 'del "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" '; + printcmd($cmd); + system($cmd); + $final_file = $target_file . ".rar"; + } + } + if($OS eq "Linux"){ + print "[db_dumper.pl] Compressing Database with Tarball... \n"; + $cmd = 'tar -zcvf "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.tar.gz" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" '; + printcmd($cmd); + system($cmd); + print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n"; + $cmd = 'rm "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" '; + printcmd($cmd); + system($cmd); + $final_file = $target_file . ".tar.gz"; + } +} +else { + $final_file = $target_file . ".sql"; +} + +#::: Get Final File Location for display +if($backup_location[1] ne ""){ $final_loc = $backup_location[1] . '' . $file_app . ""; } +else{ + if($OS eq "Windows"){ + $final_loc = `echo %cd%`; + } + elsif($OS eq "Linux"){ + $final_loc = `pwd`; + } +} + +print "[db_dumper.pl] Final file located: " . $final_loc . "" . $final_file . "\n"; + +sub printcmd{ + print "[db_dumper.pl] Command [" . $_[0] . "]\n"; +} + +sub get_filesize_str{ + my $file = shift(); + my $size = (stat($file))[7] || die "stat($file): $!\n"; + if ($size > 1099511627776) { return sprintf("%.2f TiB", $size / 1099511627776); } + elsif ($size > 1073741824) { return sprintf("%.2f GiB", $size / 1073741824); } + elsif ($size > 1048576) { return sprintf("%.2f MiB", $size / 1048576); } + elsif ($size > 1024) { return sprintf("%.2f KiB", $size / 1024); } + else { return "$size byte" . ($size == 1 ? "" : "s"); } +} diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index 42d956edd..8921cf89f 100644 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -48,10 +48,18 @@ if(-e "eqemu_server_skip_update.txt"){ } #::: Check for script self update +check_xml_to_json_conversion() if $ARGV[0] eq "convert_xml"; do_self_update_check_routine() if !$skip_self_update_check; get_windows_wget(); get_perl_version(); -read_eqemu_config_xml(); +if(-e "eqemu_config.json") { + read_eqemu_config_json(); +} +else { + #::: This will need to stay for servers who simply haven't updated yet + # This script can still update without the server bins being updated + read_eqemu_config_xml(); +} get_mysql_path(); #::: Remove old eqemu_update.pl @@ -265,7 +273,7 @@ sub new_server { analytics_insertion("new_server::install", $database_name); if($OS eq "Linux"){ - build_linux_source(); + build_linux_source("login"); } do_installer_routines(); @@ -281,6 +289,10 @@ sub new_server { show_install_summary_info(); + if($OS eq "Linux") { + unlink('/home/eqemu/install_variables.txt'); + } + rmtree('updates_staged'); return; @@ -291,6 +303,61 @@ sub new_server { } } +sub check_xml_to_json_conversion { + if(-e "eqemu_config.xml" && !-e "eqemu_config.json") { + + if($OS eq "Windows"){ + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/xmltojson/xmltojson-windows-x86.exe", "xmltojson.exe"); + print "Converting eqemu_config.xml to eqemu_config.json\n"; + print `xmltojson eqemu_config.xml`; + } + if($OS eq "Linux"){ + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/xmltojson/xmltojson-linux-x86", "xmltojson"); + print "Converting eqemu_config.xml to eqemu_config.json\n"; + print `chmod 755 xmltojson`; + print `./xmltojson eqemu_config.xml`; + } + + #::: Prettify and alpha order the config + use JSON; + my $json = new JSON(); + + my $content; + open(my $fh, '<', "eqemu_config.json") or die "cannot open file $filename"; { + local $/; + $content = <$fh>; + } + close($fh); + + $result = $json->decode($content); + $json->canonical(1); + + print $json->pretty->indent_length(5)->utf8->encode($result),"\n"; + + open(my $fh, '>', 'eqemu_config.json'); + print $fh $json->pretty->indent_length(5)->utf8->encode($result); + close $fh; + + mkdir('backups'); + copy_file("eqemu_config.xml", "backups/eqemu_config.xml"); + unlink('eqemu_config.xml'); + unlink('db_dumper.pl'); + + print "[Server Maintenance] eqemu_config.xml is now DEPRECATED \n"; + print "[Server Maintenance] eqemu_config.json is now the new Server config format \n"; + print " A backup of this old config is located in the backups folder of your server directory\n"; + print " --- \n"; + print " You may have some plugins and/or applications that still require reference of this config file\n"; + print " Please update these plugins/applications to use the new configuration format if needed\n"; + print " --- \n"; + print " Thanks for your understanding\n"; + print " The EQEmulator Team\n\n"; + + exit; + } + +} + sub build_linux_source { $build_options = $_[0]; @@ -330,10 +397,10 @@ sub build_linux_source { print "Generating CMake build files...\n"; if($os_flavor eq "fedora_core"){ - print `cmake $cmake_options -DEQEMU_BUILD_LUA=ON -DLUA_INCLUDE_DIR=/usr/include/lua-5.1/ -G "Unix Makefiles" ..`; + print `cmake $cmake_options -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -DLUA_INCLUDE_DIR=/usr/include/lua-5.1/ -G "Unix Makefiles" ..`; } else { - print `cmake $cmake_options -DEQEMU_BUILD_LUA=ON -G "Unix Makefiles" ..`; + print `cmake $cmake_options -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G "Unix Makefiles" ..`; } print "Building EQEmu Server code. This will take a while."; @@ -352,6 +419,7 @@ sub build_linux_source { print `ln -s -f $source_dir/Server/build/bin/ucs .`; print `ln -s -f $source_dir/Server/build/bin/world .`; print `ln -s -f $source_dir/Server/build/bin/zone .`; + print `ln -s -f $source_dir/Server/build/bin/loginserver .`; } sub do_installer_routines { @@ -362,8 +430,8 @@ sub do_installer_routines { mkdir('updates_staged'); mkdir('shared'); - do_install_config_xml(); - read_eqemu_config_xml(); + do_install_config_json(); + read_eqemu_config_json(); get_installation_variables(); $db_name = "peq"; @@ -579,7 +647,12 @@ sub do_self_update_check_routine { sub get_installation_variables{ #::: Fetch installation variables before building the config if($OS eq "Linux"){ - open (INSTALL_VARS, "../install_variables.txt"); + if(-e "../install_variables.txt") { + open (INSTALL_VARS, "../install_variables.txt"); + } + elsif(-e "install_variables.txt") { + open (INSTALL_VARS, "./install_variables.txt"); + } } if($OS eq "Windows"){ open (INSTALL_VARS, "install_variables.txt"); @@ -593,73 +666,51 @@ sub get_installation_variables{ close (INSTALL_VARS); } -sub do_install_config_xml { +sub do_install_config_json { get_installation_variables(); - #::: Fetch XML template - get_remote_file($install_repository_request_url . "eqemu_config.xml", "eqemu_config_template.xml"); + #::: Fetch json template + get_remote_file($install_repository_request_url . "eqemu_config.json", "eqemu_config_template.json"); - #::: Open new config file - open (NEW_CONFIG, '>', 'eqemu_config.xml'); + use JSON; + my $json = new JSON(); + + my $content; + open(my $fh, '<', "eqemu_config_template.json") or die "cannot open file $filename"; { + local $/; + $content = <$fh>; + } + close($fh); + + $config = $json->decode($content); - $in_database_tag = 0; + $long_name = "Akkas " . $OS . " PEQ Installer (" . generate_random_password(5) . ')'; + $config->{"server"}{"world"}{"longname"} = $long_name; + $config->{"server"}{"world"}{"key"} = generate_random_password(30); - #::: Iterate through template and replace variables... - open (FILE_TEMPLATE, "eqemu_config_template.xml"); - while (){ - chomp; - $o = $_; - - #::: Find replace variables - - if($o=~/\<\!--/i){ - next; - } - - if($o=~/database/i && $o=~/\<\//i){ - $in_database_tag = 0; - } - if($o=~/database/i){ - $in_database_tag = 1; - } - - if($o=~/key/i){ - my($replace_key) = $o =~ />(\w+)/i){ - my($replace_name) = $o =~ /(.*)<\/longname>/; - $append = '(' . generate_random_password(5) . ')'; - $o =~ s/$replace_name/Akkas $OS PEQ Installer $append/g; - } - if($o=~/\/i && $in_database_tag){ - my($replace_username) = $o =~ />(\w+)/i && $in_database_tag){ - my($replace_password) = $o =~ />(\w+)/i){ - my($replace_db_name) = $o =~ />(\w+){"server"}{"database"}{"username"} = $installation_variables{"mysql_eqemu_user"}; + $config->{"server"}{"database"}{"password"} = $installation_variables{"mysql_eqemu_password"}; + $config->{"server"}{"database"}{"db"} = $db_name; + + $config->{"server"}{"qsdatabase"}{"username"} = $installation_variables{"mysql_eqemu_user"}; + $config->{"server"}{"qsdatabase"}{"password"} = $installation_variables{"mysql_eqemu_password"}; + $config->{"server"}{"qsdatabase"}{"db"} = $db_name; + + $json->canonical(1); + $json->indent_length(5); + + open(my $fh, '>', 'eqemu_config.json'); + print $fh $json->pretty->indent_length(5)->utf8->encode($config); + close $fh; + + unlink("eqemu_config_template.json"); } sub fetch_utility_scripts { @@ -725,6 +776,13 @@ sub show_menu_prompt { print "Enter a command #> "; $last_menu = trim($input); } + elsif($input eq "conversions"){ + print "\n>>> Conversions Menu\n\n"; + print " [quest_heading_convert] Converts old heading format in quest scripts to new (live format)\n"; + print " \n> main - go back to main menu\n"; + print "Enter a command #> "; + $last_menu = trim($input); + } elsif($input eq "assets"){ print "\n>>> Server Assets Menu\n\n"; print " [maps] Download latest maps\n"; @@ -733,7 +791,7 @@ sub show_menu_prompt { print " [plugins] Download latest plugins\n"; print " [lua_modules] Download latest lua_modules\n"; print " [utility_scripts] Download utility scripts to run and operate the EQEmu Server\n"; - if($OS eq "Windows"){ + if($OS eq "Windows") { print ">>> Windows\n"; print " [windows_server_download] Updates server via latest 'stable' code\n"; print " [windows_server_latest] Updates server via latest commit 'unstable'\n"; @@ -766,6 +824,8 @@ sub show_menu_prompt { elsif($input eq "setup_loginserver"){ do_windows_login_server_setup(); $dc = 1; } elsif($input eq "new_server"){ new_server(); $dc = 1; } elsif($input eq "setup_bots"){ setup_bots(); $dc = 1; } + elsif($input eq "linux_login_server_setup"){ do_linux_login_server_setup(); $dc = 1; } + elsif($input eq "quest_heading_convert"){ quest_heading_convert(); $dc = 1; } elsif($input eq "exit"){ exit; } @@ -816,6 +876,7 @@ sub print_main_menu { print " [assets] Manage server assets \n"; print " [new_server] New folder EQEmu/PEQ install - Assumes MySQL/Perl installed \n"; print " [setup_bots] Enables bots on server - builds code and database requirements \n"; + print " [conversions] Routines used for conversion of scripts/data \n"; print "\n"; print " exit \n"; print "\n"; @@ -858,13 +919,13 @@ sub check_for_database_dump_script{ return; } - #::: Check for script changes :: db_dumper.pl - get_remote_file($eqemu_repository_request_url . "utils/scripts/db_dumper.pl", "updates_staged/db_dumper.pl", 0, 1, 1); + #::: Check for script changes :: database_dumper.pl + get_remote_file($eqemu_repository_request_url . "utils/scripts/database_dumper.pl", "updates_staged/database_dumper.pl", 0, 1, 1); - if(-e "updates_staged/db_dumper.pl") { + if(-e "updates_staged/database_dumper.pl") { - my $remote_script_size = -s "updates_staged/db_dumper.pl"; - my $local_script_size = -s "db_dumper.pl"; + my $remote_script_size = -s "updates_staged/database_dumper.pl"; + my $local_script_size = -s "database_dumper.pl"; if($remote_script_size != $local_script_size){ print "[Update] Script has been updated, updating...\n"; @@ -876,14 +937,14 @@ sub check_for_database_dump_script{ $start_dir ); for my $file (@files) { - if($file=~/db_dumper/i){ + if($file=~/database_dumper/i){ $destination_file = $file; $destination_file =~s/updates_staged\///g; print "[Install] Installing :: " . $destination_file . "\n"; unlink($destination_file); copy_file($file, $destination_file); if($OS eq "Linux"){ - system("chmod 755 db_dumper.pl"); + system("chmod 755 database_dumper.pl"); } } } @@ -893,7 +954,7 @@ sub check_for_database_dump_script{ print "[Update] No script update necessary...\n"; } - unlink("updates_staged/db_dumper.pl"); + unlink("updates_staged/database_dumper.pl"); } return; @@ -903,7 +964,7 @@ sub check_for_database_dump_script{ sub database_dump { check_for_database_dump_script(); print "[Database] Performing database backup....\n"; - print `perl db_dumper.pl database="$db" loc="backups"`; + print `perl database_dumper.pl database="$db" loc="backups"`; } sub database_dump_player_tables { @@ -921,7 +982,7 @@ sub database_dump_player_tables { } $tables = substr($tables, 0, -1); - print `perl db_dumper.pl database="$db" loc="backups" tables="$tables" backup_name="player_tables_export" nolock`; + print `perl database_dumper.pl database="$db" loc="backups" tables="$tables" backup_name="player_tables_export" nolock`; print "[Database] Press any key to continue...\n"; @@ -932,7 +993,7 @@ sub database_dump_player_tables { sub database_dump_compress { check_for_database_dump_script(); print "[Database] Performing database backup....\n"; - print `perl db_dumper.pl database="$db" loc="backups" compress`; + print `perl database_dumper.pl database="$db" loc="backups" compress`; } sub script_exit{ @@ -1008,7 +1069,7 @@ sub get_remote_file{ } #::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt - $wget = `wget -N --no-check-certificate --quiet -O $destination_file $request_url`; + $wget = `wget -N --cache=no --no-check-certificate --quiet -O $destination_file $request_url`; print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download; if($wget=~/unable to resolve/i){ print "Error, no connection or failed request...\n\n"; @@ -1072,6 +1133,26 @@ sub read_eqemu_config_xml { close(CONFIG); } +sub read_eqemu_config_json { + use JSON; + my $json = new JSON(); + + my $content; + open(my $fh, '<', "eqemu_config.json") or die "cannot open file $filename"; { + local $/; + $content = <$fh>; + } + close($fh); + + $config = $json->decode($content); + + $db = $config->{"server"}{"database"}{"db"}; + $host = $config->{"server"}{"database"}{"host"}; + $user = $config->{"server"}{"database"}{"username"}; + $pass = $config->{"server"}{"database"}{"password"}; + +} + #::: Fetch Latest PEQ AA's sub aa_fetch{ if(!$db){ @@ -1277,6 +1358,8 @@ sub do_windows_login_server_setup { sub do_linux_login_server_setup { + build_linux_source(); + for my $file (@files) { $destination_file = $file; $destination_file =~s/updates_staged\/login_server\///g; @@ -1297,6 +1380,8 @@ sub do_linux_login_server_setup { get_remote_file($install_repository_request_url . "linux/login.ini", "login_template.ini"); get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes.conf"); get_remote_file($install_repository_request_url . "linux/login_opcodes_sod.conf", "login_opcodes_sod.conf"); + get_remote_file($install_repository_request_url . "linux/server_start_with_login.sh", "server_start_with_login.sh"); + system("chmod 755 *.sh"); get_installation_variables(); my $db_name = $installation_variables{"mysql_eqemu_db_name"}; @@ -2181,3 +2266,134 @@ sub generate_random_password { return $randpassword; } +sub quest_heading_convert { + + if(trim(get_mysql_result("SELECT value FROM variables WHERE varname = 'new_heading_conversion'")) eq "true") { + print "Conversion script has already ran... doing this again would skew proper heading values in function calls...\n"; + exit; + } + + %matches = ( + 0 => ["quest::spawn2", 6], + 1 => ["eq.spawn2", 6], + 2 => ["eq.unique_spawn", 6], + 3 => ["quest::unique_spawn", 6], + 4 => ["GMMove", 3], + 5 => ["MovePCInstance", 5], + 6 => ["MovePC", 4], + 7 => ["moveto", 3], + ); + + $total_matches = 0; + + use Scalar::Util qw(looks_like_number); + + my @files; + my $start_dir = "quests/."; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + + #::: Skip non script files + if($file!~/lua|pl/i){ next; } + + if($file=~/lua|pl/i){ + $print_buffer = ""; + + $changes_made = 0; + + #::: Open and read line by line + open (FILE, $file); + while () { + chomp; + $line = $_; + + #::: Loop through matches + foreach my $key (sort(keys %matches)) { + $argument_position = $matches{$key}[1]; + $match = $matches{$key}[0]; + + if($line=~/$match/i) { + $line_temp = $line; + $line_temp =~s/$match\(//g; + $line_temp =~s/\(.*?\)//gs; + $line_temp =~s/\);.*//; + $line_temp =~s/\).*//; + $line_temp =~s/\):.*//; + $line_temp =~s/\);//g; + + @line_data = split(",", $line_temp); + + # use Data::Dumper; + # print Dumper(\@line_data); + + $heading_value = $line_data[$argument_position]; + $heading_value_clean = trim($heading_value); + $heading_value_raw = $line_data[$argument_position]; + $heading_value_before = $line_data[$argument_position - 1]; + + if (looks_like_number($heading_value) && $heading_value != 0 && ($heading_value * 2) <= 512) { + $heading_value_new = $heading_value * 2; + + $heading_value=~s/$heading_value_clean/$heading_value_new/g; + + $heading_value_search = quotemeta($heading_value_before . "," . $heading_value_raw); + $heading_value_replace = $heading_value_before . "," . $heading_value; + + print $file . "\n"; + print $line . "\n"; + $line=~s/$heading_value_search/$heading_value_replace/g; + print $line . "\n"; + print "\n"; + + $changes_made = 1; + } + elsif ($heading_value == 0){} #::: Do nothing + elsif ($heading_value=~/GetHeading|heading|\$h/i){} #::: Do nothing + else { + if ($file=~/\.pl/i) { + if($line_temp=~/#/i) { + $line .= " - needs_heading_validation"; + } + else { + $line .= " # needs_heading_validation"; + } + } + elsif ($file=~/\.lua/i) { + if($line_temp=~/--/i) { + $line .= " - needs_heading_validation"; + } + else { + $line .= " -- needs_heading_validation"; + } + } + + $changes_made = 1; + + print $line . "\n"; + } + + $total_matches++; + } + } + + $print_buffer .= $line . "\n"; + } + close (FILE); + + if($changes_made == 1) { + #::: Write changes + open (NEW_FILE, '>', $file); + print NEW_FILE $print_buffer; + close NEW_FILE; + } + } + } + + #::: Mark conversion as ran + print get_mysql_result("INSERT INTO `variables` (varname, value, information, ts) VALUES ('new_heading_conversion', 'true', 'Script ran against quests folder to convert new heading values', NOW())"); + + print "Total matches: " . $total_matches . "\n"; +} \ No newline at end of file diff --git a/utils/scripts/linux_installer/install.sh b/utils/scripts/linux_installer/install.sh index 55972e8c8..bffa2d939 100644 --- a/utils/scripts/linux_installer/install.sh +++ b/utils/scripts/linux_installer/install.sh @@ -119,18 +119,15 @@ if [[ "$OS" == "Debian" ]]; then apt-get $apt_options install zlibc apt-get $apt_options install libsodium-dev apt-get $apt_options install libsodium18 + apt-get $apt_options install libjson-perl - # If libsodium18 isn't installed (Debian), let's download both that and the dev package and install them. - if dpkg-query -s "libsodium18" 1>/dev/null 2>&1; then - echo "Sodium library already installed." - else - wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium-dev_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium-dev.deb - wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium18_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium18.deb - dpkg -i /home/eqemu/libsodium*.deb - # Cleanup after ourselves - rm -f /home/eqemu/libsodium-dev.deb - rm -f /home/eqemu/libsodium18.deb - fi + # Install libsodium + wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium-dev_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium-dev.deb + wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium18_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium18.deb + dpkg -i /home/eqemu/libsodium*.deb + # Cleanup after ourselves + rm -f /home/eqemu/libsodium-dev.deb + rm -f /home/eqemu/libsodium18.deb #::: Install FTP for remote FTP access echo "proftpd-basic shared/proftpd/inetd_or_standalone select standalone" | debconf-set-selections @@ -159,7 +156,7 @@ EOF # Install prereqs yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm yum -y install deltarpm - yum -y install open-vm-tools vim cmake boost-* zlib-devel mariadb-server mariadb-client mariadb-devel mariadb-libs mariadb-compat perl-* lua* dos2unix php-mysql proftpd + yum -y install open-vm-tools vim cmake boost-* zlib-devel mariadb-server mariadb-client mariadb-devel mariadb-libs mariadb-compat perl-* lua* dos2unix php-mysql proftpd libuuid-devel yum -y groupinstall "Development Tools" "Basic Web Server" "Compatibility Libraries" elif [[ "$OS" == "fedora_core" ]]; then diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index c9b6a7b78..db0a04ca8 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -369,6 +369,13 @@ 9113|2017_07_19_show_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'show_name'|empty| 9114|2017_07_22_aura.sql|SHOW TABLES LIKE 'auras'|empty| 9115|2017_10_28_traps.sql|SHOW COLUMNS FROM `traps` LIKE 'triggered_number'|empty| +9116|2017_12_16_GroundSpawn_Respawn_Timer.sql|SHOW COLUMNS FROM `ground_spawns` WHERE Field = 'respawn_timer' AND Type = 'int(11) unsigned'|empty| +9117|2018_02_01_NPC_Spells_Min_Max_HP.sql|SHOW COLUMNS FROM `npc_spells_entries` LIKE 'min_hp'|empty| +9118|2018_02_04_Charm_Stats.sql|SHOW COLUMNS FROM `npc_types` LIKE 'charm_ac'|empty| +9119|2018_02_10_GlobalLoot.sql|SHOW TABLES LIKE 'global_loot'|empty| +9120|2018_02_13_Heading.sql|SELECT value FROM variables WHERE varname = 'fixed_heading'|empty| +9121|2018_02_18_bug_reports.sql|SHOW TABLES LIKE 'bug_reports'|empty| +9122|2018_03_07_ucs_command.sql|SELECT * FROM `command_settings` WHERE `command` LIKE 'ucs'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/bots/bots_db_update_manifest.txt b/utils/sql/git/bots/bots_db_update_manifest.txt index 5806cfa3e..e072dcc4b 100644 --- a/utils/sql/git/bots/bots_db_update_manifest.txt +++ b/utils/sql/git/bots/bots_db_update_manifest.txt @@ -16,6 +16,7 @@ 9015|2017_02_26_bots_spell_casting_chances_update.sql|SHOW COLUMNS FROM `bot_spell_casting_chances` LIKE 'value'|not_empty| 9016|2017_02_26_bots_spell_casting_chances_update.sql|SHOW TABLES LIKE 'bot_spell_casting_chances'|empty| 9017|2017_03_26_bots_spells_id_fix_for_saved_shadowknight_bots.sql|SELECT * FROM `bot_data` WHERE `class` = '5' AND `spells_id` = '3004'|not_empty| +9018|2018_02_02_Bot_Spells_Min_Max_HP.sql|SHOW COLUMNS FROM `bot_spells_entries` LIKE 'min_hp'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/bots/deprecated/2015_09_30_bots_supplemental.sql b/utils/sql/git/bots/deprecated/2015_09_30_bots_supplemental.sql new file mode 100644 index 000000000..aab94aff3 --- /dev/null +++ b/utils/sql/git/bots/deprecated/2015_09_30_bots_supplemental.sql @@ -0,0 +1,1305 @@ +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Server version: 10.0.22-MariaDB - mariadb.org binary distribution +-- Server OS: Win64 +-- HeidiSQL Version: 9.3.0.4984 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +-- Dumping structure for table peq_raw.bot_spells_entries +DROP TABLE IF EXISTS `bot_spells_entries`; +CREATE TABLE IF NOT EXISTS `bot_spells_entries` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `npc_spells_id` int(11) NOT NULL DEFAULT '0', + `spellid` smallint(5) NOT NULL DEFAULT '0', + `type` int(10) unsigned NOT NULL DEFAULT '0', + `minlevel` tinyint(3) unsigned NOT NULL DEFAULT '0', + `maxlevel` tinyint(3) unsigned NOT NULL DEFAULT '255', + `manacost` smallint(5) NOT NULL DEFAULT '-1', + `recast_delay` int(11) NOT NULL DEFAULT '-1', + `priority` smallint(5) NOT NULL DEFAULT '0', + `resist_adjust` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2048 DEFAULT CHARSET=latin1; + +-- Dumping data for table peq_raw.bot_spells_entries: ~1,270 rows (approximately) +/*!40000 ALTER TABLE `bot_spells_entries` DISABLE KEYS */; +INSERT INTO `bot_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`, `manacost`, `recast_delay`, `priority`, `resist_adjust`) VALUES + (1, 701, 200, 2, 1, 3, -1, -1, 1, NULL), + (2, 701, 14, 1, 1, 4, -1, -1, 1, NULL), + (3, 701, 201, 1, 1, 1, -1, -1, 1, NULL), + (4, 701, 202, 8, 1, 6, -1, -1, 10, NULL), + (5, 701, 11, 8, 1, 14, -1, -1, 8, NULL), + (6, 701, 207, 16, 1, 28, -1, -1, 1, NULL), + (7, 701, 216, 1, 2, 15, -1, -1, 1, NULL), + (8, 701, 17, 2, 4, 9, -1, -1, 1, NULL), + (9, 701, 560, 1, 5, 13, -1, -1, 1, NULL), + (10, 701, 219, 8, 7, 16, -1, -1, 10, NULL), + (11, 701, 12, 2, 10, 19, -1, -1, 2, NULL), + (12, 701, 485, 8, 11, 16, -1, -1, 7, NULL), + (13, 701, 16, 1, 14, 28, -1, -1, 1, NULL), + (14, 701, 3575, 8, 15, 34, -1, -1, 6, NULL), + (15, 701, 368, 8, 15, 24, -1, -1, 8, NULL), + (16, 701, 123, 1, 16, 30, -1, -1, 1, NULL), + (17, 701, 89, 8, 17, 20, -1, -1, 10, NULL), + (18, 701, 2502, 2, 19, 28, -1, -1, 1, NULL), + (19, 701, 15, 2, 20, 29, -1, -1, 2, NULL), + (20, 701, 4088, 8, 20, 39, -1, -1, 6, NULL), + (21, 701, 486, 8, 21, 30, -1, -1, 10, NULL), + (22, 701, 18, 8, 25, 34, -1, -1, 9, NULL), + (23, 701, 130, 16, 29, 255, -1, -1, 1, NULL), + (24, 701, 2175, 2, 29, 43, -1, -1, 1, NULL), + (25, 701, 329, 1, 29, 43, -1, -1, 1, NULL), + (26, 701, 9, 2, 30, 38, -1, -1, 2, NULL), + (27, 701, 124, 1, 31, 45, -1, -1, 1, NULL), + (28, 701, 487, 8, 31, 39, -1, -1, 10, NULL), + (29, 701, 3576, 8, 35, 61, -1, -1, 7, NULL), + (30, 701, 19, 8, 35, 39, -1, -1, 8, NULL), + (31, 701, 13, 2, 39, 69, -1, -1, 2, NULL), + (32, 701, 3692, 8, 40, 44, -1, -1, 10, NULL), + (33, 701, 4089, 8, 40, 53, -1, -1, 6, NULL), + (34, 701, 1445, 8, 40, 48, -1, -1, 11, NULL), + (35, 701, 1444, 2, 44, 58, -1, -1, 1, NULL), + (36, 701, 672, 1, 44, 53, -1, -1, 1, NULL), + (37, 701, 4053, 8, 45, 59, -1, -1, 10, NULL), + (38, 701, 125, 1, 46, 57, -1, -1, 1, NULL), + (39, 701, 2505, 8, 49, 57, -1, -1, 11, NULL), + (40, 701, 1547, 8, 51, 59, -1, -1, 9, NULL), + (41, 701, 1543, 1, 54, 55, -1, -1, 1, NULL), + (42, 701, 4090, 8, 54, 61, -1, -1, 6, NULL), + (43, 701, 2508, 1, 56, 61, -1, -1, 1, NULL), + (44, 701, 1544, 1, 58, 60, -1, -1, 1, NULL), + (45, 701, 2509, 8, 58, 59, -1, -1, 11, NULL), + (46, 701, 1522, 2, 59, 59, -1, -1, 1, NULL), + (47, 701, 1546, 8, 60, 255, -1, -1, 9, NULL), + (48, 701, 2109, 8, 60, 64, -1, -1, 11, NULL), + (49, 701, 2122, 8, 60, 61, -1, -1, 10, NULL), + (50, 701, 2180, 2, 60, 61, -1, -1, 1, NULL), + (51, 701, 3481, 1, 61, 62, -1, -1, 1, NULL), + (52, 701, 3467, 8, 62, 64, -1, -1, 10, NULL), + (53, 701, 3472, 8, 62, 63, -1, -1, 7, NULL), + (54, 701, 3475, 2, 62, 64, -1, -1, 1, NULL), + (55, 701, 3476, 1, 62, 64, -1, -1, 1, NULL), + (56, 701, 4091, 8, 62, 66, -1, -1, 6, NULL), + (57, 701, 3482, 1, 63, 65, -1, -1, 1, NULL), + (58, 701, 4108, 8, 64, 66, -1, -1, 7, NULL), + (59, 701, 3474, 8, 65, 69, -1, -1, 11, NULL), + (60, 701, 3479, 8, 65, 66, -1, -1, 10, NULL), + (61, 701, 4882, 2, 65, 66, -1, -1, 1, NULL), + (62, 701, 4973, 1, 65, 66, -1, -1, 1, NULL), + (63, 701, 5254, 1, 66, 67, -1, -1, 1, NULL), + (64, 701, 5257, 8, 67, 69, -1, -1, 10, NULL), + (65, 701, 5258, 8, 67, 68, -1, -1, 7, NULL), + (66, 701, 5259, 2, 67, 255, -1, -1, 1, NULL), + (67, 701, 5260, 1, 67, 68, -1, -1, 1, NULL), + (68, 701, 5261, 8, 67, 255, -1, -1, 6, NULL), + (69, 701, 5266, 1, 68, 255, -1, -1, 1, NULL), + (70, 701, 5272, 8, 69, 255, -1, -1, 7, NULL), + (71, 701, 8006, 1, 69, 69, -1, -1, 1, NULL), + (72, 701, 5276, 8, 70, 255, -1, -1, 11, NULL), + (73, 701, 5278, 8, 70, 255, -1, -1, 10, NULL), + (74, 701, 5279, 1, 70, 255, -1, -1, 1, NULL), + (75, 701, 6140, 2, 70, 255, -1, -1, 2, NULL), + (76, 702, 288, 8, 1, 5, -1, -1, 1, NULL), + (77, 702, 372, 1, 1, 7, -1, -1, 3, NULL), + (78, 702, 378, 8, 2, 9, -1, -1, 2, NULL), + (79, 702, 230, 4, 3, 16, -1, -1, 2, NULL), + (80, 702, 376, 1, 4, 4, -1, -1, 3, NULL), + (81, 702, 477, 1, 5, 14, -1, -1, 3, NULL), + (82, 702, 246, 8, 6, 14, -1, -1, 1, NULL), + (83, 702, 656, 1, 8, 23, -1, -1, 3, NULL), + (84, 702, 381, 8, 9, 60, -1, -1, 4, NULL), + (85, 702, 2551, 8, 10, 30, -1, -1, 2, NULL), + (86, 702, 383, 1, 10, 15, -1, -1, 3, NULL), + (87, 702, 48, 512, 11, 33, -1, -1, 1, NULL), + (88, 702, 236, 8, 13, 20, -1, -1, 5, NULL), + (89, 702, 309, 8, 15, 22, -1, -1, 1, NULL), + (90, 702, 657, 1, 15, 25, -1, -1, 3, NULL), + (91, 702, 38, 1, 16, 36, -1, -1, 3, NULL), + (92, 702, 131, 4, 17, 38, -1, -1, 2, NULL), + (93, 702, 22, 1, 17, 17, -1, -1, 3, NULL), + (94, 702, 2552, 1, 18, 27, -1, -1, 3, NULL), + (95, 702, 503, 1, 19, 46, -1, -1, 2, NULL), + (96, 702, 108, 8, 20, 41, -1, -1, 6, NULL), + (97, 702, 387, 8, 21, 29, -1, -1, 5, NULL), + (98, 702, 65, 8, 23, 32, -1, -1, 1, NULL), + (99, 702, 464, 1, 24, 33, -1, -1, 3, NULL), + (100, 702, 2553, 32, 25, 44, -1, -1, 0, NULL), + (101, 702, 465, 1, 26, 42, -1, -1, 3, NULL), + (102, 702, 470, 1, 28, 40, -1, -1, 3, NULL), + (103, 702, 393, 8, 30, 39, -1, -1, 5, NULL), + (104, 702, 1419, 8, 31, 48, -1, -1, 2, NULL), + (105, 702, 66, 8, 33, 43, -1, -1, 1, NULL), + (106, 702, 49, 512, 34, 52, -1, -1, 1, NULL), + (107, 702, 658, 1, 34, 48, -1, -1, 3, NULL), + (108, 702, 466, 1, 37, 57, -1, -1, 3, NULL), + (109, 702, 752, 16, 37, 59, -1, -1, 1, NULL), + (110, 702, 132, 4, 39, 47, -1, -1, 2, NULL), + (111, 702, 3811, 8, 40, 57, -1, -1, 3, NULL), + (112, 702, 394, 8, 40, 51, -1, -1, 5, NULL), + (113, 702, 23, 1, 41, 46, -1, -1, 3, NULL), + (114, 702, 109, 8, 42, 53, -1, -1, 6, NULL), + (115, 702, 659, 1, 43, 59, -1, -1, 3, NULL), + (116, 702, 67, 8, 44, 53, -1, -1, 1, NULL), + (117, 702, 2555, 32, 45, 53, -1, -1, 0, NULL), + (118, 702, 612, 1, 47, 50, -1, -1, 2, NULL), + (119, 702, 755, 1, 47, 59, -1, -1, 3, NULL), + (120, 702, 133, 4, 48, 50, -1, -1, 2, NULL), + (121, 702, 4067, 8, 49, 56, -1, -1, 2, NULL), + (122, 702, 732, 1, 49, 59, -1, -1, 3, NULL), + (123, 702, 1631, 128, 51, 57, -1, -1, 2, NULL), + (124, 702, 1634, 1, 51, 55, -1, -1, 2, NULL), + (125, 702, 1609, 8, 52, 62, -1, -1, 5, NULL), + (126, 702, 1526, 512, 53, 255, -1, -1, 1, NULL), + (127, 702, 1610, 8, 54, 60, -1, -1, 1, NULL), + (128, 702, 2557, 32, 54, 59, -1, -1, 0, NULL), + (129, 702, 3582, 8, 54, 61, -1, -1, 6, NULL), + (130, 702, 1635, 1, 56, 63, -1, -1, 2, NULL), + (131, 702, 4068, 8, 57, 63, -1, -1, 2, NULL), + (132, 702, 1633, 4, 58, 60, -1, -1, 2, NULL), + (133, 702, 1640, 1, 58, 60, -1, -1, 3, NULL), + (134, 702, 2559, 8, 58, 255, -1, -1, 3, NULL), + (135, 702, 2884, 1, 60, 64, -1, -1, 3, NULL), + (136, 702, 2116, 1, 60, 63, -1, -1, 3, NULL), + (137, 702, 2117, 16, 60, 255, -1, -1, 1, NULL), + (138, 702, 2560, 32, 60, 255, -1, -1, 0, NULL), + (139, 702, 2883, 1, 60, 62, -1, -1, 3, NULL), + (140, 702, 3194, 4, 61, 255, -1, -1, 2, NULL), + (141, 702, 3300, 8, 61, 63, -1, -1, 1, NULL), + (142, 702, 3326, 8, 61, 255, -1, -1, 4, NULL), + (143, 702, 3328, 1, 61, 66, -1, -1, 3, NULL), + (144, 702, 3329, 8, 62, 255, -1, -1, 6, NULL), + (145, 702, 3301, 8, 63, 67, -1, -1, 5, NULL), + (146, 702, 3335, 1, 63, 64, -1, -1, 3, NULL), + (147, 702, 3302, 8, 64, 65, -1, -1, 1, NULL), + (148, 702, 4069, 8, 64, 69, -1, -1, 2, NULL), + (149, 702, 4066, 1, 64, 68, -1, -1, 3, NULL), + (150, 702, 3333, 1, 64, 69, -1, -1, 2, NULL), + (151, 702, 4981, 1, 65, 69, -1, -1, 3, NULL), + (152, 702, 3191, 1, 65, 255, -1, -1, 3, NULL), + (153, 702, 5443, 8, 66, 255, -1, -1, 1, NULL), + (154, 702, 5445, 1, 67, 67, -1, -1, 3, NULL), + (155, 702, 5448, 8, 68, 255, -1, -1, 5, NULL), + (156, 702, 5450, 1, 68, 255, -1, -1, 3, NULL), + (157, 702, 5458, 1, 69, 255, -1, -1, 3, NULL), + (158, 702, 5459, 8, 70, 255, -1, -1, 2, NULL), + (159, 702, 8043, 1, 70, 255, -1, -1, 3, NULL), + (160, 702, 5456, 1, 70, 255, -1, -1, 3, NULL), + (161, 703, 288, 8, 1, 7, -1, -1, 1, NULL), + (162, 703, 340, 256, 1, 14, -1, -1, 2, NULL), + (163, 703, 341, 64, 1, 2, -1, -1, 3, NULL), + (164, 703, 338, 32, 1, 3, -1, -1, 0, NULL), + (165, 703, 346, 8, 3, 15, -1, -1, 3, NULL), + (166, 703, 502, 64, 3, 11, -1, -1, 3, NULL), + (167, 703, 344, 128, 4, 10, -1, -1, 1, NULL), + (168, 703, 229, 1, 4, 29, -1, 45, 6, NULL), + (169, 703, 348, 256, 4, 33, -1, -1, 3, NULL), + (170, 703, 491, 32, 4, 7, -1, -1, 0, NULL), + (171, 703, 641, 8, 6, 17, -1, -1, 4, NULL), + (172, 703, 359, 8, 7, 19, -1, -1, 5, NULL), + (173, 703, 246, 8, 8, 15, -1, -1, 1, NULL), + (174, 703, 351, 32, 8, 11, -1, -1, 0, NULL), + (175, 703, 1509, 256, 9, 28, -1, -1, 3, NULL), + (176, 703, 360, 256, 10, 27, -1, -1, 3, NULL), + (177, 703, 2541, 8, 11, 22, -1, -1, 6, NULL), + (178, 703, 355, 128, 11, 26, -1, -1, 1, NULL), + (179, 703, 362, 32, 12, 15, -1, -1, 0, NULL), + (180, 703, 445, 64, 12, 19, -1, -1, 3, NULL), + (181, 703, 367, 256, 13, 38, -1, -1, 3, NULL), + (182, 703, 236, 8, 14, 21, -1, -1, 2, NULL), + (183, 703, 365, 256, 15, 34, -1, -1, 3, NULL), + (184, 703, 309, 8, 16, 20, -1, -1, 1, NULL), + (185, 703, 492, 32, 16, 19, -1, -1, 0, NULL), + (186, 703, 2542, 1, 17, 37, -1, -1, 2, NULL), + (187, 703, 642, 8, 18, 30, -1, -1, 4, NULL), + (188, 703, 199, 16, 20, 57, -1, -1, 1, NULL), + (189, 703, 440, 32, 20, 23, -1, -1, 0, NULL), + (190, 703, 446, 64, 20, 25, -1, -1, 3, NULL), + (191, 703, 204, 1, 21, 31, -1, -1, 5, NULL), + (192, 703, 387, 8, 22, 31, -1, -1, 2, NULL), + (193, 703, 449, 8, 23, 34, -1, -1, 6, NULL), + (194, 703, 493, 32, 24, 28, -1, -1, 0, NULL), + (195, 703, 524, 64, 26, 38, -1, -1, 3, NULL), + (196, 703, 452, 128, 27, 46, -1, -1, 1, NULL), + (197, 703, 451, 256, 28, 46, -1, -1, 3, NULL), + (198, 703, 441, 32, 29, 32, -1, -1, 0, NULL), + (199, 703, 454, 256, 29, 44, -1, -1, 3, NULL), + (200, 703, 127, 1, 30, 55, -1, 45, 6, NULL), + (201, 703, 643, 8, 31, 47, -1, -1, 4, NULL), + (202, 703, 1415, 1, 32, 48, -1, -1, 5, NULL), + (203, 703, 393, 8, 32, 42, -1, -1, 2, NULL), + (204, 703, 494, 32, 33, 38, -1, -1, 0, NULL), + (205, 703, 435, 256, 34, 49, -1, -1, 3, NULL), + (206, 703, 31, 256, 35, 39, -1, -1, 3, NULL), + (207, 703, 661, 8, 35, 54, -1, -1, 6, NULL), + (208, 703, 2544, 1, 38, 255, -1, -1, 2, NULL), + (209, 703, 442, 32, 39, 43, -1, -1, 0, NULL), + (210, 703, 525, 64, 39, 47, -1, -1, 3, NULL), + (211, 703, 4096, 256, 39, 53, -1, -1, 3, NULL), + (212, 703, 1508, 256, 40, 51, -1, -1, 3, NULL), + (213, 703, 394, 8, 43, 51, -1, -1, 2, NULL), + (214, 703, 495, 32, 44, 47, -1, -1, 0, NULL), + (215, 703, 3702, 256, 45, 48, -1, -1, 3, NULL), + (216, 703, 453, 128, 47, 58, -1, -1, 1, NULL), + (217, 703, 6, 256, 47, 57, -1, -1, 3, NULL), + (218, 703, 443, 32, 48, 52, -1, -1, 0, NULL), + (219, 703, 447, 64, 48, 53, -1, -1, 3, NULL), + (220, 703, 644, 8, 48, 55, -1, -1, 4, NULL), + (221, 703, 3571, 1, 49, 53, -1, -1, 5, NULL), + (222, 703, 456, 256, 49, 56, -1, -1, 3, NULL), + (223, 703, 436, 256, 50, 64, -1, -1, 3, NULL), + (224, 703, 1609, 8, 52, 62, -1, -1, 2, NULL), + (225, 703, 32, 256, 52, 55, -1, -1, 3, NULL), + (226, 703, 1621, 32, 53, 55, -1, -1, 0, NULL), + (227, 703, 3572, 1, 54, 59, -1, -1, 5, NULL), + (228, 703, 1613, 64, 54, 58, -1, -1, 3, NULL), + (229, 703, 4097, 256, 54, 62, -1, -1, 3, NULL), + (230, 703, 1414, 8, 55, 61, -1, -1, 6, NULL), + (231, 703, 1527, 1, 56, 56, -1, 45, 6, NULL), + (232, 703, 1611, 8, 56, 59, -1, -1, 4, NULL), + (233, 703, 1615, 256, 56, 66, -1, -1, 3, NULL), + (234, 703, 1622, 32, 56, 58, -1, -1, 0, NULL), + (235, 703, 1616, 256, 57, 59, -1, -1, 3, NULL), + (236, 703, 6980, 1, 57, 61, -1, -1, 6, NULL), + (237, 703, 1612, 16, 58, 255, -1, -1, 1, NULL), + (238, 703, 1617, 256, 58, 59, -1, -1, 3, NULL), + (239, 703, 1619, 128, 59, 62, -1, -1, 1, NULL), + (240, 703, 1623, 32, 59, 60, -1, -1, 0, NULL), + (241, 703, 1618, 64, 59, 59, -1, -1, 3, NULL), + (242, 703, 1393, 64, 60, 60, -1, -1, 3, NULL), + (243, 703, 2114, 8, 60, 63, -1, -1, 4, NULL), + (244, 703, 2115, 1, 60, 60, -1, -1, 5, NULL), + (245, 703, 2550, 256, 60, 64, -1, -1, 3, NULL), + (246, 703, 2885, 256, 60, 64, -1, -1, 3, NULL), + (247, 703, 3032, 64, 61, 66, -1, -1, 3, NULL), + (248, 703, 3035, 1, 61, 65, -1, -1, 5, NULL), + (249, 703, 3304, 32, 61, 62, -1, -1, 0, NULL), + (250, 703, 3305, 8, 62, 66, -1, -1, 6, NULL), + (251, 703, 6981, 1, 62, 66, -1, -1, 6, NULL), + (252, 703, 3301, 8, 63, 68, -1, -1, 2, NULL), + (253, 703, 3309, 128, 63, 67, -1, -1, 1, NULL), + (254, 703, 3310, 32, 63, 64, -1, -1, 0, NULL), + (255, 703, 4098, 256, 63, 66, -1, -1, 3, NULL), + (256, 703, 3311, 8, 64, 64, -1, -1, 4, NULL), + (257, 703, 3303, 256, 65, 68, -1, -1, 3, NULL), + (258, 703, 3314, 32, 65, 66, -1, -1, 0, NULL), + (259, 703, 4889, 256, 65, 255, -1, -1, 3, NULL), + (260, 703, 4890, 256, 65, 68, -1, -1, 3, NULL), + (261, 703, 4978, 8, 65, 69, -1, -1, 4, NULL), + (262, 703, 5420, 1, 66, 255, -1, -1, 5, NULL), + (263, 703, 5419, 64, 67, 69, -1, -1, 3, NULL), + (264, 703, 5424, 256, 67, 255, -1, -1, 3, NULL), + (265, 703, 5425, 8, 67, 255, -1, -1, 6, NULL), + (266, 703, 5431, 32, 67, 69, -1, -1, 0, NULL), + (267, 703, 5432, 256, 67, 69, -1, -1, 3, NULL), + (268, 703, 6982, 1, 67, 255, -1, -1, 6, NULL), + (269, 703, 5430, 128, 68, 255, -1, -1, 1, NULL), + (270, 703, 5428, 8, 69, 255, -1, -1, 2, NULL), + (271, 703, 5437, 256, 69, 69, -1, -1, 3, NULL), + (272, 703, 7999, 256, 69, 255, -1, -1, 3, NULL), + (273, 703, 5438, 32, 70, 255, -1, -1, 0, NULL), + (274, 703, 5441, 256, 70, 255, -1, -1, 3, NULL), + (275, 703, 6143, 64, 70, 255, -1, -1, 3, NULL), + (276, 703, 7994, 256, 70, 255, -1, -1, 3, NULL), + (277, 703, 5434, 8, 70, 255, -1, -1, 4, NULL), + (278, 704, 288, 8, 1, 4, -1, -1, 1, NULL), + (279, 704, 93, 1, 1, 3, -1, -1, 5, NULL), + (280, 704, 315, 32, 2, 5, -1, -1, 0, NULL), + (281, 704, 316, 32, 3, 6, -1, -1, 0, NULL), + (282, 704, 317, 32, 4, 7, -1, -1, 0, NULL), + (283, 704, 94, 1, 4, 4, -1, -1, 5, NULL), + (284, 704, 58, 32, 5, 8, -1, -1, 0, NULL), + (285, 704, 246, 8, 5, 15, -1, -1, 1, NULL), + (286, 704, 322, 1, 5, 14, -1, -1, 5, NULL), + (287, 704, 398, 32, 6, 9, -1, -1, 0, NULL), + (288, 704, 399, 32, 7, 10, -1, -1, 0, NULL), + (289, 704, 324, 1, 7, 22, -1, -1, 6, NULL), + (290, 704, 332, 8, 7, 18, -1, -1, 2, NULL), + (291, 704, 400, 32, 8, 11, -1, -1, 0, NULL), + (292, 704, 397, 32, 9, 12, -1, -1, 0, NULL), + (293, 704, 248, 1, 9, 17, -1, -1, 3, NULL), + (294, 704, 402, 32, 10, 13, -1, -1, 0, NULL), + (295, 704, 403, 32, 11, 14, -1, -1, 0, NULL), + (296, 704, 327, 8, 11, 28, -1, -1, 3, NULL), + (297, 704, 404, 32, 12, 15, -1, -1, 0, NULL), + (298, 704, 333, 8, 12, 24, -1, -1, 4, NULL), + (299, 704, 401, 32, 13, 16, -1, -1, 0, NULL), + (300, 704, 336, 32, 14, 17, -1, -1, 0, NULL), + (301, 704, 395, 32, 15, 18, -1, -1, 0, NULL), + (302, 704, 334, 1, 15, 17, -1, -1, 5, NULL), + (303, 704, 396, 32, 16, 19, -1, -1, 0, NULL), + (304, 704, 309, 8, 16, 23, -1, -1, 1, NULL), + (305, 704, 335, 32, 17, 20, -1, -1, 0, NULL), + (306, 704, 497, 32, 18, 21, -1, -1, 0, NULL), + (307, 704, 68, 1, 18, 30, -1, -1, 5, NULL), + (308, 704, 663, 1, 18, 24, -1, -1, 3, NULL), + (309, 704, 498, 32, 19, 22, -1, -1, 0, NULL), + (310, 704, 411, 8, 19, 27, -1, -1, 2, NULL), + (311, 704, 499, 32, 20, 23, -1, -1, 0, NULL), + (312, 704, 496, 32, 21, 24, -1, -1, 0, NULL), + (313, 704, 570, 32, 22, 25, -1, -1, 0, NULL), + (314, 704, 571, 32, 23, 26, -1, -1, 0, NULL), + (315, 704, 113, 1, 23, 40, -1, -1, 6, NULL), + (316, 704, 572, 32, 24, 27, -1, -1, 0, NULL), + (317, 704, 65, 8, 24, 31, -1, -1, 1, NULL), + (318, 704, 569, 32, 25, 28, -1, -1, 0, NULL), + (319, 704, 115, 1, 25, 27, -1, -1, 3, NULL), + (320, 704, 81, 8, 25, 40, -1, -1, 4, NULL), + (321, 704, 574, 32, 26, 30, -1, -1, 0, NULL), + (322, 704, 575, 32, 27, 31, -1, -1, 0, NULL), + (323, 704, 576, 32, 28, 32, -1, -1, 0, NULL), + (324, 704, 479, 8, 28, 37, -1, -1, 2, NULL), + (325, 704, 664, 1, 28, 47, -1, -1, 3, NULL), + (326, 704, 106, 8, 28, 46, -1, -1, 3, NULL), + (327, 704, 573, 32, 29, 33, -1, -1, 0, NULL), + (328, 704, 1400, 32, 30, 49, -1, -1, 0, NULL), + (329, 704, 621, 32, 31, 35, -1, -1, 0, NULL), + (330, 704, 120, 1, 31, 32, -1, -1, 5, NULL), + (331, 704, 622, 32, 32, 36, -1, -1, 0, NULL), + (332, 704, 49, 512, 32, 52, -1, -1, 3, NULL), + (333, 704, 66, 8, 32, 42, -1, -1, 1, NULL), + (334, 704, 623, 32, 33, 37, -1, -1, 0, NULL), + (335, 704, 69, 1, 33, 46, -1, -1, 5, NULL), + (336, 704, 620, 32, 34, 38, -1, -1, 0, NULL), + (337, 704, 625, 32, 36, 40, -1, -1, 0, NULL), + (338, 704, 626, 32, 37, 41, -1, -1, 0, NULL), + (339, 704, 627, 32, 38, 42, -1, -1, 0, NULL), + (340, 704, 680, 8, 38, 44, -1, -1, 2, NULL), + (341, 704, 624, 32, 39, 43, -1, -1, 0, NULL), + (342, 704, 629, 32, 41, 48, -1, -1, 0, NULL), + (343, 704, 114, 1, 41, 56, -1, -1, 6, NULL), + (344, 704, 82, 8, 41, 51, -1, -1, 4, NULL), + (345, 704, 630, 32, 42, 46, -1, -1, 0, NULL), + (346, 704, 631, 32, 43, 47, -1, -1, 0, NULL), + (347, 704, 1403, 1, 43, 54, -1, -1, 4, NULL), + (348, 704, 67, 8, 43, 53, -1, -1, 1, NULL), + (349, 704, 628, 32, 44, 45, -1, -1, 0, NULL), + (350, 704, 412, 8, 45, 52, -1, -1, 2, NULL), + (351, 704, 632, 32, 46, 50, -1, -1, 0, NULL), + (352, 704, 4079, 8, 46, 57, -1, -1, 5, NULL), + (353, 704, 634, 32, 47, 51, -1, -1, 0, NULL), + (354, 704, 107, 8, 47, 51, -1, -1, 3, NULL), + (355, 704, 70, 1, 47, 51, -1, -1, 5, NULL), + (356, 704, 635, 32, 48, 52, -1, -1, 0, NULL), + (357, 704, 116, 1, 48, 55, -1, -1, 3, NULL), + (358, 704, 633, 32, 49, 53, -1, -1, 0, NULL), + (359, 704, 1402, 32, 50, 59, -1, -1, 0, NULL), + (360, 704, 1671, 32, 51, 56, -1, -1, 0, NULL), + (361, 704, 1673, 32, 52, 57, -1, -1, 0, NULL), + (362, 704, 1660, 1, 52, 58, -1, -1, 5, NULL), + (363, 704, 1666, 8, 52, 53, -1, -1, 4, NULL), + (364, 704, 3700, 8, 52, 54, -1, -1, 3, NULL), + (365, 704, 1674, 32, 53, 58, -1, -1, 0, NULL), + (366, 704, 1526, 512, 53, 255, -1, -1, 3, NULL), + (367, 704, 1668, 8, 53, 55, -1, -1, 2, NULL), + (368, 704, 1672, 32, 54, 59, -1, -1, 0, NULL), + (369, 704, 1610, 8, 54, 60, -1, -1, 1, NULL), + (370, 704, 2879, 8, 54, 57, -1, -1, 4, NULL), + (371, 704, 1405, 1, 55, 255, -1, -1, 4, NULL), + (372, 704, 1472, 8, 55, 59, -1, -1, 3, NULL), + (373, 704, 1529, 1, 56, 63, -1, -1, 3, NULL), + (374, 704, 1667, 8, 56, 59, -1, -1, 2, NULL), + (375, 704, 1675, 32, 57, 64, -1, -1, 0, NULL), + (376, 704, 1663, 1, 57, 62, -1, -1, 6, NULL), + (377, 704, 1677, 32, 58, 62, -1, -1, 0, NULL), + (378, 704, 2539, 8, 58, 61, -1, -1, 4, NULL), + (379, 704, 4080, 8, 58, 63, -1, -1, 5, NULL), + (380, 704, 1678, 32, 59, 60, -1, -1, 0, NULL), + (381, 704, 1664, 1, 59, 60, -1, -1, 5, NULL), + (382, 704, 1404, 32, 60, 64, -1, -1, 0, NULL), + (383, 704, 1676, 32, 60, 61, -1, -1, 0, NULL), + (384, 704, 1669, 8, 60, 60, -1, -1, 2, NULL), + (385, 704, 2119, 8, 60, 61, -1, -1, 3, NULL), + (386, 704, 3317, 32, 61, 65, -1, -1, 0, NULL), + (387, 704, 3198, 8, 61, 62, -1, -1, 2, NULL), + (388, 704, 3300, 8, 61, 63, -1, -1, 1, NULL), + (389, 704, 3318, 1, 61, 65, -1, -1, 5, NULL), + (390, 704, 3320, 32, 62, 66, -1, -1, 0, NULL), + (391, 704, 3031, 8, 62, 67, -1, -1, 4, NULL), + (392, 704, 3237, 8, 62, 68, -1, -1, 3, NULL), + (393, 704, 3322, 32, 63, 67, -1, -1, 0, NULL), + (394, 704, 3486, 8, 63, 65, -1, -1, 2, NULL), + (395, 704, 3321, 1, 63, 67, -1, -1, 6, NULL), + (396, 704, 3238, 1, 64, 68, -1, -1, 3, NULL), + (397, 704, 3302, 8, 64, 65, -1, -1, 1, NULL), + (398, 704, 4081, 8, 64, 68, -1, -1, 5, NULL), + (399, 704, 4888, 32, 65, 255, -1, -1, 0, NULL), + (400, 704, 3324, 32, 65, 69, -1, -1, 0, NULL), + (401, 704, 5473, 32, 66, 255, -1, -1, 0, NULL), + (402, 704, 5466, 8, 66, 69, -1, -1, 2, NULL), + (403, 704, 5472, 8, 66, 255, -1, -1, 1, NULL), + (404, 704, 5474, 1, 66, 255, -1, -1, 5, NULL), + (405, 704, 5480, 32, 67, 255, -1, -1, 0, NULL), + (406, 704, 5485, 32, 68, 255, -1, -1, 0, NULL), + (407, 704, 5476, 8, 68, 255, -1, -1, 4, NULL), + (408, 704, 5484, 1, 68, 255, -1, -1, 6, NULL), + (409, 704, 5478, 8, 69, 255, -1, -1, 3, NULL), + (410, 704, 5490, 1, 69, 255, -1, -1, 3, NULL), + (411, 704, 5494, 8, 69, 255, -1, -1, 5, NULL), + (412, 704, 5495, 32, 70, 255, -1, -1, 0, NULL), + (413, 704, 5488, 8, 70, 255, -1, -1, 2, NULL), + (414, 705, 288, 8, 1, 5, -1, -1, 1, NULL), + (415, 705, 40, 8, 1, 18, -1, -1, 2, NULL), + (416, 705, 289, 1, 1, 6, -1, -1, 7, NULL), + (417, 705, 286, 1, 1, 3, -1, -1, 6, NULL), + (418, 705, 285, 32, 1, 1, -1, -1, 0, NULL), + (419, 705, 681, 32, 2, 6, -1, -1, 0, NULL), + (420, 705, 294, 1, 4, 10, -1, -1, 6, NULL), + (421, 705, 246, 8, 6, 15, -1, -1, 1, NULL), + (422, 705, 295, 32, 7, 8, -1, -1, 0, NULL), + (423, 705, 296, 1, 7, 15, -1, -1, 7, NULL), + (424, 705, 48, 512, 7, 21, -1, -1, 7, NULL), + (425, 705, 302, 1, 9, 22, -1, -1, 2, NULL), + (426, 705, 303, 1, 9, 27, -1, -1, 5, NULL), + (427, 705, 682, 32, 9, 13, -1, -1, 0, NULL), + (428, 705, 2561, 8, 11, 16, -1, -1, 4, NULL), + (429, 705, 521, 1, 11, 25, -1, -1, 6, NULL), + (430, 705, 683, 32, 14, 16, -1, -1, 0, NULL), + (431, 705, 697, 8, 14, 25, -1, -1, 5, NULL), + (432, 705, 39, 8, 15, 20, -1, -1, 6, NULL), + (433, 705, 309, 8, 16, 22, -1, -1, 1, NULL), + (434, 705, 306, 1, 16, 20, -1, -1, 7, NULL), + (435, 705, 2562, 8, 17, 29, -1, -1, 4, NULL), + (436, 705, 684, 32, 17, 21, -1, -1, 0, NULL), + (437, 705, 170, 8, 21, 38, -1, -1, 6, NULL), + (438, 705, 350, 1, 21, 31, -1, -1, 7, NULL), + (439, 705, 24, 512, 22, 27, -1, -1, 7, NULL), + (440, 705, 685, 32, 22, 28, -1, -1, 0, NULL), + (441, 705, 185, 1, 23, 40, -1, -1, 2, NULL), + (442, 705, 65, 8, 23, 30, -1, -1, 1, NULL), + (443, 705, 174, 8, 26, 41, -1, -1, 5, NULL), + (444, 705, 450, 1, 26, 46, -1, -1, 6, NULL), + (445, 705, 49, 512, 28, 41, -1, -1, 7, NULL), + (446, 705, 619, 1, 28, 60, -1, -1, 5, NULL), + (447, 705, 4073, 8, 29, 43, -1, -1, 2, NULL), + (448, 705, 686, 32, 29, 30, -1, -1, 0, NULL), + (449, 705, 74, 1, 30, 49, -1, -1, 7, NULL), + (450, 705, 66, 8, 31, 39, -1, -1, 1, NULL), + (451, 705, 687, 32, 31, 36, -1, -1, 0, NULL), + (452, 705, 71, 1, 32, 42, -1, -1, 7, NULL), + (453, 705, 1408, 8, 34, 54, -1, -1, 3, NULL), + (454, 705, 688, 32, 37, 40, -1, -1, 0, NULL), + (455, 705, 171, 8, 39, 46, -1, -1, 7, NULL), + (456, 705, 1474, 8, 40, 62, -1, -1, 1, NULL), + (457, 705, 186, 1, 41, 56, -1, -1, 2, NULL), + (458, 705, 689, 32, 41, 47, -1, -1, 0, NULL), + (459, 705, 1694, 8, 42, 51, -1, -1, 5, NULL), + (460, 705, 25, 512, 42, 52, -1, -1, 7, NULL), + (461, 705, 673, 1, 43, 53, -1, -1, 7, NULL), + (462, 705, 4074, 1, 44, 54, -1, -1, 2, NULL), + (463, 705, 172, 8, 47, 52, -1, -1, 6, NULL), + (464, 705, 195, 1, 47, 58, -1, -1, 6, NULL), + (465, 705, 690, 32, 48, 54, -1, -1, 0, NULL), + (466, 705, 1686, 1, 50, 255, -1, -1, 7, NULL), + (467, 705, 1693, 8, 52, 55, -1, -1, 5, NULL), + (468, 705, 1697, 512, 53, 255, -1, -1, 7, NULL), + (469, 705, 1708, 8, 53, 57, -1, -1, 6, NULL), + (470, 705, 1698, 1, 54, 255, -1, -1, 7, NULL), + (471, 705, 1723, 32, 55, 61, -1, -1, 0, NULL), + (472, 705, 4075, 8, 55, 62, -1, -1, 2, NULL), + (473, 705, 1409, 8, 55, 59, -1, -1, 3, NULL), + (474, 705, 1695, 8, 56, 59, -1, -1, 5, NULL), + (475, 705, 1712, 1, 57, 68, -1, -1, 2, NULL), + (476, 705, 1709, 8, 58, 59, -1, -1, 6, NULL), + (477, 705, 1703, 1, 59, 61, -1, -1, 6, NULL), + (478, 705, 1710, 8, 60, 61, -1, -1, 6, NULL), + (479, 705, 2570, 8, 60, 62, -1, -1, 5, NULL), + (480, 705, 6739, 8, 61, 66, -1, -1, 4, NULL), + (481, 705, 3199, 8, 61, 65, -1, -1, 3, NULL), + (482, 705, 3229, 16, 61, 255, -1, -1, 1, NULL), + (483, 705, 3034, 32, 62, 65, -1, -1, 0, NULL), + (484, 705, 3240, 8, 62, 64, -1, -1, 6, NULL), + (485, 705, 3345, 1, 62, 68, -1, -1, 6, NULL), + (486, 705, 3350, 8, 63, 64, -1, -1, 5, NULL), + (487, 705, 4076, 8, 63, 67, -1, -1, 2, NULL), + (488, 705, 3241, 8, 63, 255, -1, -1, 1, NULL), + (489, 705, 3178, 8, 65, 66, -1, -1, 6, NULL), + (490, 705, 3360, 8, 65, 67, -1, -1, 5, NULL), + (491, 705, 5500, 8, 66, 255, -1, -1, 3, NULL), + (492, 705, 5505, 32, 66, 255, -1, -1, 0, NULL), + (493, 705, 5504, 8, 67, 68, -1, -1, 4, NULL), + (494, 705, 5507, 8, 67, 69, -1, -1, 6, NULL), + (495, 705, 5513, 8, 68, 69, -1, -1, 5, NULL), + (496, 705, 5515, 8, 68, 69, -1, -1, 2, NULL), + (497, 705, 5509, 1, 69, 255, -1, -1, 6, NULL), + (498, 705, 6671, 8, 69, 255, -1, -1, 4, NULL), + (499, 705, 6826, 1, 69, 255, -1, -1, 2, NULL), + (500, 705, 5517, 8, 70, 255, -1, -1, 2, NULL), + (501, 705, 5521, 8, 70, 255, -1, -1, 6, NULL), + (502, 705, 5522, 8, 70, 255, -1, -1, 5, NULL), + (503, 706, 266, 8, 1, 20, -1, -1, 1, NULL), + (504, 706, 40, 8, 1, 7, -1, -1, 2, NULL), + (505, 706, 267, 8, 1, 31, -1, -1, 3, NULL), + (506, 706, 93, 1, 1, 3, -1, -1, 1, NULL), + (507, 706, 200, 2, 1, 18, -1, -1, 2, NULL), + (508, 706, 274, 8, 3, 10, -1, -1, 9, NULL), + (509, 706, 269, 8, 3, 17, -1, -1, 10, NULL), + (510, 706, 275, 1, 4, 13, -1, -1, 5, NULL), + (511, 706, 75, 256, 4, 14, -1, -1, 4, NULL), + (512, 706, 270, 256, 5, 12, -1, -1, 2, NULL), + (513, 706, 279, 8, 6, 21, -1, -1, 11, NULL), + (514, 706, 2521, 8, 8, 17, -1, -1, 2, NULL), + (515, 706, 277, 256, 8, 23, -1, -1, 4, NULL), + (516, 706, 17, 2, 9, 18, -1, -1, 2, NULL), + (517, 706, 283, 8, 11, 19, -1, -1, 9, NULL), + (518, 706, 281, 1, 12, 28, -1, -1, 3, NULL), + (519, 706, 505, 1, 13, 26, -1, -1, 2, NULL), + (520, 706, 365, 256, 15, 18, -1, -1, 4, NULL), + (521, 706, 282, 1, 14, 22, -1, -1, 5, NULL), + (522, 706, 526, 1, 17, 37, -1, -1, 4, NULL), + (523, 706, 110, 1, 18, 31, -1, -1, 1, NULL), + (524, 706, 147, 8, 18, 27, -1, -1, 2, NULL), + (525, 706, 148, 8, 18, 30, -1, -1, 10, NULL), + (526, 706, 12, 2, 19, 28, -1, -1, 2, NULL), + (527, 706, 511, 256, 19, 30, -1, -1, 4, NULL), + (528, 706, 649, 8, 20, 25, -1, -1, 9, NULL), + (529, 706, 146, 8, 21, 24, -1, -1, 1, NULL), + (530, 706, 149, 8, 21, 29, -1, -1, 11, NULL), + (531, 706, 144, 8, 23, 38, -1, -1, 12, NULL), + (532, 706, 508, 1, 23, 32, -1, -1, 5, NULL), + (533, 706, 434, 256, 24, 36, -1, -1, 4, NULL), + (534, 706, 349, 8, 25, 38, -1, -1, 1, NULL), + (535, 706, 39, 8, 26, 41, -1, -1, 9, NULL), + (536, 706, 506, 1, 27, 37, -1, -1, 2, NULL), + (537, 706, 151, 8, 28, 34, -1, -1, 2, NULL), + (538, 706, 15, 2, 29, 50, -1, -1, 2, NULL), + (539, 706, 162, 1, 29, 40, -1, -1, 3, NULL), + (540, 706, 161, 8, 30, 42, -1, -1, 11, NULL), + (541, 706, 160, 8, 31, 40, -1, -1, 10, NULL), + (542, 706, 31, 256, 31, 48, -1, -1, 4, NULL), + (543, 706, 111, 1, 32, 47, -1, -1, 1, NULL), + (544, 706, 164, 32, 32, 36, -1, -1, 0, NULL), + (545, 706, 1428, 8, 35, 38, -1, -1, 2, NULL), + (546, 706, 435, 256, 37, 48, -1, -1, 4, NULL), + (547, 706, 577, 32, 37, 40, -1, -1, 0, NULL), + (548, 706, 507, 1, 38, 50, -1, -1, 2, NULL), + (549, 706, 527, 1, 38, 51, -1, -1, 4, NULL), + (550, 706, 145, 8, 39, 51, -1, -1, 12, NULL), + (551, 706, 152, 8, 39, 47, -1, -1, 1, NULL), + (552, 706, 153, 8, 39, 45, -1, -1, 2, NULL), + (553, 706, 154, 8, 41, 52, -1, -1, 10, NULL), + (554, 706, 163, 1, 41, 52, -1, -1, 3, NULL), + (555, 706, 165, 32, 41, 44, -1, -1, 0, NULL), + (556, 706, 170, 8, 42, 55, -1, -1, 9, NULL), + (557, 706, 158, 8, 43, 53, -1, -1, 11, NULL), + (558, 706, 3694, 1024, 44, 59, -1, -1, 5, NULL), + (559, 706, 754, 1024, 44, 53, -1, -1, 6, NULL), + (560, 706, 166, 32, 45, 54, -1, -1, 0, NULL), + (561, 706, 159, 8, 46, 56, -1, -1, 2, NULL), + (562, 706, 112, 1, 48, 56, -1, -1, 1, NULL), + (563, 706, 157, 8, 48, 57, -1, -1, 1, NULL), + (564, 706, 32, 256, 49, 58, -1, -1, 4, NULL), + (565, 706, 436, 256, 49, 55, -1, -1, 4, NULL), + (566, 706, 1588, 1, 51, 64, -1, -1, 2, NULL), + (567, 706, 9, 2, 51, 54, -1, -1, 2, NULL), + (568, 706, 1568, 8, 52, 55, -1, -1, 12, NULL), + (569, 706, 1573, 1, 52, 62, -1, -1, 4, NULL), + (570, 706, 1592, 1, 53, 65, -1, -1, 3, NULL), + (571, 706, 1594, 8, 53, 56, -1, -1, 10, NULL), + (572, 706, 1595, 8, 54, 56, -1, -1, 11, NULL), + (573, 706, 1572, 1024, 54, 57, -1, -1, 6, NULL), + (574, 706, 1290, 2, 55, 57, -1, -1, 3, NULL), + (575, 706, 1574, 32, 55, 60, -1, -1, 0, NULL), + (576, 706, 171, 8, 56, 62, -1, -1, 9, NULL), + (577, 706, 2528, 8, 56, 60, -1, -1, 12, NULL), + (578, 706, 1590, 256, 56, 59, -1, -1, 4, NULL), + (579, 706, 1580, 8, 57, 61, -1, -1, 11, NULL), + (580, 706, 1577, 1, 57, 59, -1, -1, 1, NULL), + (581, 706, 1593, 8, 57, 57, -1, -1, 2, NULL), + (582, 706, 1579, 8, 57, 60, -1, -1, 10, NULL), + (583, 706, 1596, 8, 58, 58, -1, -1, 1, NULL), + (584, 706, 1581, 8, 58, 59, -1, -1, 2, NULL), + (585, 706, 1332, 1024, 58, 64, -1, -1, 6, NULL), + (586, 706, 1583, 8, 59, 59, -1, -1, 1, NULL), + (587, 706, 1591, 256, 59, 63, -1, -1, 4, NULL), + (588, 706, 2112, 8, 60, 64, -1, -1, 2, NULL), + (589, 706, 2530, 8, 60, 61, -1, -1, 1, NULL), + (590, 706, 2113, 256, 60, 64, -1, -1, 4, NULL), + (591, 706, 1578, 1, 60, 62, -1, -1, 1, NULL), + (592, 706, 1576, 1024, 60, 64, -1, -1, 5, NULL), + (593, 706, 3378, 8, 61, 61, -1, -1, 10, NULL), + (594, 706, 3433, 8, 61, 62, -1, -1, 12, NULL), + (595, 706, 3377, 32, 61, 66, -1, -1, 0, NULL), + (596, 706, 3235, 8, 62, 64, -1, -1, 1, NULL), + (597, 706, 3383, 8, 62, 67, -1, -1, 10, NULL), + (598, 706, 3382, 8, 62, 62, -1, -1, 11, NULL), + (599, 706, 3233, 2, 62, 64, -1, -1, 2, NULL), + (600, 706, 172, 8, 63, 63, -1, -1, 9, NULL), + (601, 706, 3389, 8, 63, 67, -1, -1, 11, NULL), + (602, 706, 3441, 8, 63, 65, -1, -1, 12, NULL), + (603, 706, 3386, 1, 63, 65, -1, -1, 4, NULL), + (604, 706, 3387, 1, 63, 64, -1, -1, 1, NULL), + (605, 706, 3391, 8, 64, 255, -1, -1, 9, NULL), + (606, 706, 3394, 256, 64, 66, -1, -1, 4, NULL), + (607, 706, 3397, 8, 65, 67, -1, -1, 1, NULL), + (608, 706, 3399, 8, 65, 69, -1, -1, 2, NULL), + (609, 706, 3396, 256, 65, 69, -1, -1, 4, NULL), + (610, 706, 4900, 1, 65, 68, -1, -1, 2, NULL), + (611, 706, 3395, 1, 65, 255, -1, -1, 1, NULL), + (612, 706, 4901, 2, 65, 67, -1, -1, 2, NULL), + (613, 706, 4899, 1024, 65, 69, -1, -1, 5, NULL), + (614, 706, 4979, 1024, 65, 69, -1, -1, 6, NULL), + (615, 706, 5393, 8, 66, 68, -1, -1, 12, NULL), + (616, 706, 5394, 1, 66, 255, -1, -1, 3, NULL), + (617, 706, 5392, 1, 66, 255, -1, -1, 4, NULL), + (618, 706, 5411, 256, 67, 255, -1, -1, 4, NULL), + (619, 706, 5389, 32, 67, 255, -1, -1, 0, NULL), + (620, 706, 5396, 8, 68, 69, -1, -1, 1, NULL), + (621, 706, 5398, 8, 68, 68, -1, -1, 11, NULL), + (622, 706, 5395, 2, 68, 69, -1, -1, 2, NULL), + (623, 706, 5399, 8, 68, 255, -1, -1, 10, NULL), + (624, 706, 5405, 8, 69, 255, -1, -1, 11, NULL), + (625, 706, 5406, 8, 69, 255, -1, -1, 12, NULL), + (626, 706, 6827, 1, 69, 255, -1, -1, 2, NULL), + (627, 706, 5416, 1024, 70, 255, -1, -1, 5, NULL), + (628, 706, 5418, 1024, 70, 255, -1, -1, 6, NULL), + (629, 706, 5415, 8, 70, 255, -1, -1, 1, NULL), + (630, 706, 5417, 8, 70, 255, -1, -1, 2, NULL), + (631, 706, 5414, 256, 70, 255, -1, -1, 4, NULL), + (632, 706, 6142, 2, 70, 255, -1, -1, 2, NULL), + (633, 707, 239, 256, 1, 24, -1, -1, 2, NULL), + (634, 707, 242, 128, 1, 25, -1, -1, 1, NULL), + (635, 707, 93, 1, 1, 2, -1, -1, 3, NULL), + (636, 707, 200, 2, 1, 8, -1, -1, 2, NULL), + (637, 707, 248, 1, 2, 12, -1, -1, 2, NULL), + (638, 707, 253, 1, 3, 15, -1, -1, 3, NULL), + (639, 707, 92, 1, 3, 7, -1, -1, 3, NULL), + (640, 707, 256, 8, 7, 16, -1, -1, 1, NULL), + (641, 707, 515, 8, 7, 16, -1, -1, 8, NULL), + (642, 707, 91, 1, 8, 27, -1, -1, 3, NULL), + (643, 707, 17, 2, 9, 18, -1, -1, 2, NULL), + (644, 707, 264, 256, 10, 31, -1, -1, 2, NULL), + (645, 707, 663, 1, 13, 22, -1, -1, 2, NULL), + (646, 707, 520, 1, 16, 29, -1, -1, 3, NULL), + (647, 707, 273, 8, 17, 26, -1, -1, 1, NULL), + (648, 707, 516, 8, 17, 26, -1, -1, 8, NULL), + (649, 707, 12, 2, 19, 28, -1, -1, 2, NULL), + (650, 707, 115, 1, 23, 32, -1, -1, 2, NULL), + (651, 707, 99, 256, 24, 33, -1, -1, 2, NULL), + (652, 707, 78, 256, 25, 36, -1, -1, 2, NULL), + (653, 707, 512, 128, 26, 60, -1, -1, 1, NULL), + (654, 707, 129, 8, 27, 36, -1, -1, 1, NULL), + (655, 707, 517, 8, 27, 36, -1, -1, 8, NULL), + (656, 707, 217, 1, 28, 37, -1, -1, 3, NULL), + (657, 707, 15, 2, 29, 43, -1, -1, 2, NULL), + (658, 707, 1439, 1, 30, 55, -1, -1, 3, NULL), + (659, 707, 259, 256, 32, 39, -1, -1, 2, NULL), + (660, 707, 664, 1, 33, 42, -1, -1, 2, NULL), + (661, 707, 144, 8, 34, 38, -1, -1, 7, NULL), + (662, 707, 1437, 256, 37, 60, -1, -1, 2, NULL), + (663, 707, 432, 8, 37, 46, -1, -1, 1, NULL), + (664, 707, 518, 8, 37, 46, -1, -1, 8, NULL), + (665, 707, 57, 1, 38, 47, -1, -1, 3, NULL), + (666, 707, 137, 8, 39, 41, -1, -1, 7, NULL), + (667, 707, 665, 256, 40, 52, -1, -1, 2, NULL), + (668, 707, 427, 8, 40, 53, -1, -1, 9, NULL), + (669, 707, 1436, 256, 42, 61, -1, -1, 2, NULL), + (670, 707, 145, 8, 42, 44, -1, -1, 7, NULL), + (671, 707, 116, 1, 43, 54, -1, -1, 2, NULL), + (672, 707, 3834, 2, 44, 50, -1, -1, 2, NULL), + (673, 707, 138, 8, 45, 53, -1, -1, 7, NULL), + (674, 707, 29, 1, 47, 54, -1, -1, 3, NULL), + (675, 707, 356, 8, 47, 48, -1, -1, 1, NULL), + (676, 707, 519, 8, 47, 55, -1, -1, 8, NULL), + (677, 707, 671, 1, 48, 53, -1, -1, 3, NULL), + (678, 707, 1727, 8, 49, 57, -1, -1, 1, NULL), + (679, 707, 4104, 256, 49, 255, -1, -1, 2, NULL), + (680, 707, 1562, 8, 54, 59, -1, -1, 9, NULL), + (681, 707, 9, 2, 51, 54, -1, -1, 2, NULL), + (682, 707, 1600, 256, 52, 61, -1, -1, 2, NULL), + (683, 707, 1601, 256, 53, 62, -1, -1, 2, NULL), + (684, 707, 1568, 8, 54, 57, -1, -1, 7, NULL), + (685, 707, 1603, 1, 54, 58, -1, -1, 3, NULL), + (686, 707, 1290, 2, 55, 59, -1, -1, 2, NULL), + (687, 707, 1529, 1, 55, 64, -1, -1, 2, NULL), + (688, 707, 1605, 1, 55, 59, -1, -1, 3, NULL), + (689, 707, 4105, 256, 55, 255, -1, -1, 2, NULL), + (690, 707, 1558, 8, 56, 63, -1, -1, 8, NULL), + (691, 707, 1604, 1, 56, 60, -1, -1, 3, NULL), + (692, 707, 1560, 8, 58, 58, -1, -1, 1, NULL), + (693, 707, 1569, 8, 58, 59, -1, -1, 7, NULL), + (694, 707, 1561, 8, 59, 59, -1, -1, 1, NULL), + (695, 707, 1607, 1, 59, 59, -1, -1, 3, NULL), + (696, 707, 1563, 8, 60, 255, -1, -1, 9, NULL), + (697, 707, 1291, 2, 60, 62, -1, -1, 2, NULL), + (698, 707, 2125, 8, 60, 62, -1, -1, 1, NULL), + (699, 707, 2126, 1, 60, 63, -1, -1, 3, NULL), + (700, 707, 2520, 8, 60, 60, -1, -1, 7, NULL), + (701, 707, 2877, 1, 60, 64, -1, -1, 3, NULL), + (702, 707, 3433, 8, 61, 62, -1, -1, 7, NULL), + (703, 707, 3434, 1, 61, 65, -1, -1, 3, NULL), + (704, 707, 5572, 128, 61, 68, -1, -1, 1, NULL), + (705, 707, 3437, 256, 62, 63, -1, -1, 2, NULL), + (706, 707, 3440, 256, 62, 64, -1, -1, 2, NULL), + (707, 707, 3441, 8, 63, 65, -1, -1, 7, NULL), + (708, 707, 3443, 2, 63, 65, -1, -1, 2, NULL), + (709, 707, 3446, 256, 63, 67, -1, -1, 2, NULL), + (710, 707, 3448, 8, 63, 64, -1, -1, 1, NULL), + (711, 707, 3444, 8, 64, 255, -1, -1, 8, NULL), + (712, 707, 3449, 1, 64, 64, -1, -1, 3, NULL), + (713, 707, 4106, 256, 64, 255, -1, -1, 2, NULL), + (714, 707, 3238, 1, 65, 67, -1, -1, 2, NULL), + (715, 707, 3295, 8, 65, 66, -1, -1, 1, NULL), + (716, 707, 4974, 1, 65, 66, -1, -1, 3, NULL), + (717, 707, 4883, 2, 65, 67, -1, -1, 2, NULL), + (718, 707, 4884, 1, 65, 68, -1, -1, 3, NULL), + (719, 707, 4885, 256, 65, 66, -1, -1, 2, NULL), + (720, 707, 5342, 8, 66, 68, -1, -1, 7, NULL), + (721, 707, 5343, 1, 66, 255, -1, -1, 3, NULL), + (722, 707, 5348, 1, 67, 255, -1, -1, 3, NULL), + (723, 707, 5358, 8, 67, 69, -1, -1, 1, NULL), + (724, 707, 5355, 2, 68, 69, -1, -1, 2, NULL), + (725, 707, 5357, 256, 68, 255, -1, -1, 2, NULL), + (726, 707, 8008, 1, 68, 255, -1, -1, 1, NULL), + (727, 707, 5353, 8, 69, 255, -1, -1, 7, NULL), + (728, 707, 5361, 1, 69, 255, -1, -1, 3, NULL), + (729, 707, 6665, 128, 69, 255, -1, -1, 1, NULL), + (730, 707, 5365, 8, 70, 255, -1, -1, 1, NULL), + (731, 707, 6141, 2, 70, 255, -1, -1, 2, NULL), + (732, 708, 5011, 2, 1, 5, -1, -1, 2, NULL), + (733, 708, 200, 2, 6, 11, -1, -1, 2, NULL), + (734, 708, 2581, 1, 7, 12, -1, -1, 3, NULL), + (735, 708, 202, 8, 8, 19, -1, -1, 1, NULL), + (736, 708, 17, 2, 12, 26, -1, -1, 2, NULL), + (737, 708, 2582, 1, 13, 27, -1, -1, 3, NULL), + (738, 708, 218, 1, 14, 29, -1, -1, 2, NULL), + (739, 708, 11, 8, 15, 29, -1, -1, 2, NULL), + (740, 708, 219, 8, 20, 36, -1, -1, 1, NULL), + (741, 708, 485, 8, 24, 32, -1, -1, 3, NULL), + (742, 708, 2583, 8, 26, 62, -1, -1, 5, NULL), + (743, 708, 12, 2, 27, 35, -1, -1, 2, NULL), + (744, 708, 216, 1, 28, 41, -1, -1, 3, NULL), + (745, 708, 233, 1, 30, 45, -1, -1, 2, NULL), + (746, 708, 368, 8, 30, 38, -1, -1, 2, NULL), + (747, 708, 486, 8, 33, 45, -1, -1, 3, NULL), + (748, 708, 2584, 8, 35, 48, -1, -1, 4, NULL), + (749, 708, 15, 2, 36, 51, -1, -1, 2, NULL), + (750, 708, 89, 8, 37, 46, -1, -1, 1, NULL), + (751, 708, 18, 8, 39, 47, -1, -1, 2, NULL), + (752, 708, 123, 1, 42, 51, -1, -1, 3, NULL), + (753, 708, 2585, 8, 44, 255, -1, -1, 7, NULL), + (754, 708, 3683, 2, 44, 58, -1, -1, 1, NULL), + (755, 708, 117, 1, 46, 53, -1, -1, 2, NULL), + (756, 708, 487, 8, 46, 57, -1, -1, 3, NULL), + (757, 708, 312, 8, 47, 59, -1, -1, 1, NULL), + (758, 708, 19, 8, 48, 59, -1, -1, 2, NULL), + (759, 708, 207, 16, 48, 255, -1, -1, 1, NULL), + (760, 708, 3578, 8, 49, 52, -1, -1, 4, NULL), + (761, 708, 124, 1, 52, 52, -1, -1, 3, NULL), + (762, 708, 3684, 2, 52, 56, -1, -1, 2, NULL), + (763, 708, 1288, 8, 53, 59, -1, -1, 4, NULL), + (764, 708, 3975, 1, 53, 53, -1, -1, 3, NULL), + (765, 708, 2587, 1, 54, 61, -1, -1, 3, NULL), + (766, 708, 662, 1, 54, 61, -1, -1, 2, NULL), + (767, 708, 1743, 8, 55, 255, -1, -1, 2, NULL), + (768, 708, 9, 2, 57, 60, -1, -1, 2, NULL), + (769, 708, 488, 8, 58, 62, -1, -1, 3, NULL), + (770, 708, 1283, 2, 59, 63, -1, -1, 1, NULL), + (771, 708, 2590, 8, 60, 64, -1, -1, 4, NULL), + (772, 708, 314, 8, 60, 60, -1, -1, 1, NULL), + (773, 708, 20, 8, 60, 64, -1, -1, 2, NULL), + (774, 708, 1533, 8, 61, 63, -1, -1, 1, NULL), + (775, 708, 3429, 2, 61, 62, -1, -1, 2, NULL), + (776, 708, 3245, 1, 62, 63, -1, -1, 3, NULL), + (777, 708, 3428, 1, 62, 66, -1, -1, 2, NULL), + (778, 708, 3430, 2, 63, 64, -1, -1, 2, NULL), + (779, 708, 1535, 8, 63, 64, -1, -1, 3, NULL), + (780, 708, 3424, 8, 63, 64, -1, -1, 5, NULL), + (781, 708, 1538, 8, 64, 64, -1, -1, 1, NULL), + (782, 708, 3426, 1, 64, 64, -1, -1, 3, NULL), + (783, 708, 3247, 8, 64, 68, -1, -1, 9, NULL), + (784, 708, 2589, 2, 64, 255, -1, -1, 2, NULL), + (785, 708, 4894, 2, 65, 67, -1, -1, 2, NULL), + (786, 708, 3432, 8, 65, 69, -1, -1, 4, NULL), + (787, 708, 4109, 8, 65, 69, -1, -1, 2, NULL), + (788, 708, 4895, 8, 65, 67, -1, -1, 5, NULL), + (789, 708, 4977, 1, 65, 65, -1, -1, 3, NULL), + (790, 708, 5284, 1, 66, 67, -1, -1, 3, NULL), + (791, 708, 5286, 1, 67, 67, -1, -1, 2, NULL), + (792, 708, 5289, 2, 68, 255, -1, -1, 2, NULL), + (793, 708, 8027, 1, 68, 255, -1, -1, 2, NULL), + (794, 708, 5288, 8, 68, 255, -1, -1, 5, NULL), + (795, 708, 5292, 1, 68, 69, -1, -1, 3, NULL), + (796, 708, 5291, 8, 69, 255, -1, -1, 9, NULL), + (797, 708, 8029, 8, 69, 255, -1, -1, 10, NULL), + (798, 708, 5298, 8, 70, 255, -1, -1, 2, NULL), + (799, 708, 5297, 8, 70, 255, -1, -1, 4, NULL), + (800, 708, 5299, 1, 70, 255, -1, -1, 3, NULL), + (801, 709, 5012, 1, 1, 33, -1, -1, 5, NULL), + (802, 709, 340, 256, 5, 56, -1, -1, 3, NULL), + (803, 709, 491, 32, 7, 13, -1, -1, 0, NULL), + (804, 709, 341, 64, 8, 14, -1, -1, 3, NULL), + (805, 709, 2571, 1, 9, 49, -1, -1, 2, NULL), + (806, 709, 344, 128, 11, 19, -1, -1, 1, NULL), + (807, 709, 229, 1, 12, 42, -1, 45, 4, NULL), + (808, 709, 351, 32, 14, 21, -1, -1, 0, NULL), + (809, 709, 502, 64, 15, 28, -1, -1, 3, NULL), + (810, 709, 346, 8, 16, 57, -1, -1, 1, NULL), + (811, 709, 355, 128, 20, 43, -1, -1, 1, NULL), + (812, 709, 359, 8, 22, 36, -1, -1, 2, NULL), + (813, 709, 362, 32, 22, 29, -1, -1, 0, NULL), + (814, 709, 360, 256, 28, 40, -1, -1, 3, NULL), + (815, 709, 1289, 8, 29, 59, -1, -1, 9, NULL), + (816, 709, 445, 64, 29, 46, -1, -1, 3, NULL), + (817, 709, 492, 32, 30, 37, -1, -1, 0, NULL), + (818, 709, 236, 8, 31, 55, -1, -1, 8, NULL), + (819, 709, 3561, 1, 34, 47, -1, -1, 5, NULL), + (820, 709, 367, 256, 36, 59, -1, -1, 3, NULL), + (821, 709, 2574, 8, 37, 54, -1, -1, 2, NULL), + (822, 709, 370, 1, 37, 49, -1, -1, 2, NULL), + (823, 709, 440, 32, 38, 45, -1, -1, 0, NULL), + (824, 709, 3686, 256, 41, 52, -1, -1, 3, NULL), + (825, 709, 127, 1, 43, 56, -1, 45, 4, NULL), + (826, 709, 452, 128, 44, 58, -1, -1, 1, NULL), + (827, 709, 441, 32, 46, 51, -1, -1, 0, NULL), + (828, 709, 692, 64, 47, 56, -1, -1, 3, NULL), + (829, 709, 3560, 1, 48, 53, -1, -1, 5, NULL), + (830, 709, 199, 16, 50, 255, -1, -1, 1, NULL), + (831, 709, 442, 32, 52, 57, -1, -1, 0, NULL), + (832, 709, 451, 256, 53, 60, -1, -1, 3, NULL), + (833, 709, 3562, 1, 54, 63, -1, -1, 5, NULL), + (834, 709, 1376, 8, 55, 62, -1, -1, 2, NULL), + (835, 709, 393, 8, 56, 58, -1, -1, 8, NULL), + (836, 709, 454, 256, 57, 61, -1, -1, 3, NULL), + (837, 709, 525, 64, 57, 59, -1, -1, 3, NULL), + (838, 709, 6986, 1, 57, 61, -1, -1, 4, NULL), + (839, 709, 495, 32, 58, 63, -1, -1, 0, NULL), + (840, 709, 394, 8, 59, 255, -1, -1, 8, NULL), + (841, 709, 453, 128, 59, 60, -1, -1, 1, NULL), + (842, 709, 661, 8, 60, 63, -1, -1, 9, NULL), + (843, 709, 1508, 256, 60, 65, -1, -1, 3, NULL), + (844, 709, 447, 64, 60, 61, -1, -1, 3, NULL), + (845, 709, 3400, 128, 61, 255, -1, -1, 1, NULL), + (846, 709, 6, 256, 61, 62, -1, -1, 3, NULL), + (847, 709, 456, 256, 62, 65, -1, -1, 3, NULL), + (848, 709, 3401, 64, 62, 64, -1, -1, 3, NULL), + (849, 709, 3227, 8, 63, 64, -1, -1, 2, NULL), + (850, 709, 3489, 256, 63, 65, -1, -1, 3, NULL), + (851, 709, 6987, 1, 62, 66, -1, -1, 4, NULL), + (852, 709, 1414, 8, 64, 68, -1, -1, 9, NULL), + (853, 709, 3491, 1, 64, 64, -1, -1, 5, NULL), + (854, 709, 443, 32, 64, 67, -1, -1, 0, NULL), + (855, 709, 3413, 64, 65, 66, -1, -1, 3, NULL), + (856, 709, 4904, 1, 65, 68, -1, -1, 5, NULL), + (857, 709, 5323, 256, 66, 255, -1, -1, 3, NULL), + (858, 709, 5320, 256, 66, 67, -1, -1, 3, NULL), + (859, 709, 5322, 256, 66, 255, -1, -1, 3, NULL), + (860, 709, 5327, 8, 67, 255, -1, -1, 2, NULL), + (861, 709, 5324, 64, 67, 69, -1, -1, 3, NULL), + (862, 709, 6988, 1, 67, 255, -1, -1, 4, NULL), + (863, 709, 5330, 256, 68, 255, -1, -1, 3, NULL), + (864, 709, 5331, 32, 68, 255, -1, -1, 0, NULL), + (865, 709, 5332, 8, 69, 255, -1, -1, 9, NULL), + (866, 709, 5334, 1, 69, 255, -1, -1, 5, NULL), + (867, 709, 5338, 64, 70, 255, -1, -1, 3, NULL), + (868, 710, 5011, 2, 1, 7, -1, -1, 2, NULL), + (869, 710, 239, 256, 3, 43, -1, -1, 3, NULL), + (870, 710, 2591, 128, 5, 5, -1, -1, 1, NULL), + (871, 710, 242, 128, 6, 50, -1, -1, 1, NULL), + (872, 710, 26, 8, 7, 20, -1, -1, 1, NULL), + (873, 710, 200, 2, 8, 20, -1, -1, 2, NULL), + (874, 710, 2592, 8, 11, 51, -1, -1, 9, NULL), + (875, 710, 269, 8, 12, 54, -1, -1, 8, NULL), + (876, 710, 515, 8, 13, 29, -1, -1, 7, NULL), + (877, 710, 92, 1, 14, 18, -1, -1, 4, NULL), + (878, 710, 254, 8, 17, 36, -1, -1, 6, NULL), + (879, 710, 91, 1, 19, 28, -1, -1, 4, NULL), + (880, 710, 17, 2, 21, 37, -1, -1, 2, NULL), + (881, 710, 263, 8, 21, 37, -1, -1, 1, NULL), + (882, 710, 256, 8, 24, 42, -1, -1, 5, NULL), + (883, 710, 264, 256, 25, 39, -1, -1, 3, NULL), + (884, 710, 268, 8, 26, 52, -1, -1, 4, NULL), + (885, 710, 2593, 8, 29, 47, -1, -1, 2, NULL), + (886, 710, 3565, 1, 29, 38, -1, -1, 4, NULL), + (887, 710, 516, 8, 30, 33, -1, -1, 7, NULL), + (888, 710, 517, 8, 34, 41, -1, -1, 7, NULL), + (889, 710, 1461, 8, 36, 54, -1, -1, 10, NULL), + (890, 710, 2594, 8, 37, 50, -1, -1, 6, NULL), + (891, 710, 12, 2, 38, 56, -1, -1, 2, NULL), + (892, 710, 421, 8, 38, 53, -1, -1, 1, NULL), + (893, 710, 3564, 1, 39, 48, -1, -1, 4, NULL), + (894, 710, 3687, 256, 40, 53, -1, -1, 3, NULL), + (895, 710, 518, 8, 42, 59, -1, -1, 7, NULL), + (896, 710, 129, 8, 43, 57, -1, -1, 5, NULL), + (897, 710, 78, 256, 44, 255, -1, -1, 3, NULL), + (898, 710, 2595, 8, 48, 49, -1, -1, 2, NULL), + (899, 710, 691, 1, 49, 51, -1, -1, 4, NULL), + (900, 710, 1462, 8, 50, 61, -1, -1, 2, NULL), + (901, 710, 1741, 16, 50, 54, -1, -1, 1, NULL), + (902, 710, 1397, 8, 51, 61, -1, -1, 6, NULL), + (903, 710, 512, 128, 51, 60, -1, -1, 1, NULL), + (904, 710, 2596, 8, 52, 57, -1, -1, 9, NULL), + (905, 710, 57, 1, 52, 58, -1, -1, 4, NULL), + (906, 710, 430, 8, 53, 255, -1, -1, 4, NULL), + (907, 710, 259, 256, 54, 61, -1, -1, 3, NULL), + (908, 710, 422, 8, 54, 58, -1, -1, 1, NULL), + (909, 710, 1296, 16, 55, 255, -1, -1, 1, NULL), + (910, 710, 145, 8, 55, 63, -1, -1, 8, NULL), + (911, 710, 1463, 8, 55, 57, -1, -1, 10, NULL), + (912, 710, 15, 2, 57, 61, -1, -1, 2, NULL), + (913, 710, 432, 8, 58, 61, -1, -1, 5, NULL), + (914, 710, 4059, 8, 58, 63, -1, -1, 10, NULL), + (915, 710, 2599, 8, 58, 255, -1, -1, 9, NULL), + (916, 710, 423, 8, 59, 64, -1, -1, 1, NULL), + (917, 710, 1740, 1, 59, 63, -1, -1, 4, NULL), + (918, 710, 519, 8, 60, 62, -1, -1, 7, NULL), + (919, 710, 6732, 128, 61, 68, -1, -1, 1, NULL), + (920, 710, 3419, 8, 62, 66, -1, -1, 2, NULL), + (921, 710, 356, 8, 62, 65, -1, -1, 5, NULL), + (922, 710, 3487, 8, 62, 66, -1, -1, 6, NULL), + (923, 710, 665, 256, 62, 66, -1, -1, 3, NULL), + (924, 710, 1290, 2, 62, 64, -1, -1, 2, NULL), + (925, 710, 1558, 8, 63, 67, -1, -1, 7, NULL), + (926, 710, 1568, 8, 64, 67, -1, -1, 8, NULL), + (927, 710, 3415, 8, 64, 64, -1, -1, 10, NULL), + (928, 710, 3431, 1, 64, 64, -1, -1, 4, NULL), + (929, 710, 1559, 8, 65, 69, -1, -1, 1, NULL), + (930, 710, 4898, 8, 65, 68, -1, -1, 10, NULL), + (931, 710, 4980, 1, 65, 68, -1, -1, 4, NULL), + (932, 710, 4896, 2, 65, 66, -1, -1, 2, NULL), + (933, 710, 5302, 8, 66, 255, -1, -1, 5, NULL), + (934, 710, 5305, 8, 66, 255, -1, -1, 2, NULL), + (935, 710, 5306, 8, 67, 255, -1, -1, 6, NULL), + (936, 710, 5303, 256, 67, 255, -1, -1, 3, NULL), + (937, 710, 5304, 2, 67, 255, -1, -1, 2, NULL), + (938, 710, 5307, 8, 68, 255, -1, -1, 7, NULL), + (939, 710, 5310, 8, 68, 255, -1, -1, 8, NULL), + (940, 710, 5311, 8, 69, 255, -1, -1, 10, NULL), + (941, 710, 6664, 128, 69, 255, -1, -1, 1, NULL), + (942, 710, 5313, 1, 69, 69, -1, -1, 4, NULL), + (943, 710, 5315, 8, 70, 255, -1, -1, 1, NULL), + (944, 710, 5319, 1, 70, 255, -1, -1, 4, NULL), + (945, 711, 700, 8, 1, 9, -1, -1, 1, NULL), + (946, 711, 7, 2, 6, 33, -1, -1, 2, NULL), + (947, 711, 710, 8, 9, 12, -1, -1, 2, NULL), + (948, 711, 701, 8, 10, 35, -1, -1, 1, NULL), + (949, 711, 711, 8, 13, 24, -1, -1, 2, NULL), + (950, 711, 709, 8, 17, 51, -1, -1, 3, NULL), + (951, 711, 1287, 2, 20, 31, -1, -1, 2, NULL), + (952, 711, 738, 1, 23, 255, -1, -1, 3, NULL), + (953, 711, 712, 8, 25, 28, -1, -1, 2, NULL), + (954, 711, 715, 8, 29, 32, -1, -1, 3, NULL), + (955, 711, 707, 1, 30, 37, -1, -1, 2, NULL), + (956, 711, 723, 2, 32, 33, -1, -1, 3, NULL), + (957, 711, 713, 8, 33, 36, -1, -1, 2, NULL), + (958, 711, 1448, 2, 34, 54, -1, -1, 2, NULL), + (959, 711, 740, 8, 36, 41, -1, -1, 1, NULL), + (960, 711, 716, 8, 37, 40, -1, -1, 2, NULL), + (961, 711, 743, 1, 38, 41, -1, -1, 4, NULL), + (962, 711, 714, 8, 41, 46, -1, -1, 2, NULL), + (963, 711, 3567, 1, 42, 45, -1, -1, 5, NULL), + (964, 711, 702, 8, 42, 49, -1, -1, 1, NULL), + (965, 711, 744, 1, 46, 49, -1, -1, 6, NULL), + (966, 711, 748, 8, 47, 53, -1, -1, 2, NULL), + (967, 711, 3566, 1, 50, 62, -1, -1, 2, NULL), + (968, 711, 747, 8, 50, 53, -1, -1, 1, NULL), + (969, 711, 1751, 1, 51, 255, -1, -1, 4, NULL), + (970, 711, 2606, 8, 52, 59, -1, -1, 3, NULL), + (971, 711, 1754, 16, 53, 59, -1, -1, 1, NULL), + (972, 711, 2607, 8, 54, 255, -1, -1, 2, NULL), + (973, 711, 1759, 2, 55, 57, -1, -1, 2, NULL), + (974, 711, 2609, 2, 58, 59, -1, -1, 2, NULL), + (975, 711, 1196, 2, 60, 61, -1, -1, 2, NULL), + (976, 711, 1749, 16, 60, 255, -1, -1, 1, NULL), + (977, 711, 2610, 8, 60, 63, -1, -1, 3, NULL), + (978, 711, 3374, 8, 62, 64, -1, -1, 1, NULL), + (979, 711, 3651, 2, 62, 63, -1, -1, 2, NULL), + (980, 711, 3370, 1, 63, 63, -1, -1, 2, NULL), + (981, 711, 3066, 1, 64, 255, -1, -1, 2, NULL), + (982, 711, 3362, 8, 64, 64, -1, -1, 3, NULL), + (983, 711, 3372, 2, 64, 66, -1, -1, 2, NULL), + (984, 711, 4871, 8, 65, 67, -1, -1, 1, NULL), + (985, 711, 4872, 8, 65, 67, -1, -1, 3, NULL), + (986, 711, 5377, 2, 67, 68, -1, -1, 2, NULL), + (987, 711, 5376, 8, 68, 255, -1, -1, 1, NULL), + (988, 711, 5380, 8, 68, 68, -1, -1, 3, NULL), + (989, 711, 5382, 8, 69, 69, -1, -1, 3, NULL), + (990, 711, 5384, 2, 69, 255, -1, -1, 2, NULL), + (991, 711, 5388, 8, 70, 255, -1, -1, 3, NULL), + (992, 712, 5011, 2, 1, 5, -1, -1, 2, NULL), + (993, 712, 200, 2, 6, 19, -1, -1, 2, NULL), + (994, 712, 267, 8, 7, 19, -1, -1, 9, NULL), + (995, 712, 2612, 32, 8, 14, -1, -1, 0, NULL), + (996, 712, 2611, 2, 9, 14, -1, -1, 2, NULL), + (997, 712, 274, 8, 10, 25, -1, -1, 8, NULL), + (998, 712, 2068, 1, 12, 25, -1, -1, 4, NULL), + (999, 712, 2635, 8, 13, 17, -1, -1, 6, NULL), + (1000, 712, 40, 8, 14, 27, -1, -1, 5, NULL), + (1001, 712, 75, 256, 14, 39, -1, -1, 3, NULL), + (1002, 712, 2613, 2, 15, 26, -1, -1, 2, NULL), + (1003, 712, 2633, 32, 15, 20, -1, -1, 0, NULL), + (1004, 712, 279, 8, 17, 36, -1, -1, 4, NULL), + (1005, 712, 2636, 8, 18, 27, -1, -1, 6, NULL), + (1006, 712, 277, 256, 19, 34, -1, -1, 3, NULL), + (1007, 712, 270, 1, 20, 49, -1, -1, 3, NULL), + (1008, 712, 17, 2, 20, 35, -1, -1, 2, NULL), + (1009, 712, 2614, 32, 21, 29, -1, -1, 0, NULL), + (1010, 712, 282, 1, 26, 32, -1, -1, 4, NULL), + (1011, 712, 283, 8, 26, 36, -1, -1, 8, NULL), + (1012, 712, 2615, 2, 27, 35, -1, -1, 2, NULL), + (1013, 712, 147, 8, 28, 40, -1, -1, 5, NULL), + (1014, 712, 2637, 8, 28, 37, -1, -1, 6, NULL), + (1015, 712, 2616, 32, 30, 38, -1, -1, 0, NULL), + (1016, 712, 3568, 1, 33, 46, -1, -1, 4, NULL), + (1017, 712, 434, 256, 35, 51, -1, -1, 3, NULL), + (1018, 712, 48, 512, 35, 57, -1, -1, 6, NULL), + (1019, 712, 12, 2, 36, 56, -1, -1, 2, NULL), + (1020, 712, 2617, 2, 36, 48, -1, -1, 2, NULL), + (1021, 712, 2619, 8, 37, 51, -1, -1, 8, NULL), + (1022, 712, 149, 8, 37, 51, -1, -1, 3, NULL), + (1023, 712, 2638, 8, 38, 45, -1, -1, 6, NULL), + (1024, 712, 2618, 32, 39, 45, -1, -1, 0, NULL), + (1025, 712, 3689, 256, 40, 64, -1, -1, 3, NULL), + (1026, 712, 151, 8, 41, 53, -1, -1, 5, NULL), + (1027, 712, 2176, 8, 41, 51, -1, -1, 4, NULL), + (1028, 712, 2178, 8, 42, 59, -1, -1, 2, NULL), + (1029, 712, 2621, 32, 46, 53, -1, -1, 0, NULL), + (1030, 712, 2639, 8, 46, 50, -1, -1, 6, NULL), + (1031, 712, 308, 8, 47, 255, -1, -1, 7, NULL), + (1032, 712, 3569, 1, 47, 53, -1, -1, 4, NULL), + (1033, 712, 2620, 2, 49, 51, -1, -1, 2, NULL), + (1034, 712, 2634, 1, 50, 59, -1, -1, 3, NULL), + (1035, 712, 2640, 8, 51, 52, -1, -1, 6, NULL), + (1036, 712, 161, 8, 52, 56, -1, -1, 3, NULL), + (1037, 712, 2177, 8, 52, 58, -1, -1, 4, NULL), + (1038, 712, 2622, 2, 52, 54, -1, -1, 2, NULL), + (1039, 712, 3690, 8, 52, 54, -1, -1, 8, NULL), + (1040, 712, 435, 256, 52, 60, -1, -1, 3, NULL), + (1041, 712, 167, 8, 53, 57, -1, -1, 6, NULL), + (1042, 712, 153, 8, 54, 255, -1, -1, 5, NULL), + (1043, 712, 2623, 32, 54, 55, -1, -1, 0, NULL), + (1044, 712, 3570, 1, 54, 58, -1, -1, 4, NULL), + (1045, 712, 2625, 8, 55, 58, -1, -1, 8, NULL), + (1046, 712, 145, 8, 55, 63, -1, -1, 1, NULL), + (1047, 712, 2626, 32, 56, 57, -1, -1, 0, NULL), + (1048, 712, 15, 2, 57, 61, -1, -1, 2, NULL), + (1049, 712, 158, 8, 57, 255, -1, -1, 3, NULL), + (1050, 712, 168, 8, 58, 61, -1, -1, 6, NULL), + (1051, 712, 2627, 32, 58, 59, -1, -1, 0, NULL), + (1052, 712, 49, 512, 58, 59, -1, -1, 6, NULL), + (1053, 712, 2628, 8, 59, 62, -1, -1, 8, NULL), + (1054, 712, 2629, 8, 59, 63, -1, -1, 4, NULL), + (1055, 712, 510, 1, 59, 62, -1, -1, 4, NULL), + (1056, 712, 2941, 8, 60, 64, -1, -1, 10, NULL), + (1057, 712, 2630, 8, 60, 61, -1, -1, 2, NULL), + (1058, 712, 2631, 32, 60, 61, -1, -1, 0, NULL), + (1059, 712, 2942, 1, 60, 64, -1, -1, 3, NULL), + (1060, 712, 3492, 256, 61, 65, -1, -1, 3, NULL), + (1061, 712, 3456, 8, 62, 66, -1, -1, 2, NULL), + (1062, 712, 1585, 8, 62, 66, -1, -1, 6, NULL), + (1063, 712, 1290, 2, 62, 64, -1, -1, 2, NULL), + (1064, 712, 3457, 32, 62, 63, -1, -1, 0, NULL), + (1065, 712, 3458, 8, 63, 67, -1, -1, 8, NULL), + (1066, 712, 3493, 1, 63, 64, -1, -1, 4, NULL), + (1067, 712, 1568, 8, 64, 68, -1, -1, 1, NULL), + (1068, 712, 3460, 8, 64, 68, -1, -1, 4, NULL), + (1069, 712, 3461, 32, 64, 67, -1, -1, 0, NULL), + (1070, 712, 3463, 8, 65, 69, -1, -1, 10, NULL), + (1071, 712, 32, 256, 65, 69, -1, -1, 3, NULL), + (1072, 712, 3462, 1, 65, 69, -1, -1, 3, NULL), + (1073, 712, 4972, 1, 65, 68, -1, -1, 4, NULL), + (1074, 712, 4875, 2, 65, 66, -1, -1, 2, NULL), + (1075, 712, 5527, 256, 66, 255, -1, -1, 3, NULL), + (1076, 712, 5530, 8, 67, 255, -1, -1, 2, NULL), + (1077, 712, 5529, 8, 67, 255, -1, -1, 6, NULL), + (1078, 712, 5528, 2, 67, 255, -1, -1, 2, NULL), + (1079, 712, 5533, 8, 68, 255, -1, -1, 8, NULL), + (1080, 712, 5531, 32, 68, 69, -1, -1, 0, NULL), + (1081, 712, 5536, 8, 69, 255, -1, -1, 1, NULL), + (1082, 712, 5537, 8, 69, 255, -1, -1, 4, NULL), + (1083, 712, 5535, 1, 69, 69, -1, -1, 4, NULL), + (1084, 712, 5542, 8, 70, 255, -1, -1, 10, NULL), + (1085, 712, 5540, 256, 70, 255, -1, -1, 3, NULL), + (1086, 712, 6828, 1, 70, 255, -1, -1, 3, NULL), + (1087, 712, 5543, 1, 70, 255, -1, -1, 4, NULL), + (1088, 712, 5538, 32, 70, 255, -1, -1, 0, NULL), + (1089, 707, 425, 8, 20, 255, -1, -1, 0, NULL), + (1090, 705, 190, 2048, 47, 55, -1, -1, 0, NULL), + (1091, 705, 292, 2048, 2, 12, -1, -1, 0, NULL), + (1092, 705, 187, 2048, 13, 29, -1, -1, 0, NULL), + (1093, 705, 188, 2048, 30, 46, -1, -1, 0, NULL), + (1094, 705, 1691, 2048, 54, 58, -1, -1, 0, NULL), + (1095, 705, 1692, 2048, 59, 59, -1, -1, 0, NULL), + (1096, 705, 2120, 2048, 60, 60, -1, -1, 0, NULL), + (1097, 705, 3341, 2048, 61, 62, -1, -1, 0, NULL), + (1098, 705, 3354, 2048, 63, 63, -1, -1, 0, NULL), + (1099, 705, 3358, 2048, 64, 66, -1, -1, 0, NULL), + (1100, 705, 5503, 2048, 67, 67, -1, -1, 0, NULL), + (1101, 705, 8035, 2048, 68, 68, -1, -1, 0, NULL), + (1102, 705, 5520, 2048, 69, 255, -1, -1, 0, NULL), + (1103, 709, 343, 16384, 6, 51, -1, -1, 3, NULL), + (1104, 709, 2572, 16384, 15, 34, -1, -1, 3, NULL), + (1105, 709, 2573, 16384, 23, 49, -1, -1, 3, NULL), + (1106, 709, 1457, 16384, 35, 53, -1, -1, 3, NULL), + (1107, 709, 1458, 16384, 50, 55, -1, -1, 3, NULL), + (1108, 709, 2575, 16384, 52, 59, -1, -1, 3, NULL), + (1109, 709, 2577, 16384, 54, 64, -1, -1, 3, NULL), + (1110, 709, 2578, 16384, 56, 62, -1, -1, 3, NULL), + (1111, 709, 2579, 16384, 58, 65, -1, -1, 3, NULL), + (1112, 709, 3406, 16384, 61, 70, -1, -1, 2, NULL), + (1113, 707, 3435, 16384, 61, 85, -1, -1, 2, NULL), + (1114, 707, 5351, 16384, 67, 73, -1, -1, 2, NULL), + (1115, 707, 5354, 16384, 67, 71, -1, -1, 2, NULL), + (1116, 703, 343, 16384, 1, 12, -1, -1, 3, NULL), + (1117, 703, 1511, 16384, 10, 20, -1, -1, 3, NULL), + (1118, 703, 1512, 16384, 21, 36, -1, -1, 3, NULL), + (1119, 703, 1513, 16384, 37, 51, -1, -1, 3, NULL), + (1120, 703, 1716, 16384, 52, 67, -1, -1, 3, NULL), + (1121, 703, 2546, 16384, 52, 65, -1, -1, 3, NULL), + (1122, 703, 5427, 16384, 68, 71, -1, -1, 3, NULL), + (1123, 704, 110, 16384, 22, 43, -1, -1, 2, NULL), + (1124, 704, 111, 16384, 44, 50, -1, -1, 2, NULL), + (1125, 704, 112, 16384, 51, 57, -1, -1, 2, NULL), + (1126, 704, 1577, 16384, 58, 59, -1, -1, 2, NULL), + (1127, 704, 1772, 16384, 60, 255, -1, -1, 1, NULL), + (1128, 704, 3387, 16384, 63, 70, -1, -1, 2, NULL), + (1129, 705, 41, 16384, 1, 3, -1, -1, 3, NULL), + (1130, 705, 676, 16384, 2, 17, -1, -1, 1, NULL), + (1131, 705, 291, 16384, 4, 8, -1, -1, 3, NULL), + (1132, 705, 645, 16384, 9, 18, -1, -1, 3, NULL), + (1133, 705, 281, 16384, 16, 24, -1, -1, 3, NULL), + (1134, 705, 677, 16384, 18, 40, -1, -1, 1, NULL), + (1135, 705, 179, 16384, 19, 33, -1, -1, 4, NULL), + (1136, 705, 162, 16384, 25, 39, -1, -1, 3, NULL), + (1137, 705, 180, 16384, 34, 41, -1, -1, 4, NULL), + (1138, 705, 163, 16384, 40, 52, -1, -1, 3, NULL), + (1139, 705, 678, 16384, 41, 56, -1, -1, 1, NULL), + (1140, 705, 181, 16384, 42, 52, -1, -1, 4, NULL), + (1141, 705, 1592, 16384, 53, 65, -1, -1, 3, NULL), + (1142, 705, 1702, 16384, 57, 60, -1, -1, 1, NULL), + (1143, 705, 3342, 16384, 61, 71, -1, -1, 1, NULL), + (1144, 705, 5499, 16384, 66, 70, -1, -1, 3, NULL), + (1145, 712, 162, 16384, 44, 55, -1, -1, 2, NULL), + (1146, 712, 163, 16384, 56, 65, -1, -1, 2, NULL), + (1147, 707, 14312, 16384, 71, 75, -1, -1, 3, NULL), + (1148, 707, 14313, 16384, 71, 75, -1, -1, 3, NULL), + (1149, 707, 14314, 16384, 71, 75, -1, -1, 3, NULL), + (1150, 707, 0, 16384, 76, 80, -1, -1, 2, NULL), + (1151, 707, 18392, 16384, 81, 85, -1, -1, 2, NULL), + (1152, 707, 18393, 16384, 81, 85, -1, -1, 2, NULL), + (1153, 707, 18394, 16384, 81, 85, -1, -1, 2, NULL), + (1154, 703, 10516, 16384, 72, 76, -1, -1, 3, NULL), + (1155, 703, 10517, 16384, 72, 76, -1, -1, 3, NULL), + (1156, 703, 10518, 16384, 72, 76, -1, -1, 3, NULL), + (1157, 703, 0, 16384, 77, 81, -1, -1, 3, NULL), + (1158, 703, 18970, 16384, 82, 86, -1, -1, 3, NULL), + (1159, 703, 18971, 16384, 82, 86, -1, -1, 3, NULL), + (1160, 703, 18972, 16384, 82, 86, -1, -1, 3, NULL), + (1161, 704, 15186, 16384, 76, 80, -1, -1, 2, NULL), + (1162, 704, 15187, 16384, 76, 80, -1, -1, 2, NULL), + (1163, 704, 15188, 16384, 76, 80, -1, -1, 2, NULL), + (1164, 704, 18726, 16384, 81, 85, -1, -1, 2, NULL), + (1165, 704, 18727, 16384, 81, 85, -1, -1, 2, NULL), + (1166, 704, 18728, 16384, 81, 85, -1, -1, 2, NULL), + (1167, 705, 14446, 16384, 71, 75, -1, -1, 3, NULL), + (1168, 705, 14447, 16384, 71, 75, -1, -1, 3, NULL), + (1169, 705, 14467, 16384, 72, 76, -1, -1, 1, NULL), + (1170, 705, 14468, 16384, 72, 76, -1, -1, 1, NULL), + (1171, 705, 14469, 16384, 72, 76, -1, -1, 1, NULL), + (1172, 705, 0, 16384, 77, 81, -1, -1, 1, NULL), + (1173, 705, 18552, 16384, 81, 85, -1, -1, 3, NULL), + (1174, 705, 18553, 16384, 81, 85, -1, -1, 3, NULL), + (1175, 705, 18554, 16384, 81, 85, -1, -1, 3, NULL), + (1176, 705, 18573, 16384, 82, 86, -1, -1, 1, NULL), + (1177, 705, 18574, 16384, 82, 86, -1, -1, 1, NULL), + (1178, 705, 18575, 16384, 82, 86, -1, -1, 1, NULL), + (1179, 701, 203, 32768, 1, 21, -1, -1, 2, NULL), + (1180, 701, 213, 32768, 4, 27, -1, -1, 2, NULL), + (1181, 701, 4056, 32768, 8, 22, -1, -1, 2, NULL), + (1182, 701, 95, 32768, 22, 47, -1, -1, 2, NULL), + (1183, 701, 4057, 32768, 23, 37, -1, -1, 2, NULL), + (1184, 701, 96, 32768, 28, 50, -1, -1, 2, NULL), + (1185, 701, 2946, 32768, 38, 53, -1, -1, 2, NULL), + (1186, 701, 97, 32768, 48, 57, -1, -1, 2, NULL), + (1187, 701, 3693, 32768, 51, 83, -1, -1, 3, NULL), + (1188, 701, 2880, 32768, 54, 255, -1, -1, 2, NULL), + (1189, 701, 1525, 32768, 58, 83, -1, -1, 2, NULL), + (1190, 708, 203, 32768, 5, 33, -1, -1, 2, NULL), + (1191, 708, 213, 32768, 11, 55, -1, -1, 2, NULL), + (1192, 708, 4056, 32768, 19, 33, -1, -1, 2, NULL), + (1193, 708, 95, 32768, 34, 61, -1, -1, 2, NULL), + (1194, 708, 4057, 32768, 34, 44, -1, -1, 2, NULL), + (1195, 708, 2946, 32768, 45, 59, -1, -1, 2, NULL), + (1196, 708, 96, 32768, 56, 61, -1, -1, 2, NULL), + (1197, 708, 2880, 32768, 60, 255, -1, -1, 2, NULL), + (1198, 708, 3190, 32768, 62, 66, -1, -1, 2, NULL), + (1199, 708, 5283, 32768, 67, 80, -1, -1, 2, NULL), + (1200, 710, 203, 32768, 13, 60, -1, -1, 2, NULL), + (1201, 710, 213, 32768, 22, 60, -1, -1, 2, NULL), + (1202, 710, 95, 32768, 61, 72, -1, -1, 2, NULL), + (1203, 710, 96, 32768, 61, 72, -1, -1, 2, NULL), + (1204, 709, 213, 32768, 19, 255, -1, -1, 2, NULL), + (1205, 707, 213, 32768, 4, 27, -1, -1, 2, NULL), + (1206, 707, 203, 32768, 5, 27, -1, -1, 2, NULL), + (1207, 707, 95, 32768, 28, 51, -1, -1, 2, NULL), + (1208, 707, 96, 32768, 28, 51, -1, -1, 2, NULL), + (1209, 707, 3693, 32768, 52, 83, -1, -1, 2, NULL), + (1210, 711, 3682, 32768, 45, 85, -1, -1, 2, NULL), + (1211, 711, 3681, 32768, 52, 85, -1, -1, 2, NULL), + (1212, 706, 213, 32768, 1, 21, -1, -1, 2, NULL), + (1213, 706, 203, 32768, 2, 25, -1, -1, 2, NULL), + (1214, 706, 4056, 32768, 9, 23, -1, -1, 2, NULL), + (1215, 706, 96, 32768, 22, 47, -1, -1, 2, NULL), + (1216, 706, 4057, 32768, 24, 37, -1, -1, 2, NULL), + (1217, 706, 95, 32768, 26, 51, -1, -1, 2, NULL), + (1218, 706, 2946, 32768, 38, 53, -1, -1, 2, NULL), + (1219, 706, 98, 32768, 48, 51, -1, -1, 2, NULL), + (1220, 706, 2526, 32768, 52, 84, -1, -1, 2, NULL), + (1221, 706, 3842, 32768, 52, 84, -1, -1, 2, NULL), + (1222, 706, 2880, 32768, 54, 255, -1, -1, 2, NULL), + (1223, 712, 213, 32768, 4, 44, -1, -1, 2, NULL), + (1224, 712, 203, 32768, 13, 60, -1, -1, 2, NULL), + (1225, 712, 96, 32768, 45, 62, -1, -1, 2, NULL), + (1226, 712, 95, 32768, 61, 255, -1, -1, 2, NULL), + (1227, 712, 98, 32768, 63, 255, -1, -1, 2, NULL), + (1228, 701, 14267, 32768, 74, 78, -1, -1, 2, NULL), + (1229, 701, 14268, 32768, 74, 78, -1, -1, 2, NULL), + (1230, 701, 14269, 32768, 74, 78, -1, -1, 2, NULL), + (1231, 701, 18306, 32768, 84, 255, -1, -1, 2, NULL), + (1232, 701, 18307, 32768, 84, 255, -1, -1, 2, NULL), + (1233, 701, 18308, 32768, 84, 255, -1, -1, 2, NULL), + (1234, 701, 18389, 32768, 84, 255, -1, -1, 2, NULL), + (1235, 701, 18390, 32768, 84, 255, -1, -1, 2, NULL), + (1236, 701, 18391, 32768, 84, 255, -1, -1, 2, NULL), + (1237, 708, 19128, 32768, 81, 255, -1, -1, 2, NULL), + (1238, 708, 19129, 32768, 81, 255, -1, -1, 2, NULL), + (1239, 708, 19130, 32768, 81, 255, -1, -1, 2, NULL), + (1240, 710, 14955, 32768, 73, 77, -1, -1, 2, NULL), + (1241, 710, 14956, 32768, 73, 77, -1, -1, 2, NULL), + (1242, 710, 0, 32768, 78, 82, -1, -1, 2, NULL), + (1243, 710, 19146, 32768, 83, 87, -1, -1, 2, NULL), + (1244, 710, 19147, 32768, 83, 87, -1, -1, 2, NULL), + (1245, 710, 19148, 32768, 83, 87, -1, -1, 2, NULL), + (1246, 707, 9700, 32768, 71, 83, -1, -1, 2, NULL), + (1247, 707, 9701, 32768, 71, 83, -1, -1, 2, NULL), + (1248, 707, 9702, 32768, 71, 83, -1, -1, 2, NULL), + (1249, 707, 18389, 32768, 84, 88, -1, -1, 2, NULL), + (1250, 707, 18390, 32768, 84, 88, -1, -1, 2, NULL), + (1251, 707, 18391, 32768, 84, 88, -1, -1, 2, NULL), + (1252, 711, 14027, 32768, 79, 83, -1, -1, 2, NULL), + (1253, 711, 14028, 32768, 79, 83, -1, -1, 2, NULL), + (1254, 711, 14029, 32768, 79, 83, -1, -1, 2, NULL), + (1255, 711, 18021, 32768, 84, 85, -1, -1, 2, NULL), + (1256, 711, 18022, 32768, 84, 85, -1, -1, 2, NULL), + (1257, 711, 18023, 32768, 84, 85, -1, -1, 2, NULL), + (1258, 706, 9700, 32768, 72, 73, -1, -1, 2, NULL), + (1259, 706, 9701, 32768, 72, 73, -1, -1, 2, NULL), + (1260, 706, 9702, 32768, 72, 73, -1, -1, 2, NULL), + (1261, 706, 14387, 32768, 74, 78, -1, -1, 2, NULL), + (1262, 706, 14388, 32768, 74, 78, -1, -1, 2, NULL), + (1263, 706, 14389, 32768, 74, 78, -1, -1, 2, NULL), + (1264, 706, 0, 32768, 79, 83, -1, -1, 2, NULL), + (1265, 706, 18467, 32768, 84, 88, -1, -1, 2, NULL), + (1266, 706, 18468, 32768, 84, 88, -1, -1, 2, NULL), + (1267, 706, 18469, 32768, 84, 88, -1, -1, 2, NULL), + (1268, 706, 19513, 32768, 85, 89, -1, -1, 2, NULL), + (1269, 706, 19514, 32768, 85, 89, -1, -1, 2, NULL), + (1270, 706, 19515, 32768, 85, 89, -1, -1, 2, NULL); +/*!40000 ALTER TABLE `bot_spells_entries` ENABLE KEYS */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/utils/sql/git/bots/required/2015_09_30_bots.sql b/utils/sql/git/bots/required/2015_09_30_bots.sql index 838e85c16..d3cd66132 100644 --- a/utils/sql/git/bots/required/2015_09_30_bots.sql +++ b/utils/sql/git/bots/required/2015_09_30_bots.sql @@ -343,4 +343,1313 @@ bm.`alt` FROM `bot_guild_members` AS bm; +-- Supplemental INSERT + +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Server version: 10.0.22-MariaDB - mariadb.org binary distribution +-- Server OS: Win64 +-- HeidiSQL Version: 9.3.0.4984 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +-- Dumping structure for table peq_raw.bot_spells_entries +DROP TABLE IF EXISTS `bot_spells_entries`; +CREATE TABLE IF NOT EXISTS `bot_spells_entries` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `npc_spells_id` int(11) NOT NULL DEFAULT '0', + `spellid` smallint(5) NOT NULL DEFAULT '0', + `type` int(10) unsigned NOT NULL DEFAULT '0', + `minlevel` tinyint(3) unsigned NOT NULL DEFAULT '0', + `maxlevel` tinyint(3) unsigned NOT NULL DEFAULT '255', + `manacost` smallint(5) NOT NULL DEFAULT '-1', + `recast_delay` int(11) NOT NULL DEFAULT '-1', + `priority` smallint(5) NOT NULL DEFAULT '0', + `resist_adjust` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2048 DEFAULT CHARSET=latin1; + +-- Dumping data for table peq_raw.bot_spells_entries: ~1,270 rows (approximately) +/*!40000 ALTER TABLE `bot_spells_entries` DISABLE KEYS */; +INSERT INTO `bot_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`, `manacost`, `recast_delay`, `priority`, `resist_adjust`) VALUES + (1, 701, 200, 2, 1, 3, -1, -1, 1, NULL), + (2, 701, 14, 1, 1, 4, -1, -1, 1, NULL), + (3, 701, 201, 1, 1, 1, -1, -1, 1, NULL), + (4, 701, 202, 8, 1, 6, -1, -1, 10, NULL), + (5, 701, 11, 8, 1, 14, -1, -1, 8, NULL), + (6, 701, 207, 16, 1, 28, -1, -1, 1, NULL), + (7, 701, 216, 1, 2, 15, -1, -1, 1, NULL), + (8, 701, 17, 2, 4, 9, -1, -1, 1, NULL), + (9, 701, 560, 1, 5, 13, -1, -1, 1, NULL), + (10, 701, 219, 8, 7, 16, -1, -1, 10, NULL), + (11, 701, 12, 2, 10, 19, -1, -1, 2, NULL), + (12, 701, 485, 8, 11, 16, -1, -1, 7, NULL), + (13, 701, 16, 1, 14, 28, -1, -1, 1, NULL), + (14, 701, 3575, 8, 15, 34, -1, -1, 6, NULL), + (15, 701, 368, 8, 15, 24, -1, -1, 8, NULL), + (16, 701, 123, 1, 16, 30, -1, -1, 1, NULL), + (17, 701, 89, 8, 17, 20, -1, -1, 10, NULL), + (18, 701, 2502, 2, 19, 28, -1, -1, 1, NULL), + (19, 701, 15, 2, 20, 29, -1, -1, 2, NULL), + (20, 701, 4088, 8, 20, 39, -1, -1, 6, NULL), + (21, 701, 486, 8, 21, 30, -1, -1, 10, NULL), + (22, 701, 18, 8, 25, 34, -1, -1, 9, NULL), + (23, 701, 130, 16, 29, 255, -1, -1, 1, NULL), + (24, 701, 2175, 2, 29, 43, -1, -1, 1, NULL), + (25, 701, 329, 1, 29, 43, -1, -1, 1, NULL), + (26, 701, 9, 2, 30, 38, -1, -1, 2, NULL), + (27, 701, 124, 1, 31, 45, -1, -1, 1, NULL), + (28, 701, 487, 8, 31, 39, -1, -1, 10, NULL), + (29, 701, 3576, 8, 35, 61, -1, -1, 7, NULL), + (30, 701, 19, 8, 35, 39, -1, -1, 8, NULL), + (31, 701, 13, 2, 39, 69, -1, -1, 2, NULL), + (32, 701, 3692, 8, 40, 44, -1, -1, 10, NULL), + (33, 701, 4089, 8, 40, 53, -1, -1, 6, NULL), + (34, 701, 1445, 8, 40, 48, -1, -1, 11, NULL), + (35, 701, 1444, 2, 44, 58, -1, -1, 1, NULL), + (36, 701, 672, 1, 44, 53, -1, -1, 1, NULL), + (37, 701, 4053, 8, 45, 59, -1, -1, 10, NULL), + (38, 701, 125, 1, 46, 57, -1, -1, 1, NULL), + (39, 701, 2505, 8, 49, 57, -1, -1, 11, NULL), + (40, 701, 1547, 8, 51, 59, -1, -1, 9, NULL), + (41, 701, 1543, 1, 54, 55, -1, -1, 1, NULL), + (42, 701, 4090, 8, 54, 61, -1, -1, 6, NULL), + (43, 701, 2508, 1, 56, 61, -1, -1, 1, NULL), + (44, 701, 1544, 1, 58, 60, -1, -1, 1, NULL), + (45, 701, 2509, 8, 58, 59, -1, -1, 11, NULL), + (46, 701, 1522, 2, 59, 59, -1, -1, 1, NULL), + (47, 701, 1546, 8, 60, 255, -1, -1, 9, NULL), + (48, 701, 2109, 8, 60, 64, -1, -1, 11, NULL), + (49, 701, 2122, 8, 60, 61, -1, -1, 10, NULL), + (50, 701, 2180, 2, 60, 61, -1, -1, 1, NULL), + (51, 701, 3481, 1, 61, 62, -1, -1, 1, NULL), + (52, 701, 3467, 8, 62, 64, -1, -1, 10, NULL), + (53, 701, 3472, 8, 62, 63, -1, -1, 7, NULL), + (54, 701, 3475, 2, 62, 64, -1, -1, 1, NULL), + (55, 701, 3476, 1, 62, 64, -1, -1, 1, NULL), + (56, 701, 4091, 8, 62, 66, -1, -1, 6, NULL), + (57, 701, 3482, 1, 63, 65, -1, -1, 1, NULL), + (58, 701, 4108, 8, 64, 66, -1, -1, 7, NULL), + (59, 701, 3474, 8, 65, 69, -1, -1, 11, NULL), + (60, 701, 3479, 8, 65, 66, -1, -1, 10, NULL), + (61, 701, 4882, 2, 65, 66, -1, -1, 1, NULL), + (62, 701, 4973, 1, 65, 66, -1, -1, 1, NULL), + (63, 701, 5254, 1, 66, 67, -1, -1, 1, NULL), + (64, 701, 5257, 8, 67, 69, -1, -1, 10, NULL), + (65, 701, 5258, 8, 67, 68, -1, -1, 7, NULL), + (66, 701, 5259, 2, 67, 255, -1, -1, 1, NULL), + (67, 701, 5260, 1, 67, 68, -1, -1, 1, NULL), + (68, 701, 5261, 8, 67, 255, -1, -1, 6, NULL), + (69, 701, 5266, 1, 68, 255, -1, -1, 1, NULL), + (70, 701, 5272, 8, 69, 255, -1, -1, 7, NULL), + (71, 701, 8006, 1, 69, 69, -1, -1, 1, NULL), + (72, 701, 5276, 8, 70, 255, -1, -1, 11, NULL), + (73, 701, 5278, 8, 70, 255, -1, -1, 10, NULL), + (74, 701, 5279, 1, 70, 255, -1, -1, 1, NULL), + (75, 701, 6140, 2, 70, 255, -1, -1, 2, NULL), + (76, 702, 288, 8, 1, 5, -1, -1, 1, NULL), + (77, 702, 372, 1, 1, 7, -1, -1, 3, NULL), + (78, 702, 378, 8, 2, 9, -1, -1, 2, NULL), + (79, 702, 230, 4, 3, 16, -1, -1, 2, NULL), + (80, 702, 376, 1, 4, 4, -1, -1, 3, NULL), + (81, 702, 477, 1, 5, 14, -1, -1, 3, NULL), + (82, 702, 246, 8, 6, 14, -1, -1, 1, NULL), + (83, 702, 656, 1, 8, 23, -1, -1, 3, NULL), + (84, 702, 381, 8, 9, 60, -1, -1, 4, NULL), + (85, 702, 2551, 8, 10, 30, -1, -1, 2, NULL), + (86, 702, 383, 1, 10, 15, -1, -1, 3, NULL), + (87, 702, 48, 512, 11, 33, -1, -1, 1, NULL), + (88, 702, 236, 8, 13, 20, -1, -1, 5, NULL), + (89, 702, 309, 8, 15, 22, -1, -1, 1, NULL), + (90, 702, 657, 1, 15, 25, -1, -1, 3, NULL), + (91, 702, 38, 1, 16, 36, -1, -1, 3, NULL), + (92, 702, 131, 4, 17, 38, -1, -1, 2, NULL), + (93, 702, 22, 1, 17, 17, -1, -1, 3, NULL), + (94, 702, 2552, 1, 18, 27, -1, -1, 3, NULL), + (95, 702, 503, 1, 19, 46, -1, -1, 2, NULL), + (96, 702, 108, 8, 20, 41, -1, -1, 6, NULL), + (97, 702, 387, 8, 21, 29, -1, -1, 5, NULL), + (98, 702, 65, 8, 23, 32, -1, -1, 1, NULL), + (99, 702, 464, 1, 24, 33, -1, -1, 3, NULL), + (100, 702, 2553, 32, 25, 44, -1, -1, 0, NULL), + (101, 702, 465, 1, 26, 42, -1, -1, 3, NULL), + (102, 702, 470, 1, 28, 40, -1, -1, 3, NULL), + (103, 702, 393, 8, 30, 39, -1, -1, 5, NULL), + (104, 702, 1419, 8, 31, 48, -1, -1, 2, NULL), + (105, 702, 66, 8, 33, 43, -1, -1, 1, NULL), + (106, 702, 49, 512, 34, 52, -1, -1, 1, NULL), + (107, 702, 658, 1, 34, 48, -1, -1, 3, NULL), + (108, 702, 466, 1, 37, 57, -1, -1, 3, NULL), + (109, 702, 752, 16, 37, 59, -1, -1, 1, NULL), + (110, 702, 132, 4, 39, 47, -1, -1, 2, NULL), + (111, 702, 3811, 8, 40, 57, -1, -1, 3, NULL), + (112, 702, 394, 8, 40, 51, -1, -1, 5, NULL), + (113, 702, 23, 1, 41, 46, -1, -1, 3, NULL), + (114, 702, 109, 8, 42, 53, -1, -1, 6, NULL), + (115, 702, 659, 1, 43, 59, -1, -1, 3, NULL), + (116, 702, 67, 8, 44, 53, -1, -1, 1, NULL), + (117, 702, 2555, 32, 45, 53, -1, -1, 0, NULL), + (118, 702, 612, 1, 47, 50, -1, -1, 2, NULL), + (119, 702, 755, 1, 47, 59, -1, -1, 3, NULL), + (120, 702, 133, 4, 48, 50, -1, -1, 2, NULL), + (121, 702, 4067, 8, 49, 56, -1, -1, 2, NULL), + (122, 702, 732, 1, 49, 59, -1, -1, 3, NULL), + (123, 702, 1631, 128, 51, 57, -1, -1, 2, NULL), + (124, 702, 1634, 1, 51, 55, -1, -1, 2, NULL), + (125, 702, 1609, 8, 52, 62, -1, -1, 5, NULL), + (126, 702, 1526, 512, 53, 255, -1, -1, 1, NULL), + (127, 702, 1610, 8, 54, 60, -1, -1, 1, NULL), + (128, 702, 2557, 32, 54, 59, -1, -1, 0, NULL), + (129, 702, 3582, 8, 54, 61, -1, -1, 6, NULL), + (130, 702, 1635, 1, 56, 63, -1, -1, 2, NULL), + (131, 702, 4068, 8, 57, 63, -1, -1, 2, NULL), + (132, 702, 1633, 4, 58, 60, -1, -1, 2, NULL), + (133, 702, 1640, 1, 58, 60, -1, -1, 3, NULL), + (134, 702, 2559, 8, 58, 255, -1, -1, 3, NULL), + (135, 702, 2884, 1, 60, 64, -1, -1, 3, NULL), + (136, 702, 2116, 1, 60, 63, -1, -1, 3, NULL), + (137, 702, 2117, 16, 60, 255, -1, -1, 1, NULL), + (138, 702, 2560, 32, 60, 255, -1, -1, 0, NULL), + (139, 702, 2883, 1, 60, 62, -1, -1, 3, NULL), + (140, 702, 3194, 4, 61, 255, -1, -1, 2, NULL), + (141, 702, 3300, 8, 61, 63, -1, -1, 1, NULL), + (142, 702, 3326, 8, 61, 255, -1, -1, 4, NULL), + (143, 702, 3328, 1, 61, 66, -1, -1, 3, NULL), + (144, 702, 3329, 8, 62, 255, -1, -1, 6, NULL), + (145, 702, 3301, 8, 63, 67, -1, -1, 5, NULL), + (146, 702, 3335, 1, 63, 64, -1, -1, 3, NULL), + (147, 702, 3302, 8, 64, 65, -1, -1, 1, NULL), + (148, 702, 4069, 8, 64, 69, -1, -1, 2, NULL), + (149, 702, 4066, 1, 64, 68, -1, -1, 3, NULL), + (150, 702, 3333, 1, 64, 69, -1, -1, 2, NULL), + (151, 702, 4981, 1, 65, 69, -1, -1, 3, NULL), + (152, 702, 3191, 1, 65, 255, -1, -1, 3, NULL), + (153, 702, 5443, 8, 66, 255, -1, -1, 1, NULL), + (154, 702, 5445, 1, 67, 67, -1, -1, 3, NULL), + (155, 702, 5448, 8, 68, 255, -1, -1, 5, NULL), + (156, 702, 5450, 1, 68, 255, -1, -1, 3, NULL), + (157, 702, 5458, 1, 69, 255, -1, -1, 3, NULL), + (158, 702, 5459, 8, 70, 255, -1, -1, 2, NULL), + (159, 702, 8043, 1, 70, 255, -1, -1, 3, NULL), + (160, 702, 5456, 1, 70, 255, -1, -1, 3, NULL), + (161, 703, 288, 8, 1, 7, -1, -1, 1, NULL), + (162, 703, 340, 256, 1, 14, -1, -1, 2, NULL), + (163, 703, 341, 64, 1, 2, -1, -1, 3, NULL), + (164, 703, 338, 32, 1, 3, -1, -1, 0, NULL), + (165, 703, 346, 8, 3, 15, -1, -1, 3, NULL), + (166, 703, 502, 64, 3, 11, -1, -1, 3, NULL), + (167, 703, 344, 128, 4, 10, -1, -1, 1, NULL), + (168, 703, 229, 1, 4, 29, -1, 45, 6, NULL), + (169, 703, 348, 256, 4, 33, -1, -1, 3, NULL), + (170, 703, 491, 32, 4, 7, -1, -1, 0, NULL), + (171, 703, 641, 8, 6, 17, -1, -1, 4, NULL), + (172, 703, 359, 8, 7, 19, -1, -1, 5, NULL), + (173, 703, 246, 8, 8, 15, -1, -1, 1, NULL), + (174, 703, 351, 32, 8, 11, -1, -1, 0, NULL), + (175, 703, 1509, 256, 9, 28, -1, -1, 3, NULL), + (176, 703, 360, 256, 10, 27, -1, -1, 3, NULL), + (177, 703, 2541, 8, 11, 22, -1, -1, 6, NULL), + (178, 703, 355, 128, 11, 26, -1, -1, 1, NULL), + (179, 703, 362, 32, 12, 15, -1, -1, 0, NULL), + (180, 703, 445, 64, 12, 19, -1, -1, 3, NULL), + (181, 703, 367, 256, 13, 38, -1, -1, 3, NULL), + (182, 703, 236, 8, 14, 21, -1, -1, 2, NULL), + (183, 703, 365, 256, 15, 34, -1, -1, 3, NULL), + (184, 703, 309, 8, 16, 20, -1, -1, 1, NULL), + (185, 703, 492, 32, 16, 19, -1, -1, 0, NULL), + (186, 703, 2542, 1, 17, 37, -1, -1, 2, NULL), + (187, 703, 642, 8, 18, 30, -1, -1, 4, NULL), + (188, 703, 199, 16, 20, 57, -1, -1, 1, NULL), + (189, 703, 440, 32, 20, 23, -1, -1, 0, NULL), + (190, 703, 446, 64, 20, 25, -1, -1, 3, NULL), + (191, 703, 204, 1, 21, 31, -1, -1, 5, NULL), + (192, 703, 387, 8, 22, 31, -1, -1, 2, NULL), + (193, 703, 449, 8, 23, 34, -1, -1, 6, NULL), + (194, 703, 493, 32, 24, 28, -1, -1, 0, NULL), + (195, 703, 524, 64, 26, 38, -1, -1, 3, NULL), + (196, 703, 452, 128, 27, 46, -1, -1, 1, NULL), + (197, 703, 451, 256, 28, 46, -1, -1, 3, NULL), + (198, 703, 441, 32, 29, 32, -1, -1, 0, NULL), + (199, 703, 454, 256, 29, 44, -1, -1, 3, NULL), + (200, 703, 127, 1, 30, 55, -1, 45, 6, NULL), + (201, 703, 643, 8, 31, 47, -1, -1, 4, NULL), + (202, 703, 1415, 1, 32, 48, -1, -1, 5, NULL), + (203, 703, 393, 8, 32, 42, -1, -1, 2, NULL), + (204, 703, 494, 32, 33, 38, -1, -1, 0, NULL), + (205, 703, 435, 256, 34, 49, -1, -1, 3, NULL), + (206, 703, 31, 256, 35, 39, -1, -1, 3, NULL), + (207, 703, 661, 8, 35, 54, -1, -1, 6, NULL), + (208, 703, 2544, 1, 38, 255, -1, -1, 2, NULL), + (209, 703, 442, 32, 39, 43, -1, -1, 0, NULL), + (210, 703, 525, 64, 39, 47, -1, -1, 3, NULL), + (211, 703, 4096, 256, 39, 53, -1, -1, 3, NULL), + (212, 703, 1508, 256, 40, 51, -1, -1, 3, NULL), + (213, 703, 394, 8, 43, 51, -1, -1, 2, NULL), + (214, 703, 495, 32, 44, 47, -1, -1, 0, NULL), + (215, 703, 3702, 256, 45, 48, -1, -1, 3, NULL), + (216, 703, 453, 128, 47, 58, -1, -1, 1, NULL), + (217, 703, 6, 256, 47, 57, -1, -1, 3, NULL), + (218, 703, 443, 32, 48, 52, -1, -1, 0, NULL), + (219, 703, 447, 64, 48, 53, -1, -1, 3, NULL), + (220, 703, 644, 8, 48, 55, -1, -1, 4, NULL), + (221, 703, 3571, 1, 49, 53, -1, -1, 5, NULL), + (222, 703, 456, 256, 49, 56, -1, -1, 3, NULL), + (223, 703, 436, 256, 50, 64, -1, -1, 3, NULL), + (224, 703, 1609, 8, 52, 62, -1, -1, 2, NULL), + (225, 703, 32, 256, 52, 55, -1, -1, 3, NULL), + (226, 703, 1621, 32, 53, 55, -1, -1, 0, NULL), + (227, 703, 3572, 1, 54, 59, -1, -1, 5, NULL), + (228, 703, 1613, 64, 54, 58, -1, -1, 3, NULL), + (229, 703, 4097, 256, 54, 62, -1, -1, 3, NULL), + (230, 703, 1414, 8, 55, 61, -1, -1, 6, NULL), + (231, 703, 1527, 1, 56, 56, -1, 45, 6, NULL), + (232, 703, 1611, 8, 56, 59, -1, -1, 4, NULL), + (233, 703, 1615, 256, 56, 66, -1, -1, 3, NULL), + (234, 703, 1622, 32, 56, 58, -1, -1, 0, NULL), + (235, 703, 1616, 256, 57, 59, -1, -1, 3, NULL), + (236, 703, 6980, 1, 57, 61, -1, -1, 6, NULL), + (237, 703, 1612, 16, 58, 255, -1, -1, 1, NULL), + (238, 703, 1617, 256, 58, 59, -1, -1, 3, NULL), + (239, 703, 1619, 128, 59, 62, -1, -1, 1, NULL), + (240, 703, 1623, 32, 59, 60, -1, -1, 0, NULL), + (241, 703, 1618, 64, 59, 59, -1, -1, 3, NULL), + (242, 703, 1393, 64, 60, 60, -1, -1, 3, NULL), + (243, 703, 2114, 8, 60, 63, -1, -1, 4, NULL), + (244, 703, 2115, 1, 60, 60, -1, -1, 5, NULL), + (245, 703, 2550, 256, 60, 64, -1, -1, 3, NULL), + (246, 703, 2885, 256, 60, 64, -1, -1, 3, NULL), + (247, 703, 3032, 64, 61, 66, -1, -1, 3, NULL), + (248, 703, 3035, 1, 61, 65, -1, -1, 5, NULL), + (249, 703, 3304, 32, 61, 62, -1, -1, 0, NULL), + (250, 703, 3305, 8, 62, 66, -1, -1, 6, NULL), + (251, 703, 6981, 1, 62, 66, -1, -1, 6, NULL), + (252, 703, 3301, 8, 63, 68, -1, -1, 2, NULL), + (253, 703, 3309, 128, 63, 67, -1, -1, 1, NULL), + (254, 703, 3310, 32, 63, 64, -1, -1, 0, NULL), + (255, 703, 4098, 256, 63, 66, -1, -1, 3, NULL), + (256, 703, 3311, 8, 64, 64, -1, -1, 4, NULL), + (257, 703, 3303, 256, 65, 68, -1, -1, 3, NULL), + (258, 703, 3314, 32, 65, 66, -1, -1, 0, NULL), + (259, 703, 4889, 256, 65, 255, -1, -1, 3, NULL), + (260, 703, 4890, 256, 65, 68, -1, -1, 3, NULL), + (261, 703, 4978, 8, 65, 69, -1, -1, 4, NULL), + (262, 703, 5420, 1, 66, 255, -1, -1, 5, NULL), + (263, 703, 5419, 64, 67, 69, -1, -1, 3, NULL), + (264, 703, 5424, 256, 67, 255, -1, -1, 3, NULL), + (265, 703, 5425, 8, 67, 255, -1, -1, 6, NULL), + (266, 703, 5431, 32, 67, 69, -1, -1, 0, NULL), + (267, 703, 5432, 256, 67, 69, -1, -1, 3, NULL), + (268, 703, 6982, 1, 67, 255, -1, -1, 6, NULL), + (269, 703, 5430, 128, 68, 255, -1, -1, 1, NULL), + (270, 703, 5428, 8, 69, 255, -1, -1, 2, NULL), + (271, 703, 5437, 256, 69, 69, -1, -1, 3, NULL), + (272, 703, 7999, 256, 69, 255, -1, -1, 3, NULL), + (273, 703, 5438, 32, 70, 255, -1, -1, 0, NULL), + (274, 703, 5441, 256, 70, 255, -1, -1, 3, NULL), + (275, 703, 6143, 64, 70, 255, -1, -1, 3, NULL), + (276, 703, 7994, 256, 70, 255, -1, -1, 3, NULL), + (277, 703, 5434, 8, 70, 255, -1, -1, 4, NULL), + (278, 704, 288, 8, 1, 4, -1, -1, 1, NULL), + (279, 704, 93, 1, 1, 3, -1, -1, 5, NULL), + (280, 704, 315, 32, 2, 5, -1, -1, 0, NULL), + (281, 704, 316, 32, 3, 6, -1, -1, 0, NULL), + (282, 704, 317, 32, 4, 7, -1, -1, 0, NULL), + (283, 704, 94, 1, 4, 4, -1, -1, 5, NULL), + (284, 704, 58, 32, 5, 8, -1, -1, 0, NULL), + (285, 704, 246, 8, 5, 15, -1, -1, 1, NULL), + (286, 704, 322, 1, 5, 14, -1, -1, 5, NULL), + (287, 704, 398, 32, 6, 9, -1, -1, 0, NULL), + (288, 704, 399, 32, 7, 10, -1, -1, 0, NULL), + (289, 704, 324, 1, 7, 22, -1, -1, 6, NULL), + (290, 704, 332, 8, 7, 18, -1, -1, 2, NULL), + (291, 704, 400, 32, 8, 11, -1, -1, 0, NULL), + (292, 704, 397, 32, 9, 12, -1, -1, 0, NULL), + (293, 704, 248, 1, 9, 17, -1, -1, 3, NULL), + (294, 704, 402, 32, 10, 13, -1, -1, 0, NULL), + (295, 704, 403, 32, 11, 14, -1, -1, 0, NULL), + (296, 704, 327, 8, 11, 28, -1, -1, 3, NULL), + (297, 704, 404, 32, 12, 15, -1, -1, 0, NULL), + (298, 704, 333, 8, 12, 24, -1, -1, 4, NULL), + (299, 704, 401, 32, 13, 16, -1, -1, 0, NULL), + (300, 704, 336, 32, 14, 17, -1, -1, 0, NULL), + (301, 704, 395, 32, 15, 18, -1, -1, 0, NULL), + (302, 704, 334, 1, 15, 17, -1, -1, 5, NULL), + (303, 704, 396, 32, 16, 19, -1, -1, 0, NULL), + (304, 704, 309, 8, 16, 23, -1, -1, 1, NULL), + (305, 704, 335, 32, 17, 20, -1, -1, 0, NULL), + (306, 704, 497, 32, 18, 21, -1, -1, 0, NULL), + (307, 704, 68, 1, 18, 30, -1, -1, 5, NULL), + (308, 704, 663, 1, 18, 24, -1, -1, 3, NULL), + (309, 704, 498, 32, 19, 22, -1, -1, 0, NULL), + (310, 704, 411, 8, 19, 27, -1, -1, 2, NULL), + (311, 704, 499, 32, 20, 23, -1, -1, 0, NULL), + (312, 704, 496, 32, 21, 24, -1, -1, 0, NULL), + (313, 704, 570, 32, 22, 25, -1, -1, 0, NULL), + (314, 704, 571, 32, 23, 26, -1, -1, 0, NULL), + (315, 704, 113, 1, 23, 40, -1, -1, 6, NULL), + (316, 704, 572, 32, 24, 27, -1, -1, 0, NULL), + (317, 704, 65, 8, 24, 31, -1, -1, 1, NULL), + (318, 704, 569, 32, 25, 28, -1, -1, 0, NULL), + (319, 704, 115, 1, 25, 27, -1, -1, 3, NULL), + (320, 704, 81, 8, 25, 40, -1, -1, 4, NULL), + (321, 704, 574, 32, 26, 30, -1, -1, 0, NULL), + (322, 704, 575, 32, 27, 31, -1, -1, 0, NULL), + (323, 704, 576, 32, 28, 32, -1, -1, 0, NULL), + (324, 704, 479, 8, 28, 37, -1, -1, 2, NULL), + (325, 704, 664, 1, 28, 47, -1, -1, 3, NULL), + (326, 704, 106, 8, 28, 46, -1, -1, 3, NULL), + (327, 704, 573, 32, 29, 33, -1, -1, 0, NULL), + (328, 704, 1400, 32, 30, 49, -1, -1, 0, NULL), + (329, 704, 621, 32, 31, 35, -1, -1, 0, NULL), + (330, 704, 120, 1, 31, 32, -1, -1, 5, NULL), + (331, 704, 622, 32, 32, 36, -1, -1, 0, NULL), + (332, 704, 49, 512, 32, 52, -1, -1, 3, NULL), + (333, 704, 66, 8, 32, 42, -1, -1, 1, NULL), + (334, 704, 623, 32, 33, 37, -1, -1, 0, NULL), + (335, 704, 69, 1, 33, 46, -1, -1, 5, NULL), + (336, 704, 620, 32, 34, 38, -1, -1, 0, NULL), + (337, 704, 625, 32, 36, 40, -1, -1, 0, NULL), + (338, 704, 626, 32, 37, 41, -1, -1, 0, NULL), + (339, 704, 627, 32, 38, 42, -1, -1, 0, NULL), + (340, 704, 680, 8, 38, 44, -1, -1, 2, NULL), + (341, 704, 624, 32, 39, 43, -1, -1, 0, NULL), + (342, 704, 629, 32, 41, 48, -1, -1, 0, NULL), + (343, 704, 114, 1, 41, 56, -1, -1, 6, NULL), + (344, 704, 82, 8, 41, 51, -1, -1, 4, NULL), + (345, 704, 630, 32, 42, 46, -1, -1, 0, NULL), + (346, 704, 631, 32, 43, 47, -1, -1, 0, NULL), + (347, 704, 1403, 1, 43, 54, -1, -1, 4, NULL), + (348, 704, 67, 8, 43, 53, -1, -1, 1, NULL), + (349, 704, 628, 32, 44, 45, -1, -1, 0, NULL), + (350, 704, 412, 8, 45, 52, -1, -1, 2, NULL), + (351, 704, 632, 32, 46, 50, -1, -1, 0, NULL), + (352, 704, 4079, 8, 46, 57, -1, -1, 5, NULL), + (353, 704, 634, 32, 47, 51, -1, -1, 0, NULL), + (354, 704, 107, 8, 47, 51, -1, -1, 3, NULL), + (355, 704, 70, 1, 47, 51, -1, -1, 5, NULL), + (356, 704, 635, 32, 48, 52, -1, -1, 0, NULL), + (357, 704, 116, 1, 48, 55, -1, -1, 3, NULL), + (358, 704, 633, 32, 49, 53, -1, -1, 0, NULL), + (359, 704, 1402, 32, 50, 59, -1, -1, 0, NULL), + (360, 704, 1671, 32, 51, 56, -1, -1, 0, NULL), + (361, 704, 1673, 32, 52, 57, -1, -1, 0, NULL), + (362, 704, 1660, 1, 52, 58, -1, -1, 5, NULL), + (363, 704, 1666, 8, 52, 53, -1, -1, 4, NULL), + (364, 704, 3700, 8, 52, 54, -1, -1, 3, NULL), + (365, 704, 1674, 32, 53, 58, -1, -1, 0, NULL), + (366, 704, 1526, 512, 53, 255, -1, -1, 3, NULL), + (367, 704, 1668, 8, 53, 55, -1, -1, 2, NULL), + (368, 704, 1672, 32, 54, 59, -1, -1, 0, NULL), + (369, 704, 1610, 8, 54, 60, -1, -1, 1, NULL), + (370, 704, 2879, 8, 54, 57, -1, -1, 4, NULL), + (371, 704, 1405, 1, 55, 255, -1, -1, 4, NULL), + (372, 704, 1472, 8, 55, 59, -1, -1, 3, NULL), + (373, 704, 1529, 1, 56, 63, -1, -1, 3, NULL), + (374, 704, 1667, 8, 56, 59, -1, -1, 2, NULL), + (375, 704, 1675, 32, 57, 64, -1, -1, 0, NULL), + (376, 704, 1663, 1, 57, 62, -1, -1, 6, NULL), + (377, 704, 1677, 32, 58, 62, -1, -1, 0, NULL), + (378, 704, 2539, 8, 58, 61, -1, -1, 4, NULL), + (379, 704, 4080, 8, 58, 63, -1, -1, 5, NULL), + (380, 704, 1678, 32, 59, 60, -1, -1, 0, NULL), + (381, 704, 1664, 1, 59, 60, -1, -1, 5, NULL), + (382, 704, 1404, 32, 60, 64, -1, -1, 0, NULL), + (383, 704, 1676, 32, 60, 61, -1, -1, 0, NULL), + (384, 704, 1669, 8, 60, 60, -1, -1, 2, NULL), + (385, 704, 2119, 8, 60, 61, -1, -1, 3, NULL), + (386, 704, 3317, 32, 61, 65, -1, -1, 0, NULL), + (387, 704, 3198, 8, 61, 62, -1, -1, 2, NULL), + (388, 704, 3300, 8, 61, 63, -1, -1, 1, NULL), + (389, 704, 3318, 1, 61, 65, -1, -1, 5, NULL), + (390, 704, 3320, 32, 62, 66, -1, -1, 0, NULL), + (391, 704, 3031, 8, 62, 67, -1, -1, 4, NULL), + (392, 704, 3237, 8, 62, 68, -1, -1, 3, NULL), + (393, 704, 3322, 32, 63, 67, -1, -1, 0, NULL), + (394, 704, 3486, 8, 63, 65, -1, -1, 2, NULL), + (395, 704, 3321, 1, 63, 67, -1, -1, 6, NULL), + (396, 704, 3238, 1, 64, 68, -1, -1, 3, NULL), + (397, 704, 3302, 8, 64, 65, -1, -1, 1, NULL), + (398, 704, 4081, 8, 64, 68, -1, -1, 5, NULL), + (399, 704, 4888, 32, 65, 255, -1, -1, 0, NULL), + (400, 704, 3324, 32, 65, 69, -1, -1, 0, NULL), + (401, 704, 5473, 32, 66, 255, -1, -1, 0, NULL), + (402, 704, 5466, 8, 66, 69, -1, -1, 2, NULL), + (403, 704, 5472, 8, 66, 255, -1, -1, 1, NULL), + (404, 704, 5474, 1, 66, 255, -1, -1, 5, NULL), + (405, 704, 5480, 32, 67, 255, -1, -1, 0, NULL), + (406, 704, 5485, 32, 68, 255, -1, -1, 0, NULL), + (407, 704, 5476, 8, 68, 255, -1, -1, 4, NULL), + (408, 704, 5484, 1, 68, 255, -1, -1, 6, NULL), + (409, 704, 5478, 8, 69, 255, -1, -1, 3, NULL), + (410, 704, 5490, 1, 69, 255, -1, -1, 3, NULL), + (411, 704, 5494, 8, 69, 255, -1, -1, 5, NULL), + (412, 704, 5495, 32, 70, 255, -1, -1, 0, NULL), + (413, 704, 5488, 8, 70, 255, -1, -1, 2, NULL), + (414, 705, 288, 8, 1, 5, -1, -1, 1, NULL), + (415, 705, 40, 8, 1, 18, -1, -1, 2, NULL), + (416, 705, 289, 1, 1, 6, -1, -1, 7, NULL), + (417, 705, 286, 1, 1, 3, -1, -1, 6, NULL), + (418, 705, 285, 32, 1, 1, -1, -1, 0, NULL), + (419, 705, 681, 32, 2, 6, -1, -1, 0, NULL), + (420, 705, 294, 1, 4, 10, -1, -1, 6, NULL), + (421, 705, 246, 8, 6, 15, -1, -1, 1, NULL), + (422, 705, 295, 32, 7, 8, -1, -1, 0, NULL), + (423, 705, 296, 1, 7, 15, -1, -1, 7, NULL), + (424, 705, 48, 512, 7, 21, -1, -1, 7, NULL), + (425, 705, 302, 1, 9, 22, -1, -1, 2, NULL), + (426, 705, 303, 1, 9, 27, -1, -1, 5, NULL), + (427, 705, 682, 32, 9, 13, -1, -1, 0, NULL), + (428, 705, 2561, 8, 11, 16, -1, -1, 4, NULL), + (429, 705, 521, 1, 11, 25, -1, -1, 6, NULL), + (430, 705, 683, 32, 14, 16, -1, -1, 0, NULL), + (431, 705, 697, 8, 14, 25, -1, -1, 5, NULL), + (432, 705, 39, 8, 15, 20, -1, -1, 6, NULL), + (433, 705, 309, 8, 16, 22, -1, -1, 1, NULL), + (434, 705, 306, 1, 16, 20, -1, -1, 7, NULL), + (435, 705, 2562, 8, 17, 29, -1, -1, 4, NULL), + (436, 705, 684, 32, 17, 21, -1, -1, 0, NULL), + (437, 705, 170, 8, 21, 38, -1, -1, 6, NULL), + (438, 705, 350, 1, 21, 31, -1, -1, 7, NULL), + (439, 705, 24, 512, 22, 27, -1, -1, 7, NULL), + (440, 705, 685, 32, 22, 28, -1, -1, 0, NULL), + (441, 705, 185, 1, 23, 40, -1, -1, 2, NULL), + (442, 705, 65, 8, 23, 30, -1, -1, 1, NULL), + (443, 705, 174, 8, 26, 41, -1, -1, 5, NULL), + (444, 705, 450, 1, 26, 46, -1, -1, 6, NULL), + (445, 705, 49, 512, 28, 41, -1, -1, 7, NULL), + (446, 705, 619, 1, 28, 60, -1, -1, 5, NULL), + (447, 705, 4073, 8, 29, 43, -1, -1, 2, NULL), + (448, 705, 686, 32, 29, 30, -1, -1, 0, NULL), + (449, 705, 74, 1, 30, 49, -1, -1, 7, NULL), + (450, 705, 66, 8, 31, 39, -1, -1, 1, NULL), + (451, 705, 687, 32, 31, 36, -1, -1, 0, NULL), + (452, 705, 71, 1, 32, 42, -1, -1, 7, NULL), + (453, 705, 1408, 8, 34, 54, -1, -1, 3, NULL), + (454, 705, 688, 32, 37, 40, -1, -1, 0, NULL), + (455, 705, 171, 8, 39, 46, -1, -1, 7, NULL), + (456, 705, 1474, 8, 40, 62, -1, -1, 1, NULL), + (457, 705, 186, 1, 41, 56, -1, -1, 2, NULL), + (458, 705, 689, 32, 41, 47, -1, -1, 0, NULL), + (459, 705, 1694, 8, 42, 51, -1, -1, 5, NULL), + (460, 705, 25, 512, 42, 52, -1, -1, 7, NULL), + (461, 705, 673, 1, 43, 53, -1, -1, 7, NULL), + (462, 705, 4074, 1, 44, 54, -1, -1, 2, NULL), + (463, 705, 172, 8, 47, 52, -1, -1, 6, NULL), + (464, 705, 195, 1, 47, 58, -1, -1, 6, NULL), + (465, 705, 690, 32, 48, 54, -1, -1, 0, NULL), + (466, 705, 1686, 1, 50, 255, -1, -1, 7, NULL), + (467, 705, 1693, 8, 52, 55, -1, -1, 5, NULL), + (468, 705, 1697, 512, 53, 255, -1, -1, 7, NULL), + (469, 705, 1708, 8, 53, 57, -1, -1, 6, NULL), + (470, 705, 1698, 1, 54, 255, -1, -1, 7, NULL), + (471, 705, 1723, 32, 55, 61, -1, -1, 0, NULL), + (472, 705, 4075, 8, 55, 62, -1, -1, 2, NULL), + (473, 705, 1409, 8, 55, 59, -1, -1, 3, NULL), + (474, 705, 1695, 8, 56, 59, -1, -1, 5, NULL), + (475, 705, 1712, 1, 57, 68, -1, -1, 2, NULL), + (476, 705, 1709, 8, 58, 59, -1, -1, 6, NULL), + (477, 705, 1703, 1, 59, 61, -1, -1, 6, NULL), + (478, 705, 1710, 8, 60, 61, -1, -1, 6, NULL), + (479, 705, 2570, 8, 60, 62, -1, -1, 5, NULL), + (480, 705, 6739, 8, 61, 66, -1, -1, 4, NULL), + (481, 705, 3199, 8, 61, 65, -1, -1, 3, NULL), + (482, 705, 3229, 16, 61, 255, -1, -1, 1, NULL), + (483, 705, 3034, 32, 62, 65, -1, -1, 0, NULL), + (484, 705, 3240, 8, 62, 64, -1, -1, 6, NULL), + (485, 705, 3345, 1, 62, 68, -1, -1, 6, NULL), + (486, 705, 3350, 8, 63, 64, -1, -1, 5, NULL), + (487, 705, 4076, 8, 63, 67, -1, -1, 2, NULL), + (488, 705, 3241, 8, 63, 255, -1, -1, 1, NULL), + (489, 705, 3178, 8, 65, 66, -1, -1, 6, NULL), + (490, 705, 3360, 8, 65, 67, -1, -1, 5, NULL), + (491, 705, 5500, 8, 66, 255, -1, -1, 3, NULL), + (492, 705, 5505, 32, 66, 255, -1, -1, 0, NULL), + (493, 705, 5504, 8, 67, 68, -1, -1, 4, NULL), + (494, 705, 5507, 8, 67, 69, -1, -1, 6, NULL), + (495, 705, 5513, 8, 68, 69, -1, -1, 5, NULL), + (496, 705, 5515, 8, 68, 69, -1, -1, 2, NULL), + (497, 705, 5509, 1, 69, 255, -1, -1, 6, NULL), + (498, 705, 6671, 8, 69, 255, -1, -1, 4, NULL), + (499, 705, 6826, 1, 69, 255, -1, -1, 2, NULL), + (500, 705, 5517, 8, 70, 255, -1, -1, 2, NULL), + (501, 705, 5521, 8, 70, 255, -1, -1, 6, NULL), + (502, 705, 5522, 8, 70, 255, -1, -1, 5, NULL), + (503, 706, 266, 8, 1, 20, -1, -1, 1, NULL), + (504, 706, 40, 8, 1, 7, -1, -1, 2, NULL), + (505, 706, 267, 8, 1, 31, -1, -1, 3, NULL), + (506, 706, 93, 1, 1, 3, -1, -1, 1, NULL), + (507, 706, 200, 2, 1, 18, -1, -1, 2, NULL), + (508, 706, 274, 8, 3, 10, -1, -1, 9, NULL), + (509, 706, 269, 8, 3, 17, -1, -1, 10, NULL), + (510, 706, 275, 1, 4, 13, -1, -1, 5, NULL), + (511, 706, 75, 256, 4, 14, -1, -1, 4, NULL), + (512, 706, 270, 256, 5, 12, -1, -1, 2, NULL), + (513, 706, 279, 8, 6, 21, -1, -1, 11, NULL), + (514, 706, 2521, 8, 8, 17, -1, -1, 2, NULL), + (515, 706, 277, 256, 8, 23, -1, -1, 4, NULL), + (516, 706, 17, 2, 9, 18, -1, -1, 2, NULL), + (517, 706, 283, 8, 11, 19, -1, -1, 9, NULL), + (518, 706, 281, 1, 12, 28, -1, -1, 3, NULL), + (519, 706, 505, 1, 13, 26, -1, -1, 2, NULL), + (520, 706, 365, 256, 15, 18, -1, -1, 4, NULL), + (521, 706, 282, 1, 14, 22, -1, -1, 5, NULL), + (522, 706, 526, 1, 17, 37, -1, -1, 4, NULL), + (523, 706, 110, 1, 18, 31, -1, -1, 1, NULL), + (524, 706, 147, 8, 18, 27, -1, -1, 2, NULL), + (525, 706, 148, 8, 18, 30, -1, -1, 10, NULL), + (526, 706, 12, 2, 19, 28, -1, -1, 2, NULL), + (527, 706, 511, 256, 19, 30, -1, -1, 4, NULL), + (528, 706, 649, 8, 20, 25, -1, -1, 9, NULL), + (529, 706, 146, 8, 21, 24, -1, -1, 1, NULL), + (530, 706, 149, 8, 21, 29, -1, -1, 11, NULL), + (531, 706, 144, 8, 23, 38, -1, -1, 12, NULL), + (532, 706, 508, 1, 23, 32, -1, -1, 5, NULL), + (533, 706, 434, 256, 24, 36, -1, -1, 4, NULL), + (534, 706, 349, 8, 25, 38, -1, -1, 1, NULL), + (535, 706, 39, 8, 26, 41, -1, -1, 9, NULL), + (536, 706, 506, 1, 27, 37, -1, -1, 2, NULL), + (537, 706, 151, 8, 28, 34, -1, -1, 2, NULL), + (538, 706, 15, 2, 29, 50, -1, -1, 2, NULL), + (539, 706, 162, 1, 29, 40, -1, -1, 3, NULL), + (540, 706, 161, 8, 30, 42, -1, -1, 11, NULL), + (541, 706, 160, 8, 31, 40, -1, -1, 10, NULL), + (542, 706, 31, 256, 31, 48, -1, -1, 4, NULL), + (543, 706, 111, 1, 32, 47, -1, -1, 1, NULL), + (544, 706, 164, 32, 32, 36, -1, -1, 0, NULL), + (545, 706, 1428, 8, 35, 38, -1, -1, 2, NULL), + (546, 706, 435, 256, 37, 48, -1, -1, 4, NULL), + (547, 706, 577, 32, 37, 40, -1, -1, 0, NULL), + (548, 706, 507, 1, 38, 50, -1, -1, 2, NULL), + (549, 706, 527, 1, 38, 51, -1, -1, 4, NULL), + (550, 706, 145, 8, 39, 51, -1, -1, 12, NULL), + (551, 706, 152, 8, 39, 47, -1, -1, 1, NULL), + (552, 706, 153, 8, 39, 45, -1, -1, 2, NULL), + (553, 706, 154, 8, 41, 52, -1, -1, 10, NULL), + (554, 706, 163, 1, 41, 52, -1, -1, 3, NULL), + (555, 706, 165, 32, 41, 44, -1, -1, 0, NULL), + (556, 706, 170, 8, 42, 55, -1, -1, 9, NULL), + (557, 706, 158, 8, 43, 53, -1, -1, 11, NULL), + (558, 706, 3694, 1024, 44, 59, -1, -1, 5, NULL), + (559, 706, 754, 1024, 44, 53, -1, -1, 6, NULL), + (560, 706, 166, 32, 45, 54, -1, -1, 0, NULL), + (561, 706, 159, 8, 46, 56, -1, -1, 2, NULL), + (562, 706, 112, 1, 48, 56, -1, -1, 1, NULL), + (563, 706, 157, 8, 48, 57, -1, -1, 1, NULL), + (564, 706, 32, 256, 49, 58, -1, -1, 4, NULL), + (565, 706, 436, 256, 49, 55, -1, -1, 4, NULL), + (566, 706, 1588, 1, 51, 64, -1, -1, 2, NULL), + (567, 706, 9, 2, 51, 54, -1, -1, 2, NULL), + (568, 706, 1568, 8, 52, 55, -1, -1, 12, NULL), + (569, 706, 1573, 1, 52, 62, -1, -1, 4, NULL), + (570, 706, 1592, 1, 53, 65, -1, -1, 3, NULL), + (571, 706, 1594, 8, 53, 56, -1, -1, 10, NULL), + (572, 706, 1595, 8, 54, 56, -1, -1, 11, NULL), + (573, 706, 1572, 1024, 54, 57, -1, -1, 6, NULL), + (574, 706, 1290, 2, 55, 57, -1, -1, 3, NULL), + (575, 706, 1574, 32, 55, 60, -1, -1, 0, NULL), + (576, 706, 171, 8, 56, 62, -1, -1, 9, NULL), + (577, 706, 2528, 8, 56, 60, -1, -1, 12, NULL), + (578, 706, 1590, 256, 56, 59, -1, -1, 4, NULL), + (579, 706, 1580, 8, 57, 61, -1, -1, 11, NULL), + (580, 706, 1577, 1, 57, 59, -1, -1, 1, NULL), + (581, 706, 1593, 8, 57, 57, -1, -1, 2, NULL), + (582, 706, 1579, 8, 57, 60, -1, -1, 10, NULL), + (583, 706, 1596, 8, 58, 58, -1, -1, 1, NULL), + (584, 706, 1581, 8, 58, 59, -1, -1, 2, NULL), + (585, 706, 1332, 1024, 58, 64, -1, -1, 6, NULL), + (586, 706, 1583, 8, 59, 59, -1, -1, 1, NULL), + (587, 706, 1591, 256, 59, 63, -1, -1, 4, NULL), + (588, 706, 2112, 8, 60, 64, -1, -1, 2, NULL), + (589, 706, 2530, 8, 60, 61, -1, -1, 1, NULL), + (590, 706, 2113, 256, 60, 64, -1, -1, 4, NULL), + (591, 706, 1578, 1, 60, 62, -1, -1, 1, NULL), + (592, 706, 1576, 1024, 60, 64, -1, -1, 5, NULL), + (593, 706, 3378, 8, 61, 61, -1, -1, 10, NULL), + (594, 706, 3433, 8, 61, 62, -1, -1, 12, NULL), + (595, 706, 3377, 32, 61, 66, -1, -1, 0, NULL), + (596, 706, 3235, 8, 62, 64, -1, -1, 1, NULL), + (597, 706, 3383, 8, 62, 67, -1, -1, 10, NULL), + (598, 706, 3382, 8, 62, 62, -1, -1, 11, NULL), + (599, 706, 3233, 2, 62, 64, -1, -1, 2, NULL), + (600, 706, 172, 8, 63, 63, -1, -1, 9, NULL), + (601, 706, 3389, 8, 63, 67, -1, -1, 11, NULL), + (602, 706, 3441, 8, 63, 65, -1, -1, 12, NULL), + (603, 706, 3386, 1, 63, 65, -1, -1, 4, NULL), + (604, 706, 3387, 1, 63, 64, -1, -1, 1, NULL), + (605, 706, 3391, 8, 64, 255, -1, -1, 9, NULL), + (606, 706, 3394, 256, 64, 66, -1, -1, 4, NULL), + (607, 706, 3397, 8, 65, 67, -1, -1, 1, NULL), + (608, 706, 3399, 8, 65, 69, -1, -1, 2, NULL), + (609, 706, 3396, 256, 65, 69, -1, -1, 4, NULL), + (610, 706, 4900, 1, 65, 68, -1, -1, 2, NULL), + (611, 706, 3395, 1, 65, 255, -1, -1, 1, NULL), + (612, 706, 4901, 2, 65, 67, -1, -1, 2, NULL), + (613, 706, 4899, 1024, 65, 69, -1, -1, 5, NULL), + (614, 706, 4979, 1024, 65, 69, -1, -1, 6, NULL), + (615, 706, 5393, 8, 66, 68, -1, -1, 12, NULL), + (616, 706, 5394, 1, 66, 255, -1, -1, 3, NULL), + (617, 706, 5392, 1, 66, 255, -1, -1, 4, NULL), + (618, 706, 5411, 256, 67, 255, -1, -1, 4, NULL), + (619, 706, 5389, 32, 67, 255, -1, -1, 0, NULL), + (620, 706, 5396, 8, 68, 69, -1, -1, 1, NULL), + (621, 706, 5398, 8, 68, 68, -1, -1, 11, NULL), + (622, 706, 5395, 2, 68, 69, -1, -1, 2, NULL), + (623, 706, 5399, 8, 68, 255, -1, -1, 10, NULL), + (624, 706, 5405, 8, 69, 255, -1, -1, 11, NULL), + (625, 706, 5406, 8, 69, 255, -1, -1, 12, NULL), + (626, 706, 6827, 1, 69, 255, -1, -1, 2, NULL), + (627, 706, 5416, 1024, 70, 255, -1, -1, 5, NULL), + (628, 706, 5418, 1024, 70, 255, -1, -1, 6, NULL), + (629, 706, 5415, 8, 70, 255, -1, -1, 1, NULL), + (630, 706, 5417, 8, 70, 255, -1, -1, 2, NULL), + (631, 706, 5414, 256, 70, 255, -1, -1, 4, NULL), + (632, 706, 6142, 2, 70, 255, -1, -1, 2, NULL), + (633, 707, 239, 256, 1, 24, -1, -1, 2, NULL), + (634, 707, 242, 128, 1, 25, -1, -1, 1, NULL), + (635, 707, 93, 1, 1, 2, -1, -1, 3, NULL), + (636, 707, 200, 2, 1, 8, -1, -1, 2, NULL), + (637, 707, 248, 1, 2, 12, -1, -1, 2, NULL), + (638, 707, 253, 1, 3, 15, -1, -1, 3, NULL), + (639, 707, 92, 1, 3, 7, -1, -1, 3, NULL), + (640, 707, 256, 8, 7, 16, -1, -1, 1, NULL), + (641, 707, 515, 8, 7, 16, -1, -1, 8, NULL), + (642, 707, 91, 1, 8, 27, -1, -1, 3, NULL), + (643, 707, 17, 2, 9, 18, -1, -1, 2, NULL), + (644, 707, 264, 256, 10, 31, -1, -1, 2, NULL), + (645, 707, 663, 1, 13, 22, -1, -1, 2, NULL), + (646, 707, 520, 1, 16, 29, -1, -1, 3, NULL), + (647, 707, 273, 8, 17, 26, -1, -1, 1, NULL), + (648, 707, 516, 8, 17, 26, -1, -1, 8, NULL), + (649, 707, 12, 2, 19, 28, -1, -1, 2, NULL), + (650, 707, 115, 1, 23, 32, -1, -1, 2, NULL), + (651, 707, 99, 256, 24, 33, -1, -1, 2, NULL), + (652, 707, 78, 256, 25, 36, -1, -1, 2, NULL), + (653, 707, 512, 128, 26, 60, -1, -1, 1, NULL), + (654, 707, 129, 8, 27, 36, -1, -1, 1, NULL), + (655, 707, 517, 8, 27, 36, -1, -1, 8, NULL), + (656, 707, 217, 1, 28, 37, -1, -1, 3, NULL), + (657, 707, 15, 2, 29, 43, -1, -1, 2, NULL), + (658, 707, 1439, 1, 30, 55, -1, -1, 3, NULL), + (659, 707, 259, 256, 32, 39, -1, -1, 2, NULL), + (660, 707, 664, 1, 33, 42, -1, -1, 2, NULL), + (661, 707, 144, 8, 34, 38, -1, -1, 7, NULL), + (662, 707, 1437, 256, 37, 60, -1, -1, 2, NULL), + (663, 707, 432, 8, 37, 46, -1, -1, 1, NULL), + (664, 707, 518, 8, 37, 46, -1, -1, 8, NULL), + (665, 707, 57, 1, 38, 47, -1, -1, 3, NULL), + (666, 707, 137, 8, 39, 41, -1, -1, 7, NULL), + (667, 707, 665, 256, 40, 52, -1, -1, 2, NULL), + (668, 707, 427, 8, 40, 53, -1, -1, 9, NULL), + (669, 707, 1436, 256, 42, 61, -1, -1, 2, NULL), + (670, 707, 145, 8, 42, 44, -1, -1, 7, NULL), + (671, 707, 116, 1, 43, 54, -1, -1, 2, NULL), + (672, 707, 3834, 2, 44, 50, -1, -1, 2, NULL), + (673, 707, 138, 8, 45, 53, -1, -1, 7, NULL), + (674, 707, 29, 1, 47, 54, -1, -1, 3, NULL), + (675, 707, 356, 8, 47, 48, -1, -1, 1, NULL), + (676, 707, 519, 8, 47, 55, -1, -1, 8, NULL), + (677, 707, 671, 1, 48, 53, -1, -1, 3, NULL), + (678, 707, 1727, 8, 49, 57, -1, -1, 1, NULL), + (679, 707, 4104, 256, 49, 255, -1, -1, 2, NULL), + (680, 707, 1562, 8, 54, 59, -1, -1, 9, NULL), + (681, 707, 9, 2, 51, 54, -1, -1, 2, NULL), + (682, 707, 1600, 256, 52, 61, -1, -1, 2, NULL), + (683, 707, 1601, 256, 53, 62, -1, -1, 2, NULL), + (684, 707, 1568, 8, 54, 57, -1, -1, 7, NULL), + (685, 707, 1603, 1, 54, 58, -1, -1, 3, NULL), + (686, 707, 1290, 2, 55, 59, -1, -1, 2, NULL), + (687, 707, 1529, 1, 55, 64, -1, -1, 2, NULL), + (688, 707, 1605, 1, 55, 59, -1, -1, 3, NULL), + (689, 707, 4105, 256, 55, 255, -1, -1, 2, NULL), + (690, 707, 1558, 8, 56, 63, -1, -1, 8, NULL), + (691, 707, 1604, 1, 56, 60, -1, -1, 3, NULL), + (692, 707, 1560, 8, 58, 58, -1, -1, 1, NULL), + (693, 707, 1569, 8, 58, 59, -1, -1, 7, NULL), + (694, 707, 1561, 8, 59, 59, -1, -1, 1, NULL), + (695, 707, 1607, 1, 59, 59, -1, -1, 3, NULL), + (696, 707, 1563, 8, 60, 255, -1, -1, 9, NULL), + (697, 707, 1291, 2, 60, 62, -1, -1, 2, NULL), + (698, 707, 2125, 8, 60, 62, -1, -1, 1, NULL), + (699, 707, 2126, 1, 60, 63, -1, -1, 3, NULL), + (700, 707, 2520, 8, 60, 60, -1, -1, 7, NULL), + (701, 707, 2877, 1, 60, 64, -1, -1, 3, NULL), + (702, 707, 3433, 8, 61, 62, -1, -1, 7, NULL), + (703, 707, 3434, 1, 61, 65, -1, -1, 3, NULL), + (704, 707, 5572, 128, 61, 68, -1, -1, 1, NULL), + (705, 707, 3437, 256, 62, 63, -1, -1, 2, NULL), + (706, 707, 3440, 256, 62, 64, -1, -1, 2, NULL), + (707, 707, 3441, 8, 63, 65, -1, -1, 7, NULL), + (708, 707, 3443, 2, 63, 65, -1, -1, 2, NULL), + (709, 707, 3446, 256, 63, 67, -1, -1, 2, NULL), + (710, 707, 3448, 8, 63, 64, -1, -1, 1, NULL), + (711, 707, 3444, 8, 64, 255, -1, -1, 8, NULL), + (712, 707, 3449, 1, 64, 64, -1, -1, 3, NULL), + (713, 707, 4106, 256, 64, 255, -1, -1, 2, NULL), + (714, 707, 3238, 1, 65, 67, -1, -1, 2, NULL), + (715, 707, 3295, 8, 65, 66, -1, -1, 1, NULL), + (716, 707, 4974, 1, 65, 66, -1, -1, 3, NULL), + (717, 707, 4883, 2, 65, 67, -1, -1, 2, NULL), + (718, 707, 4884, 1, 65, 68, -1, -1, 3, NULL), + (719, 707, 4885, 256, 65, 66, -1, -1, 2, NULL), + (720, 707, 5342, 8, 66, 68, -1, -1, 7, NULL), + (721, 707, 5343, 1, 66, 255, -1, -1, 3, NULL), + (722, 707, 5348, 1, 67, 255, -1, -1, 3, NULL), + (723, 707, 5358, 8, 67, 69, -1, -1, 1, NULL), + (724, 707, 5355, 2, 68, 69, -1, -1, 2, NULL), + (725, 707, 5357, 256, 68, 255, -1, -1, 2, NULL), + (726, 707, 8008, 1, 68, 255, -1, -1, 1, NULL), + (727, 707, 5353, 8, 69, 255, -1, -1, 7, NULL), + (728, 707, 5361, 1, 69, 255, -1, -1, 3, NULL), + (729, 707, 6665, 128, 69, 255, -1, -1, 1, NULL), + (730, 707, 5365, 8, 70, 255, -1, -1, 1, NULL), + (731, 707, 6141, 2, 70, 255, -1, -1, 2, NULL), + (732, 708, 5011, 2, 1, 5, -1, -1, 2, NULL), + (733, 708, 200, 2, 6, 11, -1, -1, 2, NULL), + (734, 708, 2581, 1, 7, 12, -1, -1, 3, NULL), + (735, 708, 202, 8, 8, 19, -1, -1, 1, NULL), + (736, 708, 17, 2, 12, 26, -1, -1, 2, NULL), + (737, 708, 2582, 1, 13, 27, -1, -1, 3, NULL), + (738, 708, 218, 1, 14, 29, -1, -1, 2, NULL), + (739, 708, 11, 8, 15, 29, -1, -1, 2, NULL), + (740, 708, 219, 8, 20, 36, -1, -1, 1, NULL), + (741, 708, 485, 8, 24, 32, -1, -1, 3, NULL), + (742, 708, 2583, 8, 26, 62, -1, -1, 5, NULL), + (743, 708, 12, 2, 27, 35, -1, -1, 2, NULL), + (744, 708, 216, 1, 28, 41, -1, -1, 3, NULL), + (745, 708, 233, 1, 30, 45, -1, -1, 2, NULL), + (746, 708, 368, 8, 30, 38, -1, -1, 2, NULL), + (747, 708, 486, 8, 33, 45, -1, -1, 3, NULL), + (748, 708, 2584, 8, 35, 48, -1, -1, 4, NULL), + (749, 708, 15, 2, 36, 51, -1, -1, 2, NULL), + (750, 708, 89, 8, 37, 46, -1, -1, 1, NULL), + (751, 708, 18, 8, 39, 47, -1, -1, 2, NULL), + (752, 708, 123, 1, 42, 51, -1, -1, 3, NULL), + (753, 708, 2585, 8, 44, 255, -1, -1, 7, NULL), + (754, 708, 3683, 2, 44, 58, -1, -1, 1, NULL), + (755, 708, 117, 1, 46, 53, -1, -1, 2, NULL), + (756, 708, 487, 8, 46, 57, -1, -1, 3, NULL), + (757, 708, 312, 8, 47, 59, -1, -1, 1, NULL), + (758, 708, 19, 8, 48, 59, -1, -1, 2, NULL), + (759, 708, 207, 16, 48, 255, -1, -1, 1, NULL), + (760, 708, 3578, 8, 49, 52, -1, -1, 4, NULL), + (761, 708, 124, 1, 52, 52, -1, -1, 3, NULL), + (762, 708, 3684, 2, 52, 56, -1, -1, 2, NULL), + (763, 708, 1288, 8, 53, 59, -1, -1, 4, NULL), + (764, 708, 3975, 1, 53, 53, -1, -1, 3, NULL), + (765, 708, 2587, 1, 54, 61, -1, -1, 3, NULL), + (766, 708, 662, 1, 54, 61, -1, -1, 2, NULL), + (767, 708, 1743, 8, 55, 255, -1, -1, 2, NULL), + (768, 708, 9, 2, 57, 60, -1, -1, 2, NULL), + (769, 708, 488, 8, 58, 62, -1, -1, 3, NULL), + (770, 708, 1283, 2, 59, 63, -1, -1, 1, NULL), + (771, 708, 2590, 8, 60, 64, -1, -1, 4, NULL), + (772, 708, 314, 8, 60, 60, -1, -1, 1, NULL), + (773, 708, 20, 8, 60, 64, -1, -1, 2, NULL), + (774, 708, 1533, 8, 61, 63, -1, -1, 1, NULL), + (775, 708, 3429, 2, 61, 62, -1, -1, 2, NULL), + (776, 708, 3245, 1, 62, 63, -1, -1, 3, NULL), + (777, 708, 3428, 1, 62, 66, -1, -1, 2, NULL), + (778, 708, 3430, 2, 63, 64, -1, -1, 2, NULL), + (779, 708, 1535, 8, 63, 64, -1, -1, 3, NULL), + (780, 708, 3424, 8, 63, 64, -1, -1, 5, NULL), + (781, 708, 1538, 8, 64, 64, -1, -1, 1, NULL), + (782, 708, 3426, 1, 64, 64, -1, -1, 3, NULL), + (783, 708, 3247, 8, 64, 68, -1, -1, 9, NULL), + (784, 708, 2589, 2, 64, 255, -1, -1, 2, NULL), + (785, 708, 4894, 2, 65, 67, -1, -1, 2, NULL), + (786, 708, 3432, 8, 65, 69, -1, -1, 4, NULL), + (787, 708, 4109, 8, 65, 69, -1, -1, 2, NULL), + (788, 708, 4895, 8, 65, 67, -1, -1, 5, NULL), + (789, 708, 4977, 1, 65, 65, -1, -1, 3, NULL), + (790, 708, 5284, 1, 66, 67, -1, -1, 3, NULL), + (791, 708, 5286, 1, 67, 67, -1, -1, 2, NULL), + (792, 708, 5289, 2, 68, 255, -1, -1, 2, NULL), + (793, 708, 8027, 1, 68, 255, -1, -1, 2, NULL), + (794, 708, 5288, 8, 68, 255, -1, -1, 5, NULL), + (795, 708, 5292, 1, 68, 69, -1, -1, 3, NULL), + (796, 708, 5291, 8, 69, 255, -1, -1, 9, NULL), + (797, 708, 8029, 8, 69, 255, -1, -1, 10, NULL), + (798, 708, 5298, 8, 70, 255, -1, -1, 2, NULL), + (799, 708, 5297, 8, 70, 255, -1, -1, 4, NULL), + (800, 708, 5299, 1, 70, 255, -1, -1, 3, NULL), + (801, 709, 5012, 1, 1, 33, -1, -1, 5, NULL), + (802, 709, 340, 256, 5, 56, -1, -1, 3, NULL), + (803, 709, 491, 32, 7, 13, -1, -1, 0, NULL), + (804, 709, 341, 64, 8, 14, -1, -1, 3, NULL), + (805, 709, 2571, 1, 9, 49, -1, -1, 2, NULL), + (806, 709, 344, 128, 11, 19, -1, -1, 1, NULL), + (807, 709, 229, 1, 12, 42, -1, 45, 4, NULL), + (808, 709, 351, 32, 14, 21, -1, -1, 0, NULL), + (809, 709, 502, 64, 15, 28, -1, -1, 3, NULL), + (810, 709, 346, 8, 16, 57, -1, -1, 1, NULL), + (811, 709, 355, 128, 20, 43, -1, -1, 1, NULL), + (812, 709, 359, 8, 22, 36, -1, -1, 2, NULL), + (813, 709, 362, 32, 22, 29, -1, -1, 0, NULL), + (814, 709, 360, 256, 28, 40, -1, -1, 3, NULL), + (815, 709, 1289, 8, 29, 59, -1, -1, 9, NULL), + (816, 709, 445, 64, 29, 46, -1, -1, 3, NULL), + (817, 709, 492, 32, 30, 37, -1, -1, 0, NULL), + (818, 709, 236, 8, 31, 55, -1, -1, 8, NULL), + (819, 709, 3561, 1, 34, 47, -1, -1, 5, NULL), + (820, 709, 367, 256, 36, 59, -1, -1, 3, NULL), + (821, 709, 2574, 8, 37, 54, -1, -1, 2, NULL), + (822, 709, 370, 1, 37, 49, -1, -1, 2, NULL), + (823, 709, 440, 32, 38, 45, -1, -1, 0, NULL), + (824, 709, 3686, 256, 41, 52, -1, -1, 3, NULL), + (825, 709, 127, 1, 43, 56, -1, 45, 4, NULL), + (826, 709, 452, 128, 44, 58, -1, -1, 1, NULL), + (827, 709, 441, 32, 46, 51, -1, -1, 0, NULL), + (828, 709, 692, 64, 47, 56, -1, -1, 3, NULL), + (829, 709, 3560, 1, 48, 53, -1, -1, 5, NULL), + (830, 709, 199, 16, 50, 255, -1, -1, 1, NULL), + (831, 709, 442, 32, 52, 57, -1, -1, 0, NULL), + (832, 709, 451, 256, 53, 60, -1, -1, 3, NULL), + (833, 709, 3562, 1, 54, 63, -1, -1, 5, NULL), + (834, 709, 1376, 8, 55, 62, -1, -1, 2, NULL), + (835, 709, 393, 8, 56, 58, -1, -1, 8, NULL), + (836, 709, 454, 256, 57, 61, -1, -1, 3, NULL), + (837, 709, 525, 64, 57, 59, -1, -1, 3, NULL), + (838, 709, 6986, 1, 57, 61, -1, -1, 4, NULL), + (839, 709, 495, 32, 58, 63, -1, -1, 0, NULL), + (840, 709, 394, 8, 59, 255, -1, -1, 8, NULL), + (841, 709, 453, 128, 59, 60, -1, -1, 1, NULL), + (842, 709, 661, 8, 60, 63, -1, -1, 9, NULL), + (843, 709, 1508, 256, 60, 65, -1, -1, 3, NULL), + (844, 709, 447, 64, 60, 61, -1, -1, 3, NULL), + (845, 709, 3400, 128, 61, 255, -1, -1, 1, NULL), + (846, 709, 6, 256, 61, 62, -1, -1, 3, NULL), + (847, 709, 456, 256, 62, 65, -1, -1, 3, NULL), + (848, 709, 3401, 64, 62, 64, -1, -1, 3, NULL), + (849, 709, 3227, 8, 63, 64, -1, -1, 2, NULL), + (850, 709, 3489, 256, 63, 65, -1, -1, 3, NULL), + (851, 709, 6987, 1, 62, 66, -1, -1, 4, NULL), + (852, 709, 1414, 8, 64, 68, -1, -1, 9, NULL), + (853, 709, 3491, 1, 64, 64, -1, -1, 5, NULL), + (854, 709, 443, 32, 64, 67, -1, -1, 0, NULL), + (855, 709, 3413, 64, 65, 66, -1, -1, 3, NULL), + (856, 709, 4904, 1, 65, 68, -1, -1, 5, NULL), + (857, 709, 5323, 256, 66, 255, -1, -1, 3, NULL), + (858, 709, 5320, 256, 66, 67, -1, -1, 3, NULL), + (859, 709, 5322, 256, 66, 255, -1, -1, 3, NULL), + (860, 709, 5327, 8, 67, 255, -1, -1, 2, NULL), + (861, 709, 5324, 64, 67, 69, -1, -1, 3, NULL), + (862, 709, 6988, 1, 67, 255, -1, -1, 4, NULL), + (863, 709, 5330, 256, 68, 255, -1, -1, 3, NULL), + (864, 709, 5331, 32, 68, 255, -1, -1, 0, NULL), + (865, 709, 5332, 8, 69, 255, -1, -1, 9, NULL), + (866, 709, 5334, 1, 69, 255, -1, -1, 5, NULL), + (867, 709, 5338, 64, 70, 255, -1, -1, 3, NULL), + (868, 710, 5011, 2, 1, 7, -1, -1, 2, NULL), + (869, 710, 239, 256, 3, 43, -1, -1, 3, NULL), + (870, 710, 2591, 128, 5, 5, -1, -1, 1, NULL), + (871, 710, 242, 128, 6, 50, -1, -1, 1, NULL), + (872, 710, 26, 8, 7, 20, -1, -1, 1, NULL), + (873, 710, 200, 2, 8, 20, -1, -1, 2, NULL), + (874, 710, 2592, 8, 11, 51, -1, -1, 9, NULL), + (875, 710, 269, 8, 12, 54, -1, -1, 8, NULL), + (876, 710, 515, 8, 13, 29, -1, -1, 7, NULL), + (877, 710, 92, 1, 14, 18, -1, -1, 4, NULL), + (878, 710, 254, 8, 17, 36, -1, -1, 6, NULL), + (879, 710, 91, 1, 19, 28, -1, -1, 4, NULL), + (880, 710, 17, 2, 21, 37, -1, -1, 2, NULL), + (881, 710, 263, 8, 21, 37, -1, -1, 1, NULL), + (882, 710, 256, 8, 24, 42, -1, -1, 5, NULL), + (883, 710, 264, 256, 25, 39, -1, -1, 3, NULL), + (884, 710, 268, 8, 26, 52, -1, -1, 4, NULL), + (885, 710, 2593, 8, 29, 47, -1, -1, 2, NULL), + (886, 710, 3565, 1, 29, 38, -1, -1, 4, NULL), + (887, 710, 516, 8, 30, 33, -1, -1, 7, NULL), + (888, 710, 517, 8, 34, 41, -1, -1, 7, NULL), + (889, 710, 1461, 8, 36, 54, -1, -1, 10, NULL), + (890, 710, 2594, 8, 37, 50, -1, -1, 6, NULL), + (891, 710, 12, 2, 38, 56, -1, -1, 2, NULL), + (892, 710, 421, 8, 38, 53, -1, -1, 1, NULL), + (893, 710, 3564, 1, 39, 48, -1, -1, 4, NULL), + (894, 710, 3687, 256, 40, 53, -1, -1, 3, NULL), + (895, 710, 518, 8, 42, 59, -1, -1, 7, NULL), + (896, 710, 129, 8, 43, 57, -1, -1, 5, NULL), + (897, 710, 78, 256, 44, 255, -1, -1, 3, NULL), + (898, 710, 2595, 8, 48, 49, -1, -1, 2, NULL), + (899, 710, 691, 1, 49, 51, -1, -1, 4, NULL), + (900, 710, 1462, 8, 50, 61, -1, -1, 2, NULL), + (901, 710, 1741, 16, 50, 54, -1, -1, 1, NULL), + (902, 710, 1397, 8, 51, 61, -1, -1, 6, NULL), + (903, 710, 512, 128, 51, 60, -1, -1, 1, NULL), + (904, 710, 2596, 8, 52, 57, -1, -1, 9, NULL), + (905, 710, 57, 1, 52, 58, -1, -1, 4, NULL), + (906, 710, 430, 8, 53, 255, -1, -1, 4, NULL), + (907, 710, 259, 256, 54, 61, -1, -1, 3, NULL), + (908, 710, 422, 8, 54, 58, -1, -1, 1, NULL), + (909, 710, 1296, 16, 55, 255, -1, -1, 1, NULL), + (910, 710, 145, 8, 55, 63, -1, -1, 8, NULL), + (911, 710, 1463, 8, 55, 57, -1, -1, 10, NULL), + (912, 710, 15, 2, 57, 61, -1, -1, 2, NULL), + (913, 710, 432, 8, 58, 61, -1, -1, 5, NULL), + (914, 710, 4059, 8, 58, 63, -1, -1, 10, NULL), + (915, 710, 2599, 8, 58, 255, -1, -1, 9, NULL), + (916, 710, 423, 8, 59, 64, -1, -1, 1, NULL), + (917, 710, 1740, 1, 59, 63, -1, -1, 4, NULL), + (918, 710, 519, 8, 60, 62, -1, -1, 7, NULL), + (919, 710, 6732, 128, 61, 68, -1, -1, 1, NULL), + (920, 710, 3419, 8, 62, 66, -1, -1, 2, NULL), + (921, 710, 356, 8, 62, 65, -1, -1, 5, NULL), + (922, 710, 3487, 8, 62, 66, -1, -1, 6, NULL), + (923, 710, 665, 256, 62, 66, -1, -1, 3, NULL), + (924, 710, 1290, 2, 62, 64, -1, -1, 2, NULL), + (925, 710, 1558, 8, 63, 67, -1, -1, 7, NULL), + (926, 710, 1568, 8, 64, 67, -1, -1, 8, NULL), + (927, 710, 3415, 8, 64, 64, -1, -1, 10, NULL), + (928, 710, 3431, 1, 64, 64, -1, -1, 4, NULL), + (929, 710, 1559, 8, 65, 69, -1, -1, 1, NULL), + (930, 710, 4898, 8, 65, 68, -1, -1, 10, NULL), + (931, 710, 4980, 1, 65, 68, -1, -1, 4, NULL), + (932, 710, 4896, 2, 65, 66, -1, -1, 2, NULL), + (933, 710, 5302, 8, 66, 255, -1, -1, 5, NULL), + (934, 710, 5305, 8, 66, 255, -1, -1, 2, NULL), + (935, 710, 5306, 8, 67, 255, -1, -1, 6, NULL), + (936, 710, 5303, 256, 67, 255, -1, -1, 3, NULL), + (937, 710, 5304, 2, 67, 255, -1, -1, 2, NULL), + (938, 710, 5307, 8, 68, 255, -1, -1, 7, NULL), + (939, 710, 5310, 8, 68, 255, -1, -1, 8, NULL), + (940, 710, 5311, 8, 69, 255, -1, -1, 10, NULL), + (941, 710, 6664, 128, 69, 255, -1, -1, 1, NULL), + (942, 710, 5313, 1, 69, 69, -1, -1, 4, NULL), + (943, 710, 5315, 8, 70, 255, -1, -1, 1, NULL), + (944, 710, 5319, 1, 70, 255, -1, -1, 4, NULL), + (945, 711, 700, 8, 1, 9, -1, -1, 1, NULL), + (946, 711, 7, 2, 6, 33, -1, -1, 2, NULL), + (947, 711, 710, 8, 9, 12, -1, -1, 2, NULL), + (948, 711, 701, 8, 10, 35, -1, -1, 1, NULL), + (949, 711, 711, 8, 13, 24, -1, -1, 2, NULL), + (950, 711, 709, 8, 17, 51, -1, -1, 3, NULL), + (951, 711, 1287, 2, 20, 31, -1, -1, 2, NULL), + (952, 711, 738, 1, 23, 255, -1, -1, 3, NULL), + (953, 711, 712, 8, 25, 28, -1, -1, 2, NULL), + (954, 711, 715, 8, 29, 32, -1, -1, 3, NULL), + (955, 711, 707, 1, 30, 37, -1, -1, 2, NULL), + (956, 711, 723, 2, 32, 33, -1, -1, 3, NULL), + (957, 711, 713, 8, 33, 36, -1, -1, 2, NULL), + (958, 711, 1448, 2, 34, 54, -1, -1, 2, NULL), + (959, 711, 740, 8, 36, 41, -1, -1, 1, NULL), + (960, 711, 716, 8, 37, 40, -1, -1, 2, NULL), + (961, 711, 743, 1, 38, 41, -1, -1, 4, NULL), + (962, 711, 714, 8, 41, 46, -1, -1, 2, NULL), + (963, 711, 3567, 1, 42, 45, -1, -1, 5, NULL), + (964, 711, 702, 8, 42, 49, -1, -1, 1, NULL), + (965, 711, 744, 1, 46, 49, -1, -1, 6, NULL), + (966, 711, 748, 8, 47, 53, -1, -1, 2, NULL), + (967, 711, 3566, 1, 50, 62, -1, -1, 2, NULL), + (968, 711, 747, 8, 50, 53, -1, -1, 1, NULL), + (969, 711, 1751, 1, 51, 255, -1, -1, 4, NULL), + (970, 711, 2606, 8, 52, 59, -1, -1, 3, NULL), + (971, 711, 1754, 16, 53, 59, -1, -1, 1, NULL), + (972, 711, 2607, 8, 54, 255, -1, -1, 2, NULL), + (973, 711, 1759, 2, 55, 57, -1, -1, 2, NULL), + (974, 711, 2609, 2, 58, 59, -1, -1, 2, NULL), + (975, 711, 1196, 2, 60, 61, -1, -1, 2, NULL), + (976, 711, 1749, 16, 60, 255, -1, -1, 1, NULL), + (977, 711, 2610, 8, 60, 63, -1, -1, 3, NULL), + (978, 711, 3374, 8, 62, 64, -1, -1, 1, NULL), + (979, 711, 3651, 2, 62, 63, -1, -1, 2, NULL), + (980, 711, 3370, 1, 63, 63, -1, -1, 2, NULL), + (981, 711, 3066, 1, 64, 255, -1, -1, 2, NULL), + (982, 711, 3362, 8, 64, 64, -1, -1, 3, NULL), + (983, 711, 3372, 2, 64, 66, -1, -1, 2, NULL), + (984, 711, 4871, 8, 65, 67, -1, -1, 1, NULL), + (985, 711, 4872, 8, 65, 67, -1, -1, 3, NULL), + (986, 711, 5377, 2, 67, 68, -1, -1, 2, NULL), + (987, 711, 5376, 8, 68, 255, -1, -1, 1, NULL), + (988, 711, 5380, 8, 68, 68, -1, -1, 3, NULL), + (989, 711, 5382, 8, 69, 69, -1, -1, 3, NULL), + (990, 711, 5384, 2, 69, 255, -1, -1, 2, NULL), + (991, 711, 5388, 8, 70, 255, -1, -1, 3, NULL), + (992, 712, 5011, 2, 1, 5, -1, -1, 2, NULL), + (993, 712, 200, 2, 6, 19, -1, -1, 2, NULL), + (994, 712, 267, 8, 7, 19, -1, -1, 9, NULL), + (995, 712, 2612, 32, 8, 14, -1, -1, 0, NULL), + (996, 712, 2611, 2, 9, 14, -1, -1, 2, NULL), + (997, 712, 274, 8, 10, 25, -1, -1, 8, NULL), + (998, 712, 2068, 1, 12, 25, -1, -1, 4, NULL), + (999, 712, 2635, 8, 13, 17, -1, -1, 6, NULL), + (1000, 712, 40, 8, 14, 27, -1, -1, 5, NULL), + (1001, 712, 75, 256, 14, 39, -1, -1, 3, NULL), + (1002, 712, 2613, 2, 15, 26, -1, -1, 2, NULL), + (1003, 712, 2633, 32, 15, 20, -1, -1, 0, NULL), + (1004, 712, 279, 8, 17, 36, -1, -1, 4, NULL), + (1005, 712, 2636, 8, 18, 27, -1, -1, 6, NULL), + (1006, 712, 277, 256, 19, 34, -1, -1, 3, NULL), + (1007, 712, 270, 1, 20, 49, -1, -1, 3, NULL), + (1008, 712, 17, 2, 20, 35, -1, -1, 2, NULL), + (1009, 712, 2614, 32, 21, 29, -1, -1, 0, NULL), + (1010, 712, 282, 1, 26, 32, -1, -1, 4, NULL), + (1011, 712, 283, 8, 26, 36, -1, -1, 8, NULL), + (1012, 712, 2615, 2, 27, 35, -1, -1, 2, NULL), + (1013, 712, 147, 8, 28, 40, -1, -1, 5, NULL), + (1014, 712, 2637, 8, 28, 37, -1, -1, 6, NULL), + (1015, 712, 2616, 32, 30, 38, -1, -1, 0, NULL), + (1016, 712, 3568, 1, 33, 46, -1, -1, 4, NULL), + (1017, 712, 434, 256, 35, 51, -1, -1, 3, NULL), + (1018, 712, 48, 512, 35, 57, -1, -1, 6, NULL), + (1019, 712, 12, 2, 36, 56, -1, -1, 2, NULL), + (1020, 712, 2617, 2, 36, 48, -1, -1, 2, NULL), + (1021, 712, 2619, 8, 37, 51, -1, -1, 8, NULL), + (1022, 712, 149, 8, 37, 51, -1, -1, 3, NULL), + (1023, 712, 2638, 8, 38, 45, -1, -1, 6, NULL), + (1024, 712, 2618, 32, 39, 45, -1, -1, 0, NULL), + (1025, 712, 3689, 256, 40, 64, -1, -1, 3, NULL), + (1026, 712, 151, 8, 41, 53, -1, -1, 5, NULL), + (1027, 712, 2176, 8, 41, 51, -1, -1, 4, NULL), + (1028, 712, 2178, 8, 42, 59, -1, -1, 2, NULL), + (1029, 712, 2621, 32, 46, 53, -1, -1, 0, NULL), + (1030, 712, 2639, 8, 46, 50, -1, -1, 6, NULL), + (1031, 712, 308, 8, 47, 255, -1, -1, 7, NULL), + (1032, 712, 3569, 1, 47, 53, -1, -1, 4, NULL), + (1033, 712, 2620, 2, 49, 51, -1, -1, 2, NULL), + (1034, 712, 2634, 1, 50, 59, -1, -1, 3, NULL), + (1035, 712, 2640, 8, 51, 52, -1, -1, 6, NULL), + (1036, 712, 161, 8, 52, 56, -1, -1, 3, NULL), + (1037, 712, 2177, 8, 52, 58, -1, -1, 4, NULL), + (1038, 712, 2622, 2, 52, 54, -1, -1, 2, NULL), + (1039, 712, 3690, 8, 52, 54, -1, -1, 8, NULL), + (1040, 712, 435, 256, 52, 60, -1, -1, 3, NULL), + (1041, 712, 167, 8, 53, 57, -1, -1, 6, NULL), + (1042, 712, 153, 8, 54, 255, -1, -1, 5, NULL), + (1043, 712, 2623, 32, 54, 55, -1, -1, 0, NULL), + (1044, 712, 3570, 1, 54, 58, -1, -1, 4, NULL), + (1045, 712, 2625, 8, 55, 58, -1, -1, 8, NULL), + (1046, 712, 145, 8, 55, 63, -1, -1, 1, NULL), + (1047, 712, 2626, 32, 56, 57, -1, -1, 0, NULL), + (1048, 712, 15, 2, 57, 61, -1, -1, 2, NULL), + (1049, 712, 158, 8, 57, 255, -1, -1, 3, NULL), + (1050, 712, 168, 8, 58, 61, -1, -1, 6, NULL), + (1051, 712, 2627, 32, 58, 59, -1, -1, 0, NULL), + (1052, 712, 49, 512, 58, 59, -1, -1, 6, NULL), + (1053, 712, 2628, 8, 59, 62, -1, -1, 8, NULL), + (1054, 712, 2629, 8, 59, 63, -1, -1, 4, NULL), + (1055, 712, 510, 1, 59, 62, -1, -1, 4, NULL), + (1056, 712, 2941, 8, 60, 64, -1, -1, 10, NULL), + (1057, 712, 2630, 8, 60, 61, -1, -1, 2, NULL), + (1058, 712, 2631, 32, 60, 61, -1, -1, 0, NULL), + (1059, 712, 2942, 1, 60, 64, -1, -1, 3, NULL), + (1060, 712, 3492, 256, 61, 65, -1, -1, 3, NULL), + (1061, 712, 3456, 8, 62, 66, -1, -1, 2, NULL), + (1062, 712, 1585, 8, 62, 66, -1, -1, 6, NULL), + (1063, 712, 1290, 2, 62, 64, -1, -1, 2, NULL), + (1064, 712, 3457, 32, 62, 63, -1, -1, 0, NULL), + (1065, 712, 3458, 8, 63, 67, -1, -1, 8, NULL), + (1066, 712, 3493, 1, 63, 64, -1, -1, 4, NULL), + (1067, 712, 1568, 8, 64, 68, -1, -1, 1, NULL), + (1068, 712, 3460, 8, 64, 68, -1, -1, 4, NULL), + (1069, 712, 3461, 32, 64, 67, -1, -1, 0, NULL), + (1070, 712, 3463, 8, 65, 69, -1, -1, 10, NULL), + (1071, 712, 32, 256, 65, 69, -1, -1, 3, NULL), + (1072, 712, 3462, 1, 65, 69, -1, -1, 3, NULL), + (1073, 712, 4972, 1, 65, 68, -1, -1, 4, NULL), + (1074, 712, 4875, 2, 65, 66, -1, -1, 2, NULL), + (1075, 712, 5527, 256, 66, 255, -1, -1, 3, NULL), + (1076, 712, 5530, 8, 67, 255, -1, -1, 2, NULL), + (1077, 712, 5529, 8, 67, 255, -1, -1, 6, NULL), + (1078, 712, 5528, 2, 67, 255, -1, -1, 2, NULL), + (1079, 712, 5533, 8, 68, 255, -1, -1, 8, NULL), + (1080, 712, 5531, 32, 68, 69, -1, -1, 0, NULL), + (1081, 712, 5536, 8, 69, 255, -1, -1, 1, NULL), + (1082, 712, 5537, 8, 69, 255, -1, -1, 4, NULL), + (1083, 712, 5535, 1, 69, 69, -1, -1, 4, NULL), + (1084, 712, 5542, 8, 70, 255, -1, -1, 10, NULL), + (1085, 712, 5540, 256, 70, 255, -1, -1, 3, NULL), + (1086, 712, 6828, 1, 70, 255, -1, -1, 3, NULL), + (1087, 712, 5543, 1, 70, 255, -1, -1, 4, NULL), + (1088, 712, 5538, 32, 70, 255, -1, -1, 0, NULL), + (1089, 707, 425, 8, 20, 255, -1, -1, 0, NULL), + (1090, 705, 190, 2048, 47, 55, -1, -1, 0, NULL), + (1091, 705, 292, 2048, 2, 12, -1, -1, 0, NULL), + (1092, 705, 187, 2048, 13, 29, -1, -1, 0, NULL), + (1093, 705, 188, 2048, 30, 46, -1, -1, 0, NULL), + (1094, 705, 1691, 2048, 54, 58, -1, -1, 0, NULL), + (1095, 705, 1692, 2048, 59, 59, -1, -1, 0, NULL), + (1096, 705, 2120, 2048, 60, 60, -1, -1, 0, NULL), + (1097, 705, 3341, 2048, 61, 62, -1, -1, 0, NULL), + (1098, 705, 3354, 2048, 63, 63, -1, -1, 0, NULL), + (1099, 705, 3358, 2048, 64, 66, -1, -1, 0, NULL), + (1100, 705, 5503, 2048, 67, 67, -1, -1, 0, NULL), + (1101, 705, 8035, 2048, 68, 68, -1, -1, 0, NULL), + (1102, 705, 5520, 2048, 69, 255, -1, -1, 0, NULL), + (1103, 709, 343, 16384, 6, 51, -1, -1, 3, NULL), + (1104, 709, 2572, 16384, 15, 34, -1, -1, 3, NULL), + (1105, 709, 2573, 16384, 23, 49, -1, -1, 3, NULL), + (1106, 709, 1457, 16384, 35, 53, -1, -1, 3, NULL), + (1107, 709, 1458, 16384, 50, 55, -1, -1, 3, NULL), + (1108, 709, 2575, 16384, 52, 59, -1, -1, 3, NULL), + (1109, 709, 2577, 16384, 54, 64, -1, -1, 3, NULL), + (1110, 709, 2578, 16384, 56, 62, -1, -1, 3, NULL), + (1111, 709, 2579, 16384, 58, 65, -1, -1, 3, NULL), + (1112, 709, 3406, 16384, 61, 70, -1, -1, 2, NULL), + (1113, 707, 3435, 16384, 61, 85, -1, -1, 2, NULL), + (1114, 707, 5351, 16384, 67, 73, -1, -1, 2, NULL), + (1115, 707, 5354, 16384, 67, 71, -1, -1, 2, NULL), + (1116, 703, 343, 16384, 1, 12, -1, -1, 3, NULL), + (1117, 703, 1511, 16384, 10, 20, -1, -1, 3, NULL), + (1118, 703, 1512, 16384, 21, 36, -1, -1, 3, NULL), + (1119, 703, 1513, 16384, 37, 51, -1, -1, 3, NULL), + (1120, 703, 1716, 16384, 52, 67, -1, -1, 3, NULL), + (1121, 703, 2546, 16384, 52, 65, -1, -1, 3, NULL), + (1122, 703, 5427, 16384, 68, 71, -1, -1, 3, NULL), + (1123, 704, 110, 16384, 22, 43, -1, -1, 2, NULL), + (1124, 704, 111, 16384, 44, 50, -1, -1, 2, NULL), + (1125, 704, 112, 16384, 51, 57, -1, -1, 2, NULL), + (1126, 704, 1577, 16384, 58, 59, -1, -1, 2, NULL), + (1127, 704, 1772, 16384, 60, 255, -1, -1, 1, NULL), + (1128, 704, 3387, 16384, 63, 70, -1, -1, 2, NULL), + (1129, 705, 41, 16384, 1, 3, -1, -1, 3, NULL), + (1130, 705, 676, 16384, 2, 17, -1, -1, 1, NULL), + (1131, 705, 291, 16384, 4, 8, -1, -1, 3, NULL), + (1132, 705, 645, 16384, 9, 18, -1, -1, 3, NULL), + (1133, 705, 281, 16384, 16, 24, -1, -1, 3, NULL), + (1134, 705, 677, 16384, 18, 40, -1, -1, 1, NULL), + (1135, 705, 179, 16384, 19, 33, -1, -1, 4, NULL), + (1136, 705, 162, 16384, 25, 39, -1, -1, 3, NULL), + (1137, 705, 180, 16384, 34, 41, -1, -1, 4, NULL), + (1138, 705, 163, 16384, 40, 52, -1, -1, 3, NULL), + (1139, 705, 678, 16384, 41, 56, -1, -1, 1, NULL), + (1140, 705, 181, 16384, 42, 52, -1, -1, 4, NULL), + (1141, 705, 1592, 16384, 53, 65, -1, -1, 3, NULL), + (1142, 705, 1702, 16384, 57, 60, -1, -1, 1, NULL), + (1143, 705, 3342, 16384, 61, 71, -1, -1, 1, NULL), + (1144, 705, 5499, 16384, 66, 70, -1, -1, 3, NULL), + (1145, 712, 162, 16384, 44, 55, -1, -1, 2, NULL), + (1146, 712, 163, 16384, 56, 65, -1, -1, 2, NULL), + (1147, 707, 14312, 16384, 71, 75, -1, -1, 3, NULL), + (1148, 707, 14313, 16384, 71, 75, -1, -1, 3, NULL), + (1149, 707, 14314, 16384, 71, 75, -1, -1, 3, NULL), + (1150, 707, 0, 16384, 76, 80, -1, -1, 2, NULL), + (1151, 707, 18392, 16384, 81, 85, -1, -1, 2, NULL), + (1152, 707, 18393, 16384, 81, 85, -1, -1, 2, NULL), + (1153, 707, 18394, 16384, 81, 85, -1, -1, 2, NULL), + (1154, 703, 10516, 16384, 72, 76, -1, -1, 3, NULL), + (1155, 703, 10517, 16384, 72, 76, -1, -1, 3, NULL), + (1156, 703, 10518, 16384, 72, 76, -1, -1, 3, NULL), + (1157, 703, 0, 16384, 77, 81, -1, -1, 3, NULL), + (1158, 703, 18970, 16384, 82, 86, -1, -1, 3, NULL), + (1159, 703, 18971, 16384, 82, 86, -1, -1, 3, NULL), + (1160, 703, 18972, 16384, 82, 86, -1, -1, 3, NULL), + (1161, 704, 15186, 16384, 76, 80, -1, -1, 2, NULL), + (1162, 704, 15187, 16384, 76, 80, -1, -1, 2, NULL), + (1163, 704, 15188, 16384, 76, 80, -1, -1, 2, NULL), + (1164, 704, 18726, 16384, 81, 85, -1, -1, 2, NULL), + (1165, 704, 18727, 16384, 81, 85, -1, -1, 2, NULL), + (1166, 704, 18728, 16384, 81, 85, -1, -1, 2, NULL), + (1167, 705, 14446, 16384, 71, 75, -1, -1, 3, NULL), + (1168, 705, 14447, 16384, 71, 75, -1, -1, 3, NULL), + (1169, 705, 14467, 16384, 72, 76, -1, -1, 1, NULL), + (1170, 705, 14468, 16384, 72, 76, -1, -1, 1, NULL), + (1171, 705, 14469, 16384, 72, 76, -1, -1, 1, NULL), + (1172, 705, 0, 16384, 77, 81, -1, -1, 1, NULL), + (1173, 705, 18552, 16384, 81, 85, -1, -1, 3, NULL), + (1174, 705, 18553, 16384, 81, 85, -1, -1, 3, NULL), + (1175, 705, 18554, 16384, 81, 85, -1, -1, 3, NULL), + (1176, 705, 18573, 16384, 82, 86, -1, -1, 1, NULL), + (1177, 705, 18574, 16384, 82, 86, -1, -1, 1, NULL), + (1178, 705, 18575, 16384, 82, 86, -1, -1, 1, NULL), + (1179, 701, 203, 32768, 1, 21, -1, -1, 2, NULL), + (1180, 701, 213, 32768, 4, 27, -1, -1, 2, NULL), + (1181, 701, 4056, 32768, 8, 22, -1, -1, 2, NULL), + (1182, 701, 95, 32768, 22, 47, -1, -1, 2, NULL), + (1183, 701, 4057, 32768, 23, 37, -1, -1, 2, NULL), + (1184, 701, 96, 32768, 28, 50, -1, -1, 2, NULL), + (1185, 701, 2946, 32768, 38, 53, -1, -1, 2, NULL), + (1186, 701, 97, 32768, 48, 57, -1, -1, 2, NULL), + (1187, 701, 3693, 32768, 51, 83, -1, -1, 3, NULL), + (1188, 701, 2880, 32768, 54, 255, -1, -1, 2, NULL), + (1189, 701, 1525, 32768, 58, 83, -1, -1, 2, NULL), + (1190, 708, 203, 32768, 5, 33, -1, -1, 2, NULL), + (1191, 708, 213, 32768, 11, 55, -1, -1, 2, NULL), + (1192, 708, 4056, 32768, 19, 33, -1, -1, 2, NULL), + (1193, 708, 95, 32768, 34, 61, -1, -1, 2, NULL), + (1194, 708, 4057, 32768, 34, 44, -1, -1, 2, NULL), + (1195, 708, 2946, 32768, 45, 59, -1, -1, 2, NULL), + (1196, 708, 96, 32768, 56, 61, -1, -1, 2, NULL), + (1197, 708, 2880, 32768, 60, 255, -1, -1, 2, NULL), + (1198, 708, 3190, 32768, 62, 66, -1, -1, 2, NULL), + (1199, 708, 5283, 32768, 67, 80, -1, -1, 2, NULL), + (1200, 710, 203, 32768, 13, 60, -1, -1, 2, NULL), + (1201, 710, 213, 32768, 22, 60, -1, -1, 2, NULL), + (1202, 710, 95, 32768, 61, 72, -1, -1, 2, NULL), + (1203, 710, 96, 32768, 61, 72, -1, -1, 2, NULL), + (1204, 709, 213, 32768, 19, 255, -1, -1, 2, NULL), + (1205, 707, 213, 32768, 4, 27, -1, -1, 2, NULL), + (1206, 707, 203, 32768, 5, 27, -1, -1, 2, NULL), + (1207, 707, 95, 32768, 28, 51, -1, -1, 2, NULL), + (1208, 707, 96, 32768, 28, 51, -1, -1, 2, NULL), + (1209, 707, 3693, 32768, 52, 83, -1, -1, 2, NULL), + (1210, 711, 3682, 32768, 45, 85, -1, -1, 2, NULL), + (1211, 711, 3681, 32768, 52, 85, -1, -1, 2, NULL), + (1212, 706, 213, 32768, 1, 21, -1, -1, 2, NULL), + (1213, 706, 203, 32768, 2, 25, -1, -1, 2, NULL), + (1214, 706, 4056, 32768, 9, 23, -1, -1, 2, NULL), + (1215, 706, 96, 32768, 22, 47, -1, -1, 2, NULL), + (1216, 706, 4057, 32768, 24, 37, -1, -1, 2, NULL), + (1217, 706, 95, 32768, 26, 51, -1, -1, 2, NULL), + (1218, 706, 2946, 32768, 38, 53, -1, -1, 2, NULL), + (1219, 706, 98, 32768, 48, 51, -1, -1, 2, NULL), + (1220, 706, 2526, 32768, 52, 84, -1, -1, 2, NULL), + (1221, 706, 3842, 32768, 52, 84, -1, -1, 2, NULL), + (1222, 706, 2880, 32768, 54, 255, -1, -1, 2, NULL), + (1223, 712, 213, 32768, 4, 44, -1, -1, 2, NULL), + (1224, 712, 203, 32768, 13, 60, -1, -1, 2, NULL), + (1225, 712, 96, 32768, 45, 62, -1, -1, 2, NULL), + (1226, 712, 95, 32768, 61, 255, -1, -1, 2, NULL), + (1227, 712, 98, 32768, 63, 255, -1, -1, 2, NULL), + (1228, 701, 14267, 32768, 74, 78, -1, -1, 2, NULL), + (1229, 701, 14268, 32768, 74, 78, -1, -1, 2, NULL), + (1230, 701, 14269, 32768, 74, 78, -1, -1, 2, NULL), + (1231, 701, 18306, 32768, 84, 255, -1, -1, 2, NULL), + (1232, 701, 18307, 32768, 84, 255, -1, -1, 2, NULL), + (1233, 701, 18308, 32768, 84, 255, -1, -1, 2, NULL), + (1234, 701, 18389, 32768, 84, 255, -1, -1, 2, NULL), + (1235, 701, 18390, 32768, 84, 255, -1, -1, 2, NULL), + (1236, 701, 18391, 32768, 84, 255, -1, -1, 2, NULL), + (1237, 708, 19128, 32768, 81, 255, -1, -1, 2, NULL), + (1238, 708, 19129, 32768, 81, 255, -1, -1, 2, NULL), + (1239, 708, 19130, 32768, 81, 255, -1, -1, 2, NULL), + (1240, 710, 14955, 32768, 73, 77, -1, -1, 2, NULL), + (1241, 710, 14956, 32768, 73, 77, -1, -1, 2, NULL), + (1242, 710, 0, 32768, 78, 82, -1, -1, 2, NULL), + (1243, 710, 19146, 32768, 83, 87, -1, -1, 2, NULL), + (1244, 710, 19147, 32768, 83, 87, -1, -1, 2, NULL), + (1245, 710, 19148, 32768, 83, 87, -1, -1, 2, NULL), + (1246, 707, 9700, 32768, 71, 83, -1, -1, 2, NULL), + (1247, 707, 9701, 32768, 71, 83, -1, -1, 2, NULL), + (1248, 707, 9702, 32768, 71, 83, -1, -1, 2, NULL), + (1249, 707, 18389, 32768, 84, 88, -1, -1, 2, NULL), + (1250, 707, 18390, 32768, 84, 88, -1, -1, 2, NULL), + (1251, 707, 18391, 32768, 84, 88, -1, -1, 2, NULL), + (1252, 711, 14027, 32768, 79, 83, -1, -1, 2, NULL), + (1253, 711, 14028, 32768, 79, 83, -1, -1, 2, NULL), + (1254, 711, 14029, 32768, 79, 83, -1, -1, 2, NULL), + (1255, 711, 18021, 32768, 84, 85, -1, -1, 2, NULL), + (1256, 711, 18022, 32768, 84, 85, -1, -1, 2, NULL), + (1257, 711, 18023, 32768, 84, 85, -1, -1, 2, NULL), + (1258, 706, 9700, 32768, 72, 73, -1, -1, 2, NULL), + (1259, 706, 9701, 32768, 72, 73, -1, -1, 2, NULL), + (1260, 706, 9702, 32768, 72, 73, -1, -1, 2, NULL), + (1261, 706, 14387, 32768, 74, 78, -1, -1, 2, NULL), + (1262, 706, 14388, 32768, 74, 78, -1, -1, 2, NULL), + (1263, 706, 14389, 32768, 74, 78, -1, -1, 2, NULL), + (1264, 706, 0, 32768, 79, 83, -1, -1, 2, NULL), + (1265, 706, 18467, 32768, 84, 88, -1, -1, 2, NULL), + (1266, 706, 18468, 32768, 84, 88, -1, -1, 2, NULL), + (1267, 706, 18469, 32768, 84, 88, -1, -1, 2, NULL), + (1268, 706, 19513, 32768, 85, 89, -1, -1, 2, NULL), + (1269, 706, 19514, 32768, 85, 89, -1, -1, 2, NULL), + (1270, 706, 19515, 32768, 85, 89, -1, -1, 2, NULL); +/*!40000 ALTER TABLE `bot_spells_entries` ENABLE KEYS */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; + + -- End of File diff --git a/utils/sql/git/bots/required/2018_02_02_Bot_Spells_Min_Max_HP.sql b/utils/sql/git/bots/required/2018_02_02_Bot_Spells_Min_Max_HP.sql new file mode 100644 index 000000000..95108afac --- /dev/null +++ b/utils/sql/git/bots/required/2018_02_02_Bot_Spells_Min_Max_HP.sql @@ -0,0 +1,2 @@ +ALTER TABLE `bot_spells_entries` ADD `min_hp` SMALLINT(5) DEFAULT '0'; +ALTER TABLE `bot_spells_entries` ADD `max_hp` SMALLINT(5) DEFAULT '0'; diff --git a/utils/sql/git/optional/2018_02_11_GlobalDefiant.sql b/utils/sql/git/optional/2018_02_11_GlobalDefiant.sql new file mode 100644 index 000000000..10c918884 --- /dev/null +++ b/utils/sql/git/optional/2018_02_11_GlobalDefiant.sql @@ -0,0 +1,451 @@ +DELETE FROM lootdrop_entries WHERE item_id IN (50005, 50006, 50007, 50008, 50009, 50010, 50011, 50012, 50013, 50014, 50015, 50016, 50017, 50018, 50019, 50020, 50021, 50022, 50023, 50024, 50025, 50026, 50027, 50028, 50029, 50030, 50031, 50032, 50500, 50501, 50502, 50503, 50504, 50505, 50506, 50507, 50508, 50509, 50510, 50511, 50512, 50513, 50514, 50515, 50516, 50517, 50518); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Crude-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Crude-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50005, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50006, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50007, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50008, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50009, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50010, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50011, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50012, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50013, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50014, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50015, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50016, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50017, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50018, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50019, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50020, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50021, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50022, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50023, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50024, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50025, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50026, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50027, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50028, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50029, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50030, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50031, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50032, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50500, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50501, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50502, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50503, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50504, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50505, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50506, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50507, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50508, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50509, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50510, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50511, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50512, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50513, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50514, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50515, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50516, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50517, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50518, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Crude-Defiant', loottable_id=@loottable_id, max_level=15; + +DELETE FROM lootdrop_entries WHERE item_id IN (50033, 50034, 50035, 50036, 50037, 50038, 50039, 50040, 50041, 50042, 50043, 50044, 50045, 50046, 50047, 50048, 50049, 50050, 50051, 50052, 50053, 50054, 50055, 50056, 50057, 50058, 50059, 50060, 50519, 50520, 50521, 50522, 50523, 50524, 50525, 50526, 50527, 50528, 50529, 50530, 50531, 50532, 50533, 50534, 50535); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Simple-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Simple-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50033, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50034, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50035, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50036, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50037, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50038, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50039, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50040, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50041, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50042, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50043, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50044, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50045, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50046, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50047, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50048, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50049, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50050, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50051, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50052, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50053, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50054, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50055, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50056, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50057, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50058, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50059, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50060, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50519, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50520, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50521, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50522, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50523, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50524, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50525, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50526, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50527, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50528, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50529, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50530, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50531, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50532, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50533, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50534, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50535, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Simple-Defiant', loottable_id=@loottable_id, min_level=14, max_level=25; + +DELETE FROM lootdrop_entries WHERE item_id IN (50061, 50062, 50063, 50064, 50065, 50066, 50067, 50068, 50069, 50070, 50071, 50072, 50073, 50074, 50075, 50076, 50077, 50078, 50079, 50080, 50081, 50082, 50083, 50084, 50085, 50086, 50087, 50088, 50536, 50537, 50540, 50541, 50542, 50543, 50544, 50545, 50546, 50547, 50548, 50549, 50550, 50551, 50552, 50553); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Rough-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Rough-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50061, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50062, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50063, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50064, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50065, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50066, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50067, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50068, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50069, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50070, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50071, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50072, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50073, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50074, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50075, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50076, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50077, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50078, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50079, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50080, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50081, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50082, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50083, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50084, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50085, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50086, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50087, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50088, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50536, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50537, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50540, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50541, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50542, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50543, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50544, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50545, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50546, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50547, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50548, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50549, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50550, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50551, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50552, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50553, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Rough-Defiant', loottable_id=@loottable_id, min_level=24, max_level=36; + +DELETE FROM lootdrop_entries WHERE item_id IN (50089, 50090, 50091, 50092, 50093, 50094, 50095, 50096, 50097, 50098, 50099, 50100, 50101, 50102, 50103, 50104, 50105, 50106, 50107, 50108, 50109, 50110, 50111, 50112, 50113, 50114, 50115, 50116, 50554, 50555, 50556, 50557, 50558, 50559, 50560, 50561, 50562, 50563, 50564, 50565, 50566, 50567, 50568, 50569); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Ornate-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Ornate-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50089, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50090, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50091, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50092, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50093, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50094, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50095, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50096, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50097, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50098, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50099, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50100, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50101, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50102, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50103, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50104, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50105, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50106, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50107, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50108, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50109, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50110, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50111, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50112, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50113, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50114, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50115, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50116, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50554, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50555, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50556, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50557, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50558, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50559, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50560, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50561, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50562, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50563, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50564, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50565, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50566, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50567, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50568, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50569, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Ornate-Defiant', loottable_id=@loottable_id, min_level=35, max_level=47; + +DELETE FROM lootdrop_entries WHERE item_id IN (50117, 50118, 50119, 50120, 50121, 50122, 50123, 50124, 50125, 50126, 50127, 50128, 50129, 50130, 50131, 50132, 50133, 50134, 50135, 50136, 50137, 50138, 50139, 50140, 50141, 50142, 50143, 50144, 50570, 50571, 50572, 50573, 50574, 50575, 50576, 50577, 50578, 50579, 50580, 50581, 50582, 50583, 50584, 50585); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Flawed-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Flawed-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50117, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50118, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50119, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50120, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50121, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50122, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50123, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50124, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50125, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50126, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50127, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50128, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50129, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50130, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50131, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50132, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50133, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50134, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50135, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50136, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50137, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50138, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50139, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50140, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50141, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50142, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50143, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50144, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50570, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50571, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50572, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50573, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50574, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50575, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50576, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50577, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50578, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50579, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50580, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50581, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50582, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50583, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50584, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50585, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Flawed-Defiant', loottable_id=@loottable_id, enabled=0, min_level=44, max_level=55; + +DELETE FROM lootdrop_entries WHERE item_id IN (50145, 50146, 50147, 50148, 50149, 50150, 50151, 50152, 50153, 50154, 50155, 50156, 50157, 50158, 50159, 50160, 50161, 50162, 50163, 50164, 50165, 50166, 50167, 50168, 50169, 50170, 50171, 50172, 50173, 50174, 50175, 50176, 50177, 50178, 50586, 50587, 50588, 50589, 50590, 50591, 50592, 50593, 50594, 50595, 50596, 50597, 50598, 50599, 50600, 50601); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Intricate-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Intricate-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50145, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50146, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50147, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50148, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50149, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50150, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50151, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50152, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50153, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50154, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50155, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50156, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50157, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50158, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50159, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50160, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50161, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50162, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50163, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50164, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50165, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50166, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50167, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50168, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50169, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50170, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50171, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50172, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50173, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50174, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50175, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50176, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50177, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50178, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50586, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50587, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50588, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50589, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50590, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50591, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50592, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50593, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50594, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50595, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50596, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50597, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50598, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50599, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50600, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50601, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Intricate-Defiant', loottable_id=@loottable_id, enabled=0, min_level=54, max_level=65; + +DELETE FROM lootdrop_entries WHERE item_id IN (50179, 50180, 50181, 50182, 50183, 50184, 50185, 50186, 50187, 50188, 50189, 50190, 50191, 50192, 50193, 50194, 50195, 50196, 50197, 50198, 50199, 50200, 50201, 50202, 50203, 50204, 50205, 50206, 50207, 50208, 50209, 50210, 50211, 50212, 50602, 50603, 50604, 50605, 50606, 50607, 50608, 50609, 50610, 50611, 50612, 50613, 50614, 50615, 50616); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Elaborate-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Elaborate-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50179, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50180, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50181, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50182, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50183, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50184, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50185, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50186, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50187, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50188, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50189, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50190, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50191, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50192, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50193, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50194, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50195, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50196, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50197, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50198, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50199, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50200, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50201, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50202, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50203, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50204, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50205, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50206, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50207, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50208, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50209, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50210, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50211, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50212, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50602, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50603, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50604, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50605, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50606, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50607, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50608, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50609, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50610, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50611, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50612, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50613, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50614, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50615, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50616, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Elaborate-Defiant', loottable_id=@loottable_id, enabled=0, min_level=64, max_level=75; + +DELETE FROM lootdrop_entries WHERE item_id IN (50213, 50214, 50215, 50216, 50217, 50218, 50219, 50220, 50221, 50222, 50223, 50224, 50225, 50226, 50227, 50228, 50229, 50230, 50231, 50232, 50233, 50234, 50235, 50236, 50237, 50238, 50239, 50240, 50241, 50242, 50243, 50244, 50245, 50246, 50617, 50618, 50619, 50620, 50621, 50622, 50623, 50624, 50625, 50626, 50627, 50628, 50629, 50630, 50631); + +SELECT @loottable_id := MAX(id) + 1 FROM loottable; +INSERT INTO loottable SET id=@loottable_id, name="GLB-Elegant-Defiant", mincash="0", maxcash="0", avgcoin="0"; +SELECT @lootdrop_id := MAX(id) + 1 FROM lootdrop; +INSERT INTO lootdrop SET id=@lootdrop_id, name="GLB-Elegant-Defiant-Drop"; +INSERT INTO loottable_entries SET loottable_id=@loottable_id, lootdrop_id=@lootdrop_id, droplimit='0', mindrop='1', multiplier='1', probability='2'; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50213, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50214, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50215, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50216, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50217, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50218, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50219, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50220, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50221, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50222, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50223, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50224, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50225, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50226, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50227, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50228, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50229, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50230, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50231, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50232, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50233, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50234, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50235, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50236, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50237, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50238, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50239, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50240, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50241, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50242, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50243, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50244, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50245, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50246, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50617, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50618, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50619, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50620, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50621, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50622, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50623, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50624, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50625, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50626, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50627, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50628, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50629, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50630, equip_item=1, item_charges=1, multiplier=1, chance=1; +INSERT INTO lootdrop_entries SET lootdrop_id=@lootdrop_id, item_id=50631, equip_item=1, item_charges=1, multiplier=1, chance=1; + +INSERT INTO global_loot SET description='GLB-Elegant-Defiant', loottable_id=@loottable_id, enabled=0, min_level=74, max_level=86; diff --git a/utils/sql/git/required/2017_12_16_GroundSpawn_Respawn_Timer.sql b/utils/sql/git/required/2017_12_16_GroundSpawn_Respawn_Timer.sql new file mode 100644 index 000000000..f7c8b6a31 --- /dev/null +++ b/utils/sql/git/required/2017_12_16_GroundSpawn_Respawn_Timer.sql @@ -0,0 +1,2 @@ +ALTER TABLE `ground_spawns` MODIFY `respawn_timer` int(11) unsigned NOT NULL default 300; +UPDATE `ground_spawns` SET `respawn_timer` = `respawn_timer` / 1000; diff --git a/utils/sql/git/required/2018_02_01_NPC_Spells_Min_Max_HP.sql b/utils/sql/git/required/2018_02_01_NPC_Spells_Min_Max_HP.sql new file mode 100644 index 000000000..b0535e25f --- /dev/null +++ b/utils/sql/git/required/2018_02_01_NPC_Spells_Min_Max_HP.sql @@ -0,0 +1,2 @@ +ALTER TABLE `npc_spells_entries` ADD `min_hp` SMALLINT(5) DEFAULT '0'; +ALTER TABLE `npc_spells_entries` ADD `max_hp` SMALLINT(5) DEFAULT '0'; diff --git a/utils/sql/git/required/2018_02_04_Charm_Stats.sql b/utils/sql/git/required/2018_02_04_Charm_Stats.sql new file mode 100644 index 000000000..3a9164f40 --- /dev/null +++ b/utils/sql/git/required/2018_02_04_Charm_Stats.sql @@ -0,0 +1,7 @@ +ALTER TABLE `npc_types` ADD `charm_ac` SMALLINT(5) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_min_dmg` INT(10) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_max_dmg` INT(10) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_attack_delay` TINYINT(3) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_accuracy_rating` MEDIUMINT(9) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_avoidance_rating` MEDIUMINT(9) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_atk` MEDIUMINT(9) DEFAULT '0'; diff --git a/utils/sql/git/required/2018_02_10_GlobalLoot.sql b/utils/sql/git/required/2018_02_10_GlobalLoot.sql new file mode 100644 index 000000000..573ab8f71 --- /dev/null +++ b/utils/sql/git/required/2018_02_10_GlobalLoot.sql @@ -0,0 +1,19 @@ +ALTER TABLE `npc_types` ADD `skip_global_loot` TINYINT DEFAULT '0'; +ALTER TABLE `npc_types` ADD `rare_spawn` TINYINT DEFAULT '0'; + +CREATE TABLE global_loot ( + id INT NOT NULL AUTO_INCREMENT, + description varchar(255), + loottable_id INT NOT NULL, + enabled TINYINT NOT NULL DEFAULT 1, + min_level INT NOT NULL DEFAULT 0, + max_level INT NOT NULL DEFAULT 0, + rare TINYINT NULL, + raid TINYINT NULL, + race MEDIUMTEXT NULL, + class MEDIUMTEXT NULL, + bodytype MEDIUMTEXT NULL, + zone MEDIUMTEXT NULL, + PRIMARY KEY (id) +); + diff --git a/utils/sql/git/required/2018_02_13_Heading.sql b/utils/sql/git/required/2018_02_13_Heading.sql new file mode 100644 index 000000000..e7869b575 --- /dev/null +++ b/utils/sql/git/required/2018_02_13_Heading.sql @@ -0,0 +1,3 @@ +UPDATE spawn2 SET heading = heading * 8.0 / 4.0; +UPDATE grid_entries SET heading = heading * 8.0 / 4.0 WHERE heading <> -1; +INSERT INTO variables (varname, value, information) VALUES ('fixed_heading', 1, 'manifest heading fix hack'); -- hack diff --git a/utils/sql/git/required/2018_02_18_bug_reports.sql b/utils/sql/git/required/2018_02_18_bug_reports.sql new file mode 100644 index 000000000..92afbd7c9 --- /dev/null +++ b/utils/sql/git/required/2018_02_18_bug_reports.sql @@ -0,0 +1,44 @@ +CREATE TABLE `bug_reports` ( + `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `zone` VARCHAR(32) NOT NULL DEFAULT 'Unknown', + `client_version_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `client_version_name` VARCHAR(24) NOT NULL DEFAULT 'Unknown', + `account_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `character_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `character_name` VARCHAR(64) NOT NULL DEFAULT 'Unknown', + `reporter_spoof` TINYINT(1) NOT NULL DEFAULT '1', + `category_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `category_name` VARCHAR(64) NOT NULL DEFAULT 'Other', + `reporter_name` VARCHAR(64) NOT NULL DEFAULT 'Unknown', + `ui_path` VARCHAR(128) NOT NULL DEFAULT 'Unknown', + `pos_x` FLOAT NOT NULL DEFAULT '0', + `pos_y` FLOAT NOT NULL DEFAULT '0', + `pos_z` FLOAT NOT NULL DEFAULT '0', + `heading` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `time_played` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `target_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `target_name` VARCHAR(64) NOT NULL DEFAULT 'Unknown', + `optional_info_mask` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `_can_duplicate` TINYINT(1) NOT NULL DEFAULT '0', + `_crash_bug` TINYINT(1) NOT NULL DEFAULT '0', + `_target_info` TINYINT(1) NOT NULL DEFAULT '0', + `_character_flags` TINYINT(1) NOT NULL DEFAULT '0', + `_unknown_value` TINYINT(1) NOT NULL DEFAULT '0', + `bug_report` VARCHAR(1024) NOT NULL DEFAULT '', + `system_info` VARCHAR(1024) NOT NULL DEFAULT '', + `report_datetime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `bug_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `last_review` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `last_reviewer` VARCHAR(64) NOT NULL DEFAULT 'None', + `reviewer_notes` VARCHAR(1024) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE INDEX `id` (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; + +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES +(1, 'Bugs:ReportingSystemActive', 'true', 'Activates bug reporting'), +(1, 'Bugs:UseOldReportingMethod', 'true', 'Forces the use of the old bug reporting system'), +(1, 'Bugs:DumpTargetEntity', 'false', 'Dumps the target entity, if one is provided'); diff --git a/utils/sql/git/required/2018_03_07_ucs_command.sql b/utils/sql/git/required/2018_03_07_ucs_command.sql new file mode 100644 index 000000000..fdad0dda1 --- /dev/null +++ b/utils/sql/git/required/2018_03_07_ucs_command.sql @@ -0,0 +1 @@ +INSERT INTO `command_settings` VALUES ('ucs', '0', ''); diff --git a/utils/sql/user_tables.txt b/utils/sql/user_tables.txt index 9e35ac5e2..a210aa381 100644 --- a/utils/sql/user_tables.txt +++ b/utils/sql/user_tables.txt @@ -17,7 +17,6 @@ character_bind character_corpses character_corpse_items character_languages -character_lookup character_skills character_spells character_memmed_spells @@ -89,4 +88,4 @@ spell_globals timers trader trader_audit -zone_flags \ No newline at end of file +zone_flags diff --git a/utils/xmltojson/.gitignore b/utils/xmltojson/.gitignore new file mode 100644 index 000000000..2f08e63ef --- /dev/null +++ b/utils/xmltojson/.gitignore @@ -0,0 +1,2 @@ +eqemu_config.xml +eqemu_config.json \ No newline at end of file diff --git a/utils/xmltojson/README.md b/utils/xmltojson/README.md new file mode 100644 index 000000000..a8fec4a3a --- /dev/null +++ b/utils/xmltojson/README.md @@ -0,0 +1 @@ +Converts the old eqemu_config.xml to eqemu_config.json diff --git a/utils/xmltojson/build.bat b/utils/xmltojson/build.bat new file mode 100644 index 000000000..be0e60488 --- /dev/null +++ b/utils/xmltojson/build.bat @@ -0,0 +1,21 @@ +@echo off +setlocal +set name="xmltojson" + +echo Building Linux +set GOOS=linux +set GOARCH=amd64 +go build -o %name%-linux-x64 main.go +set GOARCH=386 +go build -o %name%-linux-x86 main.go +echo Building Windows +set GOOS=windows +set GOARCH=amd64 +go build -o %name%-windows-x64.exe main.go +set GOARCH=386 +go build -o %name%-windows-x86.exe main.go +echo Building OSX +REM set GOOS=darwin +REM set GOARCH=amd64 +REM go build -o %name%-osx-x64 main.go +endlocal \ No newline at end of file diff --git a/utils/xmltojson/build.sh b/utils/xmltojson/build.sh new file mode 100644 index 000000000..079822f14 --- /dev/null +++ b/utils/xmltojson/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e +export NAME="xmltojson" +echo Building Linux +GOOS=linux GOARCH=amd64 go build -o $NAME-linux-x64 main.go +GOOS=linux GOARCH=386 go build -o $NAME-linux-x86 main.go +echo Building Windows +GOOS=windows GOARCH=amd64 go build -o $NAME-windows-x64.exe main.go +GOOS=windows GOARCH=386 go build -o $NAME-windows-x86.exe main.go +#echo Building OSX +#GOOS=darwin GOARCH=amd64 go build -o $NAME-osx-x64 main.go \ No newline at end of file diff --git a/utils/xmltojson/main.go b/utils/xmltojson/main.go new file mode 100644 index 000000000..867cb0c79 --- /dev/null +++ b/utils/xmltojson/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "strings" + + xj "github.com/basgys/goxml2json" +) + +func main() { + var err error + var data []byte + var sData string + buf := &bytes.Buffer{} + var buf2 bytes.Buffer + + if data, err = ioutil.ReadFile("eqemu_config.xml"); err != nil { + fmt.Println("Failed to open eqemu_config.xml:", err.Error()) + os.Exit(1) + } + + //detect malformed xml in eqemuconfig + sData = strings.Replace(string(data), "", "", 1) + r := strings.NewReader(sData) + dec := xj.NewDecoder(r) + root := &xj.Node{} + if err = dec.DecodeWithCustomPrefixes(root, "", ""); err != nil { + fmt.Println("Failed to decode eqemu_config.xml:", err.Error()) + os.Exit(1) + } + + if root.Children["server"] == nil || len(root.Children["server"]) < 1 { + fmt.Println("Server element not found") + os.Exit(1) + } + server := root.Children["server"][0] + + //locked: "true" is only way to trigger locked + if server.Children["world"] != nil && len(server.Children["world"]) > 0 { + world := server.Children["world"][0] + + if world.Children["locked"] != nil && len(world.Children["locked"]) > 0 { + fmt.Println("Locked!") + world.Children["locked"][0].Data = "true" + } + } + + elements := []string{ + "chatserver", + "directories", + "files", + "launcher", + "mailserver", + "webinterface", + "world", + "zones", + } + for _, ele := range elements { + if server.Children[ele] != nil && len(server.Children[ele]) > 0 && len(server.Children[ele][0].Children) == 0 { + delete(server.Children, ele) + } + } + + enc := xj.NewEncoder(buf) + err = enc.EncodeWithCustomPrefixes(root, "", "") + if err != nil { + fmt.Println("Failed to encode eqemu_config.xml:", err.Error()) + os.Exit(1) + } + + //prettyprint + if err = json.Indent(&buf2, buf.Bytes(), "", "\t"); err != nil { + fmt.Println("Failed to encode json:", err.Error()) + os.Exit(1) + } + + if err = ioutil.WriteFile("eqemu_config.json", buf2.Bytes(), 0744); err != nil { + fmt.Println("Failed to write eqemu_config.json:", err.Error()) + os.Exit(1) + } +} diff --git a/utils/xmltojson/xmltojson-linux-x64 b/utils/xmltojson/xmltojson-linux-x64 new file mode 100644 index 000000000..ea6e3dc25 Binary files /dev/null and b/utils/xmltojson/xmltojson-linux-x64 differ diff --git a/utils/xmltojson/xmltojson-linux-x86 b/utils/xmltojson/xmltojson-linux-x86 new file mode 100644 index 000000000..b94fcae51 Binary files /dev/null and b/utils/xmltojson/xmltojson-linux-x86 differ diff --git a/utils/xmltojson/xmltojson-windows-x64 b/utils/xmltojson/xmltojson-windows-x64 new file mode 100644 index 000000000..9c598dcff Binary files /dev/null and b/utils/xmltojson/xmltojson-windows-x64 differ diff --git a/utils/xmltojson/xmltojson-windows-x64.exe b/utils/xmltojson/xmltojson-windows-x64.exe new file mode 100644 index 000000000..520920988 Binary files /dev/null and b/utils/xmltojson/xmltojson-windows-x64.exe differ diff --git a/utils/xmltojson/xmltojson-windows-x86 b/utils/xmltojson/xmltojson-windows-x86 new file mode 100644 index 000000000..f25ae2a3c Binary files /dev/null and b/utils/xmltojson/xmltojson-windows-x86 differ diff --git a/utils/xmltojson/xmltojson-windows-x86.exe b/utils/xmltojson/xmltojson-windows-x86.exe new file mode 100644 index 000000000..53ff5f194 Binary files /dev/null and b/utils/xmltojson/xmltojson-windows-x86.exe differ diff --git a/world/client.cpp b/world/client.cpp index aaf7d4c9c..d3b74ae3f 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -84,6 +84,7 @@ extern ClientList client_list; extern EQEmu::Random emu_random; extern uint32 numclients; extern volatile bool RunLoops; +extern volatile bool UCSServerAvailable_; Client::Client(EQStreamInterface* ieqs) : autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)), @@ -890,53 +891,84 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { } QueuePacket(outapp); safe_delete(outapp); - + + // set mailkey - used for duration of character session int MailKey = emu_random.Int(1, INT_MAX); database.SetMailKey(charid, GetIP(), MailKey); + if (UCSServerAvailable_) { + const WorldConfig *Config = WorldConfig::get(); + std::string buffer; - char ConnectionType; + EQEmu::versions::UCSVersion ConnectionType = EQEmu::versions::ucsUnknown; - if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) - ConnectionType = 'U'; - else if (m_ClientVersionBit & EQEmu::versions::bit_SoFAndLater) - ConnectionType = 'S'; - else - ConnectionType = 'C'; + // chat server packet + switch (GetClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + ConnectionType = EQEmu::versions::ucsTitaniumChat; + break; + case EQEmu::versions::ClientVersion::SoF: + ConnectionType = EQEmu::versions::ucsSoFCombined; + break; + case EQEmu::versions::ClientVersion::SoD: + ConnectionType = EQEmu::versions::ucsSoDCombined; + break; + case EQEmu::versions::ClientVersion::UF: + ConnectionType = EQEmu::versions::ucsUFCombined; + break; + case EQEmu::versions::ClientVersion::RoF: + ConnectionType = EQEmu::versions::ucsRoFCombined; + break; + case EQEmu::versions::ClientVersion::RoF2: + ConnectionType = EQEmu::versions::ucsRoF2Combined; + break; + default: + ConnectionType = EQEmu::versions::ucsUnknown; + break; + } - auto outapp2 = new EQApplicationPacket(OP_SetChatServer); - char buffer[112]; + buffer = StringFormat("%s,%i,%s.%s,%c%08X", + Config->ChatHost.c_str(), + Config->ChatPort, + Config->ShortName.c_str(), + GetCharName(), + ConnectionType, + MailKey + ); - const WorldConfig *Config = WorldConfig::get(); + outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; - sprintf(buffer,"%s,%i,%s.%s,%c%08X", - Config->ChatHost.c_str(), - Config->ChatPort, - Config->ShortName.c_str(), - this->GetCharName(), ConnectionType, MailKey - ); - outapp2->size=strlen(buffer)+1; - outapp2->pBuffer = new uchar[outapp2->size]; - memcpy(outapp2->pBuffer,buffer,outapp2->size); - QueuePacket(outapp2); - safe_delete(outapp2); + QueuePacket(outapp); + safe_delete(outapp); - outapp2 = new EQApplicationPacket(OP_SetChatServer2); + // mail server packet + switch (GetClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + ConnectionType = EQEmu::versions::ucsTitaniumMail; + break; + default: + // retain value from previous switch + break; + } - if (m_ClientVersionBit & EQEmu::versions::bit_TitaniumAndEarlier) - ConnectionType = 'M'; + buffer = StringFormat("%s,%i,%s.%s,%c%08X", + Config->MailHost.c_str(), + Config->MailPort, + Config->ShortName.c_str(), + GetCharName(), + ConnectionType, + MailKey + ); - sprintf(buffer,"%s,%i,%s.%s,%c%08X", - Config->MailHost.c_str(), - Config->MailPort, - Config->ShortName.c_str(), - this->GetCharName(), ConnectionType, MailKey - ); - outapp2->size=strlen(buffer)+1; - outapp2->pBuffer = new uchar[outapp2->size]; - memcpy(outapp2->pBuffer,buffer,outapp2->size); - QueuePacket(outapp2); - safe_delete(outapp2); + outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; + + QueuePacket(outapp); + safe_delete(outapp); + } EnterWorld(); diff --git a/world/client.h b/world/client.h index 88dc27c57..d36dc692d 100644 --- a/world/client.h +++ b/world/client.h @@ -68,6 +68,7 @@ public: inline const char* GetLSKey() { if (cle) { return cle->GetLSKey(); } return "NOKEY"; } inline uint32 GetCharID() { return charid; } inline const char* GetCharName() { return char_name; } + inline EQEmu::versions::ClientVersion GetClientVersion() { return m_ClientVersion; } inline ClientListEntry* GetCLE() { return cle; } inline void SetCLE(ClientListEntry* iCLE) { cle = iCLE; } private: diff --git a/world/net.cpp b/world/net.cpp index b6e7babcc..c9a3f134c 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -104,6 +104,7 @@ EQEmuLogSys LogSys; WebInterfaceList web_interface; void CatchSignal(int sig_num); +void CheckForServerScript(bool force_download = false); inline void UpdateWindowTitle(std::string new_title) { #ifdef _WINDOWS @@ -116,6 +117,17 @@ int main(int argc, char** argv) { LogSys.LoadLogSettingsDefaults(); set_exception_handler(); + /* If eqemu_config.json does not exist - create it from conversion... */ + if (!std::ifstream("eqemu_config.json")) { + CheckForServerScript(true); + /* Run EQEmu Server script (Checks for database updates) */ + system("perl eqemu_server.pl convert_xml"); + } + else { + /* Download EQEmu Server Maintenance Script if doesn't exist */ + CheckForServerScript(); + } + /* Database Version Check */ uint32 Database_Version = CURRENT_BINARY_DATABASE_VERSION; uint32 Bots_Database_Version = CURRENT_BINARY_BOTS_DATABASE_VERSION; @@ -173,7 +185,7 @@ int main(int argc, char** argv) { } } - Log(Logs::General, Logs::World_Server, "Connecting to MySQL..."); + Log(Logs::General, Logs::World_Server, "Connecting to MySQL %s@%s:%i...", Config->DatabaseUsername.c_str(), Config->DatabaseHost.c_str(), Config->DatabasePort); if (!database.Connect( Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(), @@ -450,6 +462,8 @@ int main(int argc, char** argv) { connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID()); UCSLink.SetConnection(connection); + + zoneserver_list.UpdateUCSServerAvailable(); }); server_connection->OnConnectionRemoved("UCS", [](std::shared_ptr connection) { @@ -457,6 +471,8 @@ int main(int argc, char** argv) { connection->GetUUID()); UCSLink.SetConnection(nullptr); + + zoneserver_list.UpdateUCSServerAvailable(false); }); server_connection->OnConnectionIdentified("WebInterface", [](std::shared_ptr connection) { @@ -572,4 +588,33 @@ int main(int argc, char** argv) { void CatchSignal(int sig_num) { Log(Logs::General, Logs::World_Server, "Caught signal %d", sig_num); RunLoops = false; +} + +void UpdateWindowTitle(char* iNewTitle) { +#ifdef _WINDOWS + char tmp[500]; + if (iNewTitle) { + snprintf(tmp, sizeof(tmp), "World: %s", iNewTitle); + } + else { + snprintf(tmp, sizeof(tmp), "World"); + } + SetConsoleTitle(tmp); +#endif +} + +void CheckForServerScript(bool force_download) { + /* Fetch EQEmu Server script */ + if (!std::ifstream("eqemu_server.pl") || force_download) { + + if(force_download) + std::remove("eqemu_server.pl"); /* Delete local before fetch */ + + std::cout << "Pulling down EQEmu Server Maintenance Script (eqemu_server.pl)..." << std::endl; +#ifdef _WIN32 + system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl'); if ($response->is_success){ open(FILE, '> eqemu_server.pl'); print FILE $response->decoded_content; close(FILE); }\""); +#else + system("wget -N --no-check-certificate --quiet -O eqemu_server.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl"); +#endif + } } \ No newline at end of file diff --git a/world/world_config.h b/world/world_config.h index 4689aa08f..2a274ed29 100644 --- a/world/world_config.h +++ b/world/world_config.h @@ -52,7 +52,7 @@ public: _world_config=new WorldConfig; _config=_world_config; - return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server"); + return _config->parseFile(); } // Accessors for the static private object diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 0b118ff2e..cbf901cf7 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -516,23 +516,6 @@ void WorldDatabase::GetLauncherList(std::vector &rl) { } -void WorldDatabase::SetMailKey(int CharID, int IPAddress, int MailKey) -{ - char MailKeyString[17]; - - if(RuleB(Chat, EnableMailKeyIPVerification) == true) - sprintf(MailKeyString, "%08X%08X", IPAddress, MailKey); - else - sprintf(MailKeyString, "%08X", MailKey); - - std::string query = StringFormat("UPDATE character_data SET mailkey = '%s' WHERE id = '%i'", - MailKeyString, CharID); - auto results = QueryDatabase(query); - if (!results.Success()) - Log(Logs::General, Logs::Error, "WorldDatabase::SetMailKey(%i, %s) : %s", CharID, MailKeyString, results.ErrorMessage().c_str()); - -} - bool WorldDatabase::GetCharacterLevel(const char *name, int &level) { std::string query = StringFormat("SELECT level FROM character_data WHERE name = '%s'", name); diff --git a/world/worlddb.h b/world/worlddb.h index b0c2ff221..2afd69920 100644 --- a/world/worlddb.h +++ b/world/worlddb.h @@ -34,7 +34,6 @@ public: int MoveCharacterToBind(int CharID, uint8 bindnum = 0); void GetLauncherList(std::vector &result); - void SetMailKey(int CharID, int IPAddress, int MailKey); bool GetCharacterLevel(const char *name, int &level); bool LoadCharacterCreateAllocations(); diff --git a/world/zonelist.cpp b/world/zonelist.cpp index a1f0a60ff..d86f727f6 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -32,6 +32,7 @@ extern uint32 numzones; extern bool holdzones; extern EQEmu::Random emu_random; extern WebInterfaceList web_interface; +volatile bool UCSServerAvailable_ = false; void CatchSignal(int sig_num); ZSList::ZSList() @@ -669,6 +670,16 @@ void ZSList::GetZoneIDList(std::vector &zones) { } } +void ZSList::UpdateUCSServerAvailable(bool ucss_available) { + UCSServerAvailable_ = ucss_available; + auto outapp = new ServerPacket(ServerOP_UCSServerStatusReply, sizeof(UCSServerStatus_Struct)); + auto ucsss = (UCSServerStatus_Struct*)outapp->pBuffer; + ucsss->available = (ucss_available ? 1 : 0); + ucsss->timestamp = Timer::GetCurrentTime(); + SendPacket(outapp); + safe_delete(outapp); +} + void ZSList::WorldShutDown(uint32 time, uint32 interval) { if (time > 0) { diff --git a/world/zonelist.h b/world/zonelist.h index e152e5046..9911b87e0 100644 --- a/world/zonelist.h +++ b/world/zonelist.h @@ -54,7 +54,8 @@ public: Timer* reminder; void NextGroupIDs(uint32 &start, uint32 &end); void SendLSZones(); - uint16 GetAvailableZonePort(); + uint16 GetAvailableZonePort(); + void UpdateUCSServerAvailable(bool ucss_available = true); int GetZoneCount(); void GetZoneIDList(std::vector &zones); diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 4de771701..e685b280e 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -41,6 +41,7 @@ extern GroupLFPList LFPGroupList; extern ZSList zoneserver_list; extern LoginServerList loginserverlist; extern volatile bool RunLoops; +extern volatile bool UCSServerAvailable_; extern AdventureManager adventure_manager; extern UCSConnection UCSLink; extern QueryServConnection QSLink; @@ -1267,6 +1268,24 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { UCSLink.SendPacket(pack); break; } + + case ServerOP_UCSServerStatusRequest: + { + auto ucsss = (UCSServerStatus_Struct*)pack->pBuffer; + auto zs = zoneserver_list.FindByPort(ucsss->port); + if (!zs) + break; + + auto outapp = new ServerPacket(ServerOP_UCSServerStatusReply, sizeof(UCSServerStatus_Struct)); + ucsss = (UCSServerStatus_Struct*)outapp->pBuffer; + ucsss->available = (UCSServerAvailable_ ? 1 : 0); + ucsss->timestamp = Timer::GetCurrentTime(); + zs->SendPacket(outapp); + safe_delete(outapp); + + break; + } + case ServerOP_QSSendQuery: case ServerOP_QueryServGeneric: case ServerOP_Speech: diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 0171c8eb9..b10ab32a0 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -28,6 +28,7 @@ SET(zone_sources encounter.cpp entity.cpp exp.cpp + fastmath.cpp fearpath.cpp forage.cpp groups.cpp @@ -68,6 +69,7 @@ SET(zone_sources exp.cpp fearpath.cpp forage.cpp + global_loot_manager.cpp groups.cpp guild.cpp guild_mgr.cpp @@ -157,7 +159,9 @@ SET(zone_headers entity.h errmsg.h event_codes.h + fastmath.h forage.h + global_loot_manager.h groups.h guild_mgr.h hate_list.h diff --git a/zone/aa.cpp b/zone/aa.cpp index 31ad9c162..38d477fb8 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -424,6 +424,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) npca->GetSwarmInfo()->duration->Start(duration*1000); } + npca->StartSwarmTimer(duration * 1000); npca->GetSwarmInfo()->owner_id = GetID(); //give the pet somebody to "love" diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 340493578..d73b96f6f 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -253,7 +253,7 @@ bool Mob::CheckWillAggro(Mob *mob) { //sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM //they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting if (mob->IsClient()) { - if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->zoning) + if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning) return false; } @@ -1007,6 +1007,28 @@ bool Mob::CheckLosFN(float posX, float posY, float posZ, float mobSize) { return zone->zonemap->CheckLoS(myloc, oloc); } +bool Mob::CheckLosFN(glm::vec3 posWatcher, float sizeWatcher, glm::vec3 posTarget, float sizeTarget) { + if (zone->zonemap == nullptr) { + //not sure what the best return is on error + //should make this a database variable, but im lazy today +#ifdef LOS_DEFAULT_CAN_SEE + return(true); +#else + return(false); +#endif + } + +#define LOS_DEFAULT_HEIGHT 6.0f + + posWatcher.z += (sizeWatcher == 0.0f ? LOS_DEFAULT_HEIGHT : sizeWatcher) / 2 * HEAD_POSITION; + posTarget.z += (sizeTarget == 0.0f ? LOS_DEFAULT_HEIGHT : sizeTarget) / 2 * SEE_POSITION; + +#if LOSDEBUG>=5 + Log(Logs::General, Logs::None, "LOS from (%.2f, %.2f, %.2f) to (%.2f, %.2f, %.2f) sizes: (%.2f, %.2f) [static]", posWatcher.x, posWatcher.y, posWatcher.z, posTarget.x, posTarget.y, posTarget.z, sizeWatcher, sizeTarget); +#endif + return zone->zonemap->CheckLoS(posWatcher, posTarget); +} + //offensive spell aggro int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc) { diff --git a/zone/attack.cpp b/zone/attack.cpp index d12d8d36c..26121134e 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "worldserver.h" #include "zone.h" #include "lua_parser.h" +#include "fastmath.h" #include #include @@ -43,6 +44,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA extern QueryServ* QServ; extern WorldServer worldserver; +extern FastMath g_Math; #ifdef _WINDOWS #define snprintf _snprintf @@ -358,7 +360,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit) Mob *attacker = other; Mob *defender = this; - bool InFront = attacker->InFrontMob(this, attacker->GetX(), attacker->GetY()); + bool InFront = !attacker->BehindMob(this, attacker->GetX(), attacker->GetY()); /* This special ability adds a negative modifer to the defenders riposte/block/parry/chance @@ -852,16 +854,56 @@ int Mob::ACSum() return ac; } +int Mob::GetBestMeleeSkill() + { + int bestSkill=0; + EQEmu::skills::SkillType meleeSkills[]= + { EQEmu::skills::Skill1HBlunt, + EQEmu::skills::Skill1HSlashing, + EQEmu::skills::Skill2HBlunt, + EQEmu::skills::Skill2HSlashing, + EQEmu::skills::SkillHandtoHand, + EQEmu::skills::Skill1HPiercing, + EQEmu::skills::Skill2HPiercing, + EQEmu::skills::SkillCount + }; + int i; + + for (i=0; meleeSkills[i] != EQEmu::skills::SkillCount; ++i) { + int value; + value = GetSkill(meleeSkills[i]); + bestSkill = std::max(value, bestSkill); + } + + return bestSkill; + } + int Mob::offense(EQEmu::skills::SkillType skill) { int offense = GetSkill(skill); - int stat_bonus = 0; - if (skill == EQEmu::skills::SkillArchery || skill == EQEmu::skills::SkillThrowing) - stat_bonus = GetDEX(); - else - stat_bonus = GetSTR(); + int stat_bonus = GetSTR(); + + switch (skill) { + case EQEmu::skills::SkillArchery: + case EQEmu::skills::SkillThrowing: + stat_bonus = GetDEX(); + break; + + // Mobs with no weapons default to H2H. + // Since H2H is capped at 100 for many many classes, + // lets not handicap mobs based on not spawning with a + // weapon. + // + // Maybe we tweak this if Disarm is actually implemented. + + case EQEmu::skills::SkillHandtoHand: + offense = GetBestMeleeSkill(); + break; + } + if (stat_bonus >= 75) offense += (2 * stat_bonus - 150) / 3; + offense += GetATK(); return offense; } @@ -1688,6 +1730,15 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk if (!RuleB(Character, UseDeathExpLossMult)) { exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000); } + + if (RuleB(Zone, LevelBasedEXPMods)) { + // Death in levels with xp_mod (such as hell levels) was resulting + // in losing more that appropriate since the loss was the same but + // getting it back would take way longer. This makes the death the + // same amount of time to recover. Will also lose more if level is + // granting a bonus. + exploss *= zone->level_exp_mod[GetLevel()].ExpMod; + } if ((GetLevel() < RuleI(Character, DeathExpLossLevel)) || (GetLevel() > RuleI(Character, DeathExpLossMaxLevel)) || IsBecomeNPC()) { @@ -2635,7 +2686,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic); - if (other->IsClient() && !on_hatelist) + if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other->CastToClient())) other->CastToClient()->AddAutoXTarget(this); #ifdef BOTS @@ -2676,9 +2727,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b // owner must get on list, but he's not actually gained any hate yet if (!owner->GetSpecialAbility(IMMUNE_AGGRO)) { - hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic); if (owner->IsClient() && !CheckAggro(owner)) owner->CastToClient()->AddAutoXTarget(this); + hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic); } } } @@ -3314,6 +3365,12 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const damage = DMG_INVULNERABLE; } + // this should actually happen MUCH sooner, need to investigate though -- good enough for now + if ((skill_used == EQEmu::skills::SkillArchery || skill_used == EQEmu::skills::SkillThrowing) && GetSpecialAbility(IMMUNE_RANGED_ATTACKS)) { + Log(Logs::Detail, Logs::Combat, "Avoiding %d damage due to IMMUNE_RANGED_ATTACKS.", damage); + damage = DMG_INVULNERABLE; + } + if (spell_id != SPELL_UNKNOWN || attacker == nullptr) avoidable = false; @@ -3556,26 +3613,21 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const a->special = 2; else a->special = 0; - a->meleepush_xy = attacker ? attacker->GetHeading() * 2.0f : 0.0f; + a->hit_heading = attacker ? attacker->GetHeading() : 0.0f; if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() && (IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) { a->force = EQEmu::skills::GetSkillMeleePushForce(skill_used); - // update NPC stuff - auto new_pos = glm::vec3(m_Position.x + (a->force * std::sin(a->meleepush_xy) + m_Delta.x), - m_Position.y + (a->force * std::cos(a->meleepush_xy) + m_Delta.y), m_Position.z); - if (zone->zonemap && zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable. - if (IsNPC()) { - // Is this adequate? - - Teleport(new_pos); - if (position_update_melee_push_timer.Check()) { - SendPositionUpdate(); - } + if (IsNPC()) { + if (attacker->IsNPC()) + a->force = 0.0f; // 2013 change that disabled NPC vs NPC push + else + a->force *= 0.10f; // force against NPCs is divided by 10 I guess? ex bash is 0.3, parsed 0.03 against an NPC + if (ForcedMovement == 0 && a->force != 0.0f && position_update_melee_push_timer.Check()) { + m_Delta.x += a->force * g_Math.FastSin(a->hit_heading); + m_Delta.y += a->force * g_Math.FastCos(a->hit_heading); + ForcedMovement = 3; } } - else { - a->force = 0.0f; // we couldn't move there, so lets not - } } //Note: if players can become pets, they will not receive damage messages of their own @@ -4390,6 +4442,12 @@ void Mob::DoRiposte(Mob *defender) if (!defender) return; + // so ahhh the angle you can riposte is larger than the angle you can hit :P + if (!defender->IsFacingMob(this)) { + defender->Message_StringID(MT_TooFarAway, CANT_SEE_TARGET); + return; + } + defender->Attack(this, EQEmu::inventory::slotPrimary, true); if (HasDied()) return; @@ -5250,19 +5308,30 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell) // extra off hand non-sense, can only double with skill of 150 or above // or you have any amount of GiveDoubleAttack if (candouble && hand == EQEmu::inventory::slotSecondary) - candouble = GetSkill(EQEmu::skills::SkillDoubleAttack) > 149 || (aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0; + candouble = + GetSkill(EQEmu::skills::SkillDoubleAttack) > 149 || + (aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0; if (candouble) { CheckIncreaseSkill(EQEmu::skills::SkillDoubleAttack, target, -10); if (CheckDoubleAttack()) { Attack(target, hand, false, false, IsFromSpell); + + // Modern AA description: Increases your chance of ... performing one additional hit with a 2-handed weapon when double attacking by 2%. + if (hand == EQEmu::inventory::slotPrimary) { + auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + + itembonuses.ExtraAttackChance; + if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance)) + Attack(target, hand, false, false, IsFromSpell); + } + // you can only triple from the main hand if (hand == EQEmu::inventory::slotPrimary && CanThisClassTripleAttack()) { CheckIncreaseSkill(EQEmu::skills::SkillTripleAttack, target, -10); if (CheckTripleAttack()) { Attack(target, hand, false, false, IsFromSpell); auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + - itembonuses.FlurryChance; + itembonuses.FlurryChance; if (flurrychance && zone->random.Roll(flurrychance)) { Attack(target, hand, false, false, IsFromSpell); if (zone->random.Roll(flurrychance)) @@ -5273,12 +5342,6 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell) } } } - - if (hand == EQEmu::inventory::slotPrimary) { - auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance; - if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance)) - Attack(target, hand, false, false, IsFromSpell); - } } bool Mob::CheckDualWield() diff --git a/zone/aura.cpp b/zone/aura.cpp index 8c54b75ee..8a885c67b 100644 --- a/zone/aura.cpp +++ b/zone/aura.cpp @@ -616,6 +616,7 @@ bool Aura::Process() it = spawned_for.erase(it); } } + safe_delete(app); } // TODO: waypoints? @@ -757,6 +758,8 @@ void Mob::MakeAura(uint16 spell_id) auto npc = new Aura(npc_type, this, record); npc->SetAuraID(spell_id); + if (trap) + npc->TryMoveAlong(5.0f, 0.0f, false); // try to place 5 units in front entity_list.AddNPC(npc, false); if (trap) diff --git a/zone/bot.cpp b/zone/bot.cpp index 6a1521d6b..8751d40f7 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -70,7 +70,6 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm SetBotCharmer(false); SetPetChooser(false); SetRangerAutoWeaponSelect(false); - SetHasBeenSummoned(false); SetTaunting(GetClass() == WARRIOR); SetDefaultBotStance(); @@ -140,7 +139,6 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to SetBotCharmer(false); SetPetChooser(false); SetRangerAutoWeaponSelect(false); - SetHasBeenSummoned(false); bool stance_flag = false; if (!botdb.LoadStance(this, stance_flag) && bot_owner) @@ -2043,70 +2041,106 @@ void Bot::SetTarget(Mob* mob) { } } -float Bot::GetMaxMeleeRangeToTarget(Mob* target) { - float result = 0; - if(target) { - float size_mod = GetSize(); - float other_size_mod = target->GetSize(); +void Bot::SetGuardMode() { + WipeHateList(); + SetTarget(nullptr); + SetFollowID(GetID()); + StopMoving(); + m_GuardPoint = GetPosition(); - if(GetRace() == 49 || GetRace() == 158 || GetRace() == 196) //For races with a fixed size - size_mod = 60.0f; - else if (size_mod < 6.0) - size_mod = 8.0f; - - if(target->GetRace() == 49 || target->GetRace() == 158 || target->GetRace() == 196) //For races with a fixed size - other_size_mod = 60.0f; - else if (other_size_mod < 6.0) - other_size_mod = 8.0f; - - if (other_size_mod > size_mod) - size_mod = other_size_mod; - - if (size_mod > 29) - size_mod *= size_mod; - else if (size_mod > 19) - size_mod *= (size_mod * 2); - else - size_mod *= (size_mod * 4); - - // prevention of ridiculously sized hit boxes - if (size_mod > 10000) - size_mod = (size_mod / 7); - - result = size_mod; + if (HasPet()) { + GetPet()->WipeHateList(); + GetPet()->SetTarget(nullptr); + GetPet()->StopMoving(); } - - return result; } // AI Processing for the Bot object void Bot::AI_Process() { - // TODO: Need to add root checks to all movement code - if (!IsAIControlled()) - return; - if (GetPauseAI()) +#define TEST_TARGET() if (!GetTarget()) { return; } + + Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr); + Group* bot_group = GetGroup(); + Mob* follow_mob = entity_list.GetMob(GetFollowID()); + + // Primary reasons for not processing AI + if (!bot_owner || !bot_group || !follow_mob || !IsAIControlled()) return; - uint8 botClass = GetClass(); - uint8 botLevel = GetLevel(); + if (bot_owner->IsDead()) { + SetTarget(nullptr); + SetBotOwner(nullptr); + + return; + } + + // We also need a leash owner (subset of primary AI criteria) + Client* leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner); + if (!leash_owner) + return; + + // Berserk updates should occur if primary AI criteria are met + if (GetClass() == WARRIOR || GetClass() == BERSERKER) { + if (!berserk && GetHP() > 0 && GetHPRatio() < 30.0f) { + entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_START, GetName()); + berserk = true; + } + + if (berserk && GetHPRatio() >= 30.0f) { + entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_END, GetName()); + berserk = false; + } + } + + // Secondary reasons for not processing AI + if (GetPauseAI() || IsStunned() || IsMezzed() || (GetAppearance() == eaDead)) { + if (IsCasting()) + InterruptSpell(); + if (IsMyHealRotationSet() || (AmICastingForHealRotation() && m_member_of_heal_rotation->CastingMember() == this)) { + AdvanceHealRotation(false); + m_member_of_heal_rotation->SetMemberIsCasting(this, false); + } + + return; + } + + bool guard_mode = (follow_mob == this); + + auto fm_dist = DistanceSquared(m_Position, follow_mob->GetPosition()); + auto lo_distance = DistanceSquared(m_Position, leash_owner->GetPosition()); if (IsCasting()) { - if ( - IsHealRotationMember() && + if (IsHealRotationMember() && m_member_of_heal_rotation->CastingOverride() && m_member_of_heal_rotation->CastingTarget() != nullptr && m_member_of_heal_rotation->CastingReady() && m_member_of_heal_rotation->CastingMember() == this && - !m_member_of_heal_rotation->MemberIsCasting(this) - ) { + !m_member_of_heal_rotation->MemberIsCasting(this)) + { InterruptSpell(); } else if (AmICastingForHealRotation() && m_member_of_heal_rotation->CastingMember() == this) { AdvanceHealRotation(false); return; } - else if (botClass != BARD) { + else if (GetClass() != BARD) { + if (IsEngaged()) + return; + if (fm_dist > GetFollowDistance()) // Cancel out-of-combat casting if movement is required + InterruptSpell(); + if (guard_mode) { + auto& my_pos = GetPosition(); + auto& my_guard = GetGuardPoint(); + + if (my_pos.x != my_guard.x || + my_pos.y != my_guard.y || + my_pos.z != my_guard.z) + { + InterruptSpell(); + } + } + return; } } @@ -2114,28 +2148,13 @@ void Bot::AI_Process() { m_member_of_heal_rotation->SetMemberIsCasting(this, false); } - // A bot wont start its AI if not grouped - if(!GetBotOwner() || !IsGrouped() || GetAppearance() == eaDead) - return; - - Mob* BotOwner = GetBotOwner(); - if(!BotOwner) - return; - - try { - if(BotOwner->CastToClient()->IsDead()) { - SetTarget(0); - SetBotOwner(0); - return; - } - } - catch(...) { - SetTarget(0); - SetBotOwner(0); + // Can't move if rooted... + if (IsRooted() && IsMoving()) { + StopMoving(); return; } - if(IsMyHealRotationSet()) { + if (IsMyHealRotationSet()) { Mob* delete_me = HealRotationTarget(); if (AIHealRotation(HealRotationTarget(), UseHealRotationFastHeals())) { #if (EQDEBUG >= 12) @@ -2154,432 +2173,651 @@ void Bot::AI_Process() { } } - if(GetHasBeenSummoned()) { - if(IsBotCaster() || IsBotArcher()) { - if (AI_movement_timer->Check()) { - if(!GetTarget() || (IsBotCaster() && !IsBotCasterAtCombatRange(GetTarget())) || (IsBotArcher() && IsArcheryRange(GetTarget())) || (DistanceSquaredNoZ(static_cast(m_Position), m_PreSummonLocation) < 10)) { - if(GetTarget()) - FaceTarget(GetTarget()); + // Empty hate list - let's find a target + if (!guard_mode && !IsEngaged()) { + Mob* lo_target = leash_owner->GetTarget(); - SetHasBeenSummoned(false); - } else if(!IsRooted()) { - if(GetTarget() && GetTarget()->GetHateTop() && GetTarget()->GetHateTop() != this) { - Log(Logs::Detail, Logs::AI, "Returning to location prior to being summoned."); - CalculateNewPosition2(m_PreSummonLocation.x, m_PreSummonLocation.y, m_PreSummonLocation.z, GetBotRunspeed()); - SetHeading(CalculateHeadingToTarget(m_PreSummonLocation.x, m_PreSummonLocation.y)); - return; - } - } - - if(IsMoving()) - SendPositionUpdate(); - else - SendPosition(); - } - } else { - if(GetTarget()) - FaceTarget(GetTarget()); - - SetHasBeenSummoned(false); + if (lo_target && lo_target->IsNPC() && + !lo_target->IsMezzed() && + (lo_target->GetHateAmount(leash_owner) || leash_owner->AutoAttackEnabled()) && + lo_distance <= BOT_LEASH_DISTANCE && + DistanceSquared(m_Position, lo_target->GetPosition()) <= BOT_LEASH_DISTANCE && + (CheckLosFN(lo_target) || leash_owner->CheckLosFN(lo_target)) && + IsAttackAllowed(lo_target)) + { + AddToHateList(lo_target, 1); + if (HasPet()) + GetPet()->AddToHateList(lo_target, 1); } - return; - } + else { + for (int counter = 0; counter < bot_group->GroupCount(); counter++) { + Mob* bg_member = bot_group->members[counter]; + if (!bg_member) + continue; - if(!IsEngaged()) { - if(GetFollowID()) { - if(BotOwner && BotOwner->GetTarget() && BotOwner->GetTarget()->IsNPC() && (BotOwner->GetTarget()->GetHateAmount(BotOwner) || BotOwner->CastToClient()->AutoAttackEnabled()) && IsAttackAllowed(BotOwner->GetTarget())) { - AddToHateList(BotOwner->GetTarget(), 1); - if(HasPet()) - GetPet()->AddToHateList(BotOwner->GetTarget(), 1); - } else { - Group* g = GetGroup(); - if(g) { - for(int counter = 0; counter < g->GroupCount(); counter++) { - if(g->members[counter]) { - Mob* tar = g->members[counter]->GetTarget(); - if(tar && tar->IsNPC() && tar->GetHateAmount(g->members[counter]) && IsAttackAllowed(g->members[counter]->GetTarget())) { - AddToHateList(tar, 1); - if(HasPet()) - GetPet()->AddToHateList(tar, 1); + Mob* bgm_target = bg_member->GetTarget(); + if (!bgm_target || !bgm_target->IsNPC()) + continue; - break; - } - } - } + if (!bgm_target->IsMezzed() && + bgm_target->GetHateAmount(bg_member) && + lo_distance <= BOT_LEASH_DISTANCE && + DistanceSquared(m_Position, bgm_target->GetPosition()) <= BOT_LEASH_DISTANCE && + (CheckLosFN(bgm_target) || leash_owner->CheckLosFN(bgm_target)) && + IsAttackAllowed(bgm_target)) + { + AddToHateList(bgm_target, 1); + if (HasPet()) + GetPet()->AddToHateList(bgm_target, 1); + + break; } } } } - if(IsEngaged()) { - if(rest_timer.Enabled()) + glm::vec3 Goal(0, 0, 0); + + // We have aggro to choose from + if (IsEngaged()) { + if (rest_timer.Enabled()) rest_timer.Disable(); - if(IsRooted()) - SetTarget(hate_list.GetClosestEntOnHateList(this)); - else - SetTarget(hate_list.GetEntWithMostHateOnList(this)); + // Group roles can be expounded upon in the future + auto assist_mob = entity_list.GetMob(bot_group->GetMainAssistName()); + bool find_target = true; + + if (assist_mob) { + if (assist_mob->GetTarget()) { + if (assist_mob != this) + SetTarget(assist_mob->GetTarget()); - if(!GetTarget()) + find_target = false; + } + else if (assist_mob != this) { + SetTarget(nullptr); + if (HasPet()) + GetPet()->SetTarget(nullptr); + + find_target = false; + } + } + + if (find_target) { + if (IsRooted()) + SetTarget(hate_list.GetClosestEntOnHateList(this)); + else + SetTarget(hate_list.GetEntWithMostHateOnList(this)); + } + + TEST_TARGET(); + + Mob* tar = GetTarget(); + if (!tar) return; - if(HasPet()) - GetPet()->SetTarget(GetTarget()); - - if(!IsSitting()) - FaceTarget(GetTarget()); - - if(DivineAura()) - return; + float tar_distance = DistanceSquared(m_Position, tar->GetPosition()); // Let's check if we have a los with our target. // If we don't, our hate_list is wiped. // Else, it was causing the bot to aggro behind wall etc... causing massive trains. - if(GetTarget()->IsMezzed() || !IsAttackAllowed(GetTarget())) { - WipeHateList(); - if(IsMoving()) { - SetHeading(0); - SetRunAnimSpeed(0); - SetCurrentSpeed(GetBotRunspeed()); - if(moved) - SetCurrentSpeed(0); + if (guard_mode || + !tar->IsNPC() || + tar->IsMezzed() || + (!tar->GetHateAmount(this) && !tar->GetHateAmount(leash_owner) && !leash_owner->AutoAttackEnabled()) || + lo_distance > BOT_LEASH_DISTANCE || + tar_distance > BOT_LEASH_DISTANCE || + (!CheckLosFN(tar) && !leash_owner->CheckLosFN(tar)) || + !IsAttackAllowed(tar)) + { + if (HasPet()) { + GetPet()->RemoveFromHateList(tar); + GetPet()->SetTarget(nullptr); } - return; - } - else if (!CheckLosFN(GetTarget())) { - if (RuleB(Bots, UsePathing) && zone->pathing) { - bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), - GetBotRunspeed(), WaypointChanged, NodeReached); + RemoveFromHateList(tar); + SetTarget(nullptr); - if (WaypointChanged) - tar_ndx = 20; - - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotRunspeed()); - } - else { - Mob* follow = entity_list.GetMob(GetFollowID()); - if (follow) - CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), GetBotRunspeed()); - } + if (IsMoving()) + StopMoving(); return; } + if (HasPet()) // this causes conflicts with default pet handler (bounces between targets) + GetPet()->SetTarget(tar); + + if (DivineAura()) + return; + if (!(m_PlayerState & static_cast(PlayerState::Aggressive))) SendAddPlayerState(PlayerState::Aggressive); bool atCombatRange = false; - float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget()); - if(botClass == SHADOWKNIGHT || botClass == PALADIN || botClass == WARRIOR) - meleeDistance = (meleeDistance * .30); - else - meleeDistance *= (float)zone->random.Real(.50, .85); - bool atArcheryRange = IsArcheryRange(GetTarget()); + const auto* p_item = GetBotItem(EQEmu::inventory::slotPrimary); + const auto* s_item = GetBotItem(EQEmu::inventory::slotSecondary); - if(GetRangerAutoWeaponSelect()) { + bool behind_mob = false; + bool backstab_weapon = false; + if (GetClass() == ROGUE) { + behind_mob = BehindMob(tar, GetX(), GetY()); // can be separated for other future use + backstab_weapon = p_item && p_item->GetItemBackstabDamage(); + } + + // Calculate melee distance + float melee_distance_max = 0.0f; + { + float size_mod = GetSize(); + float other_size_mod = tar->GetSize(); + + if (GetRace() == RT_DRAGON || GetRace() == RT_WURM || GetRace() == RT_DRAGON_7) //For races with a fixed size + size_mod = 60.0f; + else if (size_mod < 6.0f) + size_mod = 8.0f; + + if (tar->GetRace() == RT_DRAGON || tar->GetRace() == RT_WURM || tar->GetRace() == RT_DRAGON_7) //For races with a fixed size + other_size_mod = 60.0f; + else if (other_size_mod < 6.0f) + other_size_mod = 8.0f; + + if (other_size_mod > size_mod) + size_mod = other_size_mod; + + if (size_mod > 29.0f) + size_mod *= size_mod; + else if (size_mod > 19.0f) + size_mod *= (size_mod * 2.0f); + else + size_mod *= (size_mod * 4.0f); + + // prevention of ridiculously sized hit boxes + if (size_mod > 10000.0f) + size_mod = (size_mod / 7.0f); + + melee_distance_max = size_mod; + } + + float melee_distance = 0.0f; + + switch (GetClass()) { + case WARRIOR: + case PALADIN: + case SHADOWKNIGHT: + if (p_item && p_item->GetItem()->IsType2HWeapon()) + melee_distance = melee_distance_max * 0.45f; + else if ((s_item && s_item->GetItem()->IsTypeShield()) || (!p_item && !s_item)) + melee_distance = melee_distance_max * 0.35f; + else + melee_distance = melee_distance_max * 0.40f; + + break; + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + if (p_item && p_item->GetItem()->IsType2HWeapon()) + melee_distance = melee_distance_max * 0.95f; + else + melee_distance = melee_distance_max * 0.75f; + + break; + case ROGUE: + if (behind_mob && backstab_weapon) { + if (p_item->GetItem()->IsType2HWeapon()) // p_item tested above + melee_distance = melee_distance_max * 0.30f; + else + melee_distance = melee_distance_max * 0.25f; + + break; + } + // Fall-through + default: + if (p_item && p_item->GetItem()->IsType2HWeapon()) + melee_distance = melee_distance_max * 0.70f; + else + melee_distance = melee_distance_max * 0.50f; + + break; + } + + float melee_distance_min = melee_distance / 2.0f; + + // Calculate casting distance + float caster_distance_max = 0.0f; + { + if (GetLevel() >= RuleI(Bots, CasterStopMeleeLevel)) { + switch (GetClass()) { + case CLERIC: + caster_distance_max = 1156.0f; // as DSq value (34 units) + break; + case DRUID: + caster_distance_max = 1764.0f; // as DSq value (42 units) + break; + case SHAMAN: + caster_distance_max = 1444.0f; // as DSq value (38 units) + break; + case NECROMANCER: + caster_distance_max = 2916.0f; // as DSq value (54 units) + break; + case WIZARD: + caster_distance_max = 2304.0f; // as DSq value (48 units) + break; + case MAGICIAN: + caster_distance_max = 2704.0f; // as DSq value (52 units) + break; + case ENCHANTER: + caster_distance_max = 2500.0f; // as DSq value (50 units) + break; + default: + break; + } + } + } + + float caster_distance_min = 0.0f; + if (caster_distance_max) { + caster_distance_min = melee_distance_max; + + if (caster_distance_max <= caster_distance_min) + caster_distance_max = caster_distance_min * 1.25f; + } + + bool atArcheryRange = IsArcheryRange(tar); + + if (GetRangerAutoWeaponSelect()) { bool changeWeapons = false; - if(atArcheryRange && !IsBotArcher()) { + if (atArcheryRange && !IsBotArcher()) { SetBotArcher(true); changeWeapons = true; - } else if(!atArcheryRange && IsBotArcher()) { + } + else if (!atArcheryRange && IsBotArcher()) { SetBotArcher(false); changeWeapons = true; } - if(changeWeapons) + if (changeWeapons) ChangeBotArcherWeapons(IsBotArcher()); } - if (IsBotArcher() && atArcheryRange) { + if (IsBotArcher() && atArcheryRange) + atCombatRange = true; + else if (caster_distance_max && tar_distance <= caster_distance_max) + atCombatRange = true; + else if (tar_distance <= melee_distance) + atCombatRange = true; + + // We can fight + if (atCombatRange) { if (IsMoving()) { - SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); - SetRunAnimSpeed(0); - SetCurrentSpeed(0); - if (moved) { - moved = false; - SetCurrentSpeed(0); - } + StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY())); + return; } - atCombatRange = true; - } - else if (GetLevel() >= RuleI(Bots, CasterStopMeleeLevel) && IsBotCasterAtCombatRange(GetTarget())) { - atCombatRange = true; - } - else if (DistanceSquared(m_Position, GetTarget()->GetPosition()) <= meleeDistance) { - atCombatRange = true; - } + + // Combat 'jitter' code + if (AI_movement_timer->Check() && (!spellend_timer.Enabled() || GetClass() == BARD)) { + if (!IsRooted()) { + if (HasTargetReflection()) { + if (!tar->IsFeared() && !tar->IsStunned()) { + if (GetClass() == ROGUE) { + if (evade_timer.Check(false)) { // Attempt to evade + int timer_duration = (HideReuseTime - GetSkillReuseTime(EQEmu::skills::SkillHide)) * 1000; + if (timer_duration < 0) + timer_duration = 0; - if(atCombatRange) { - if(IsMoving()) { - SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); - SetCurrentSpeed(0); - if(moved) { - moved = false; - SetCurrentSpeed(0); - } - } + evade_timer.Start(timer_duration); + if (zone->random.Int(0, 260) < (int)GetSkill(EQEmu::skills::SkillHide)) + RogueEvade(tar); - if(AI_movement_timer->Check()) { - if (!IsMoving()) { - if (GetClass() == ROGUE) { - if (HasTargetReflection() && !GetTarget()->IsFeared() && !GetTarget()->IsStunned()) { - // Hate redux actions - if (evade_timer.Check(false)) { - // Attempt to evade - int timer_duration = (HideReuseTime - GetSkillReuseTime(EQEmu::skills::SkillHide)) * 1000; - if (timer_duration < 0) - timer_duration = 0; - evade_timer.Start(timer_duration); - - Bot::BotGroupSay(this, "Attempting to evade %s", GetTarget()->GetCleanName()); - if (zone->random.Int(0, 260) < (int)GetSkill(EQEmu::skills::SkillHide)) - RogueEvade(GetTarget()); - - return; + return; + } } - else if (GetTarget()->IsRooted()) { - // Move rogue back from rooted mob - out of combat range, if necessary - float melee_distance = GetMaxMeleeRangeToTarget(GetTarget()); - float current_distance = DistanceSquared(static_cast(m_Position), static_cast(GetTarget()->GetPosition())); - - if (current_distance <= melee_distance) { - float newX = 0; - float newY = 0; - float newZ = 0; - FaceTarget(GetTarget()); - if (PlotPositionAroundTarget(this, newX, newY, newZ)) { - CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed()); - return; + + if (tar->IsRooted()) { // Move caster/rogue back from rooted mob - out of combat range, if necessary + if (GetArchetype() == ARCHETYPE_CASTER || GetClass() == ROGUE) { + if (tar_distance <= melee_distance_max) { + if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) { + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false); + return; + } } } } } - else if (!BehindMob(GetTarget(), GetX(), GetY())) { - // Move the rogue to behind the mob - float newX = 0; - float newY = 0; - float newZ = 0; - if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) { - CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed()); - return; + } + else { + if (caster_distance_min && tar_distance < caster_distance_min && !tar->IsFeared()) { // Caster back-off adjustment + if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) { + if (DistanceSquared(Goal, tar->GetPosition()) <= caster_distance_max) { + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false); + return; + } } } - } - else if (GetClass() != ROGUE && (DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) < GetTarget()->GetSize())) { - // If we are not a rogue trying to backstab, let's try to adjust our melee range so we don't appear to be bunched up - float newX = 0; - float newY = 0; - float newZ = 0; - if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) { - CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed()); + else if (tar_distance < melee_distance_min) { // Melee back-off adjustment + if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) { + if (DistanceSquared(Goal, tar->GetPosition()) <= melee_distance_max) { + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false); + return; + } + } + } + else if (backstab_weapon && !behind_mob) { // Move the rogue to behind the mob + if (PlotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z)) { + if (DistanceSquared(Goal, tar->GetPosition()) <= melee_distance_max) { + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotRunspeed(), true, false); // rogues are agile enough to run in melee range + return; + } + } + } + else { + if (caster_distance_max == 0.0f && // Not a caster or a caster still below melee stop level (standard combat jitter) + zone->random.Int(1, 100) >= 94 && // 7:100 chance + PlotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z)) // If we're behind the mob, we can attack when it's enraged + { + if (DistanceSquared(Goal, tar->GetPosition()) <= melee_distance_max) { + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false); + return; + } + } + } + + if (!IsFacingMob(tar)) { + FaceTarget(tar); return; } } } - - // TODO: Test RuleB(Bots, UpdatePositionWithTimer) - if(IsMoving()) - SendPositionUpdate(); - else - SendPosition(); + else { + if (!IsSitting() && !IsFacingMob(tar)) { + FaceTarget(tar); + return; + } + } } - if(IsBotArcher() && ranged_timer.Check(false)) { - if(GetTarget()->GetHPRatio() <= 99.0f) - BotRangedAttack(GetTarget()); + // Up to this point, GetTarget() has been safe to dereference since the initial + // TEST_TARGET() call. Due to the chance of the target dying and our pointer + // being nullified, we need to test it before dereferencing to avoid crashes + + if (IsBotArcher() && ranged_timer.Check(false)) { // can shoot mezzed, stunned and dead!? + TEST_TARGET(); + if (GetTarget()->GetHPRatio() <= 99.0f) + BotRangedAttack(tar); } - else if(!IsBotArcher() && (!(IsBotCaster() && GetLevel() >= RuleI(Bots, CasterStopMeleeLevel))) && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead)) { + else if (!IsBotArcher() && (!(IsBotCaster() && GetLevel() >= RuleI(Bots, CasterStopMeleeLevel)))) { // we can't fight if we don't have a target, are stun/mezzed or dead.. // Stop attacking if the target is enraged - if((IsEngaged() && !BehindMob(GetTarget(), GetX(), GetY()) && GetTarget()->IsEnraged()) || GetBotStance() == BotStancePassive) + TEST_TARGET(); + if (GetBotStance() == BotStancePassive || (tar->IsEnraged() && !BehindMob(tar, GetX(), GetY()))) return; // First, special attack per class (kick, backstab etc..) - DoClassAttacks(GetTarget()); - if(attack_timer.Check()) { - Attack(GetTarget(), EQEmu::inventory::slotPrimary); - TriggerDefensiveProcs(GetTarget(), EQEmu::inventory::slotPrimary, false); - EQEmu::ItemInstance *wpn = GetBotItem(EQEmu::inventory::slotPrimary); - TryWeaponProc(wpn, GetTarget(), EQEmu::inventory::slotPrimary); - bool tripleSuccess = false; - if(BotOwner && GetTarget() && CanThisClassDoubleAttack()) { - if(BotOwner && CheckBotDoubleAttack()) - Attack(GetTarget(), EQEmu::inventory::slotPrimary, true); + TEST_TARGET(); + DoClassAttacks(tar); - if(BotOwner && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) { - tripleSuccess = true; - Attack(GetTarget(), EQEmu::inventory::slotPrimary, true); + TEST_TARGET(); + if (attack_timer.Check()) { // Process primary weapon attacks + Attack(tar, EQEmu::inventory::slotPrimary); + + TEST_TARGET(); + TriggerDefensiveProcs(tar, EQEmu::inventory::slotPrimary, false); + + TEST_TARGET(); + TryWeaponProc(p_item, tar, EQEmu::inventory::slotPrimary); + + //bool tripleSuccess = false; + + TEST_TARGET(); + if (CanThisClassDoubleAttack()) { + if (CheckBotDoubleAttack()) + Attack(tar, EQEmu::inventory::slotPrimary, true); + + TEST_TARGET(); + if (GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) { + //tripleSuccess = true; + Attack(tar, EQEmu::inventory::slotPrimary, true); } + TEST_TARGET(); //quad attack, does this belong here?? - if(BotOwner && GetTarget() && GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) - Attack(GetTarget(), EQEmu::inventory::slotPrimary, true); + if (GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) + Attack(tar, EQEmu::inventory::slotPrimary, true); } + TEST_TARGET(); //Live AA - Flurry, Rapid Strikes ect (Flurry does not require Triple Attack). int32 flurrychance = (aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance); - if (GetTarget() && flurrychance) { - if(zone->random.Int(0, 100) < flurrychance) { + if (flurrychance) { + if (zone->random.Int(0, 100) < flurrychance) { Message_StringID(MT_NPCFlurry, YOU_FLURRY); - Attack(GetTarget(), EQEmu::inventory::slotPrimary, false); - Attack(GetTarget(), EQEmu::inventory::slotPrimary, false); + Attack(tar, EQEmu::inventory::slotPrimary, false); + + TEST_TARGET(); + Attack(tar, EQEmu::inventory::slotPrimary, false); } } + TEST_TARGET(); int32 ExtraAttackChanceBonus = (spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance); - if (GetTarget() && ExtraAttackChanceBonus) { - EQEmu::ItemInstance *wpn = GetBotItem(EQEmu::inventory::slotPrimary); - if(wpn) { - if (wpn->GetItem()->IsType2HWeapon()) { - if(zone->random.Int(0, 100) < ExtraAttackChanceBonus) - Attack(GetTarget(), EQEmu::inventory::slotPrimary, false); - } + if (ExtraAttackChanceBonus) { + if (p_item && p_item->GetItem()->IsType2HWeapon()) { + if (zone->random.Int(0, 100) < ExtraAttackChanceBonus) + Attack(tar, EQEmu::inventory::slotPrimary, false); } } } - if (GetClass() == WARRIOR || GetClass() == BERSERKER) { - if(GetHP() > 0 && !berserk && this->GetHPRatio() < 30) { - entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_START, GetName()); - this->berserk = true; - } - - if (berserk && this->GetHPRatio() > 30) { - entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_END, GetName()); - this->berserk = false; - } - } - - //now off hand - if(GetTarget() && attack_dw_timer.Check() && CanThisClassDualWield()) { - const EQEmu::ItemInstance* instweapon = GetBotItem(EQEmu::inventory::slotSecondary); - const EQEmu::ItemData* weapon = nullptr; + TEST_TARGET(); + if (attack_dw_timer.Check() && CanThisClassDualWield()) { // Process secondary weapon attacks + const EQEmu::ItemData* s_itemdata = nullptr; //can only dual wield without a weapon if you're a monk - if(instweapon || (botClass == MONK)) { - if(instweapon) - weapon = instweapon->GetItem(); + if (s_item || (GetClass() == MONK)) { + if(s_item) + s_itemdata = s_item->GetItem(); - int weapontype = 0; // No weapon type. - bool bIsFist = true; - if(weapon) { - weapontype = weapon->ItemType; - bIsFist = false; + int weapon_type = 0; // No weapon type. + bool use_fist = true; + if (s_itemdata) { + weapon_type = s_itemdata->ItemType; + use_fist = false; } - if (bIsFist || !weapon->IsType2HWeapon()) { + if (use_fist || !s_itemdata->IsType2HWeapon()) { float DualWieldProbability = 0.0f; + int32 Ambidexterity = (aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity); DualWieldProbability = ((GetSkill(EQEmu::skills::SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f); // 78.0 max + int32 DWBonus = (spellbonuses.DualWieldChance + itembonuses.DualWieldChance); DualWieldProbability += (DualWieldProbability * float(DWBonus) / 100.0f); + float random = zone->random.Real(0, 1); + if (random < DualWieldProbability){ // Max 78% of DW - Attack(GetTarget(), EQEmu::inventory::slotSecondary); // Single attack with offhand - EQEmu::ItemInstance *wpn = GetBotItem(EQEmu::inventory::slotSecondary); - TryWeaponProc(wpn, GetTarget(), EQEmu::inventory::slotSecondary); - if( CanThisClassDoubleAttack() && CheckBotDoubleAttack()) { - if(GetTarget() && GetTarget()->GetHP() > -10) - Attack(GetTarget(), EQEmu::inventory::slotSecondary); // Single attack with offhand + Attack(tar, EQEmu::inventory::slotSecondary); // Single attack with offhand + + TEST_TARGET(); + TryWeaponProc(s_item, tar, EQEmu::inventory::slotSecondary); + + TEST_TARGET(); + if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) { + if (tar->GetHP() > -10) + Attack(tar, EQEmu::inventory::slotSecondary); // Single attack with offhand } } } } } } - } else { - if(GetTarget()->IsFeared() && !spellend_timer.Enabled()){ - // This is a mob that is fleeing either because it has been feared or is low on hitpoints - if(GetBotStance() != BotStancePassive) - AI_PursueCastCheck(); - } - - if (AI_movement_timer->Check()) { - if(!IsRooted()) { + } + else { // To far away to fight (GetTarget() validity can be iffy below this point - including outer scopes) + if (AI_movement_timer->Check() && (!spellend_timer.Enabled() || GetClass() == BARD)) { // Pursue processing + if (GetTarget() && !IsRooted()) { Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); - CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetBotRunspeed()); + + Goal = GetTarget()->GetPosition(); + + if (RuleB(Bots, UsePathing) && zone->pathing) { + bool WaypointChanged, NodeReached; + + Goal = UpdatePath(Goal.x, Goal.y, Goal.z, + GetBotRunspeed(), WaypointChanged, NodeReached); + + if (WaypointChanged) + tar_ndx = 20; + } + + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotRunspeed()); + return; } + else { + if (IsMoving()) + StopMoving(); + else + SendPosition(); - if(IsMoving()) - SendPositionUpdate(); - else - SendPosition(); + return; + } + } + + // Fix Z when following during pull, not when engaged and stationary + if (IsMoving() && fix_z_timer_engaged.Check()) { + FixZ(); + return; + } + + if (GetTarget() && GetTarget()->IsFeared() && !spellend_timer.Enabled() && AI_think_timer->Check()) { + if (!IsFacingMob(GetTarget())) + FaceTarget(GetTarget()); + + // This is a mob that is fleeing either because it has been feared or is low on hitpoints + if (GetBotStance() != BotStancePassive) { + AI_PursueCastCheck(); // This appears to always return true..can't trust for success/fail + return; + } } } // end not in combat range - if(!IsMoving() && !spellend_timer.Enabled()) { - if(GetBotStance() == BotStancePassive) - return; + if (!IsMoving() && !spellend_timer.Enabled()) { // This may actually need work... + SendPosition(); - if(AI_EngagedCastCheck()) + if (GetBotStance() == BotStancePassive) + return; + + if (GetTarget() && AI_EngagedCastCheck()) BotMeditate(false); - else if(GetArchetype() == ARCHETYPE_CASTER) + else if (GetArchetype() == ARCHETYPE_CASTER) BotMeditate(true); + + return; } } - else { + else { // Out-of-combat behavior SetTarget(nullptr); + + if (HasPet()) { + GetPet()->WipeHateList(); + GetPet()->SetTarget(nullptr); + } + if (m_PlayerState & static_cast(PlayerState::Aggressive)) SendRemovePlayerState(PlayerState::Aggressive); - Mob* follow = entity_list.GetMob(GetFollowID()); - if (!follow) - return; + // Check guard point + if (guard_mode) { + auto& my_pos = GetPosition(); + auto& my_guard = GetGuardPoint(); - if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { - if (GetBotStance() != BotStancePassive) { - if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD) - BotMeditate(true); - } - else { - if (GetClass() != BARD) - BotMeditate(true); + if (my_pos.x != my_guard.x || + my_pos.y != my_guard.y || + my_pos.z != my_guard.z) + { + if (IsMoving()) + StopMoving(); + + Warp(glm::vec3(my_guard)); + + if (HasPet()) + GetPet()->Warp(glm::vec3(my_guard)); + + return; } } + // Leash the bot + else if (lo_distance > BOT_LEASH_DISTANCE) { + if (IsMoving()) + StopMoving(); - if (AI_movement_timer->Check()) { - float dist = DistanceSquared(m_Position, follow->GetPosition()); - int speed = GetBotRunspeed(); + Warp(glm::vec3(leash_owner->GetPosition())); + + if (HasPet()) + GetPet()->Warp(glm::vec3(leash_owner->GetPosition())); - if (dist < GetFollowDistance() + BOT_FOLLOW_DISTANCE_WALK) - speed = GetBotWalkspeed(); + return; + } - SetRunAnimSpeed(0); - - if (dist > GetFollowDistance()) { - if (RuleB(Bots, UsePathing) && zone->pathing) { - bool WaypointChanged, NodeReached; - - glm::vec3 Goal = UpdatePath(follow->GetX(), follow->GetY(), follow->GetZ(), - speed, WaypointChanged, NodeReached); - - if (WaypointChanged) - tar_ndx = 20; - - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); + // Ok to idle + if (fm_dist <= GetFollowDistance()) { + if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { + if (GetBotStance() != BotStancePassive) { + if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD) + BotMeditate(true); } else { - CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed); + if (GetClass() != BARD) + BotMeditate(true); } - if (rest_timer.Enabled()) - rest_timer.Disable(); + return; + } + } + + // Non-engaged movement checks + if (AI_movement_timer->Check() && (!IsCasting() || GetClass() == BARD)) { + if (fm_dist > GetFollowDistance()) { + if (!IsRooted()) { + if (rest_timer.Enabled()) + rest_timer.Disable(); + + int speed = GetBotRunspeed(); + if (fm_dist < GetFollowDistance() + BOT_FOLLOW_DISTANCE_WALK) + speed = GetBotWalkspeed(); + + Goal = follow_mob->GetPosition(); + + if (RuleB(Bots, UsePathing) && zone->pathing) { + bool WaypointChanged, NodeReached; + + Goal = UpdatePath(Goal.x, Goal.y, Goal.z, + speed, WaypointChanged, NodeReached); + + if (WaypointChanged) + tar_ndx = 20; + } + + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); + + return; + } } else { - if (moved) { - moved = false; - SetCurrentSpeed(0); + if (IsMoving()) { + StopMoving(); + return; } } } + // Basically, bard bots get a chance to cast idle spells while moving if (IsMoving()) { - if (GetClass() == BARD && GetBotStance() != BotStancePassive && !spellend_timer.Enabled() && AI_think_timer->Check()) { - AI_IdleCastCheck(); + if (GetBotStance() != BotStancePassive) { + if (GetClass() == BARD && !spellend_timer.Enabled() && AI_think_timer->Check()) { + AI_IdleCastCheck(); + return; + } } } } @@ -2589,7 +2827,7 @@ void Bot::AI_Process() { void Bot::PetAIProcess() { if( !HasPet() || !GetPet() || !GetPet()->IsNPC()) return; - + Mob* BotOwner = this->GetBotOwner(); NPC* botPet = this->GetPet()->CastToNPC(); if(!botPet->GetOwner() || !botPet->GetID() || !botPet->GetOwnerID()) { @@ -2815,7 +3053,7 @@ void Bot::Depop() { NPC::Depop(false); } -void Bot::Spawn(Client* botCharacterOwner) { +bool Bot::Spawn(Client* botCharacterOwner) { if(GetBotID() > 0 && _botOwnerCharacterID > 0 && botCharacterOwner && botCharacterOwner->CharacterID() == _botOwnerCharacterID) { // Rename the bot name to make sure that Mob::GetName() matches Mob::GetCleanName() so we dont have a bot named "Jesuschrist001" strcpy(name, GetCleanName()); @@ -2859,7 +3097,11 @@ void Bot::Spawn(Client* botCharacterOwner) { this->SendWearChange(materialFromSlot); } } + + return true; } + + return false; } // Deletes the inventory record for the specified item from the database for this bot. @@ -3008,16 +3250,20 @@ void Bot::LoadAndSpawnAllZonedBots(Client* botOwner) { if(!ActiveBots.empty()) { for(std::list::iterator itr = ActiveBots.begin(); itr != ActiveBots.end(); ++itr) { Bot* activeBot = Bot::LoadBot(*itr); + if (!activeBot) + continue; - if(activeBot) { - activeBot->Spawn(botOwner); - g->UpdatePlayer(activeBot); - // follow the bot owner, not the group leader we just zoned with our owner. - if(g->IsGroupMember(botOwner) && g->IsGroupMember(activeBot)) - activeBot->SetFollowID(botOwner->GetID()); + if (!activeBot->Spawn(botOwner)) { + safe_delete(activeBot); + continue; } - if(activeBot && !botOwner->HasGroup()) + g->UpdatePlayer(activeBot); + // follow the bot owner, not the group leader we just zoned with our owner. + if (g->IsGroupMember(botOwner) && g->IsGroupMember(activeBot)) + activeBot->SetFollowID(botOwner->GetID()); + + if(!botOwner->HasGroup()) database.SetGroupID(activeBot->GetCleanName(), 0, activeBot->GetBotID()); } } @@ -7046,33 +7292,6 @@ bool Bot::IsArcheryRange(Mob *target) { return result; } -bool Bot::IsBotCasterAtCombatRange(Mob *target) -{ - static const float local[PLAYER_CLASS_COUNT] = { - 0.0f, // WARRIOR - 1156.0f, // CLERIC as DSq value (34 units) - 0.0f, 0.0f, 0.0f, // PALADIN, RANGER, SHADOWKNIGHT - 1764.0f, // DRUID as DSq value (42 units) - 0.0f, 0.0f, 0.0f, // MONK, BARD, ROGUE - 1444.0f, // SHAMAN as DSq value (38 units) - 2916.0f, // NECROMANCER as DSq value (54 units) - 2304.0f, // WIZARD as DSq value (48 units) - 2704.0f, // MAGICIAN as DSq value (52 units) - 2500.0f, // ENCHANTER as DSq value (50 units) - 0.0f, 0.0f // BEASTLORD, BERSERKER - }; - - if (!target) - return false; - if (GetClass() < WARRIOR || GetClass() > BERSERKER) - return false; - - float targetDistance = DistanceSquaredNoZ(m_Position, target->GetPosition()); - if (targetDistance < local[GetClass() - 1]) - return true; - return false; -} - void Bot::UpdateGroupCastingRoles(const Group* group, bool disband) { if (!group) @@ -8417,12 +8636,6 @@ bool Bot::HasOrMayGetAggro() { return mayGetAggro; } -void Bot::SetHasBeenSummoned(bool wasSummoned) { - _hasBeenSummoned = wasSummoned; - if(!wasSummoned) - m_PreSummonLocation = glm::vec3(); -} - void Bot::SetDefaultBotStance() { BotStanceType defaultStance = BotStanceBalanced; if (GetClass() == WARRIOR) @@ -8681,6 +8894,8 @@ bool Bot::DyeArmor(int16 slot_id, uint32 rgb, bool all_flag, bool save_flag) std::string Bot::CreateSayLink(Client* c, const char* message, const char* name) { + // TODO: review + int saylink_size = strlen(message); char* escaped_string = new char[saylink_size * 2]; diff --git a/zone/bot.h b/zone/bot.h index 1a6bcf7cd..1d38e5f57 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -42,6 +42,8 @@ #define BOT_FOLLOW_DISTANCE_DEFAULT_MAX 2500 // as DSq value (50 units) #define BOT_FOLLOW_DISTANCE_WALK 1000 // as DSq value (~31.623 units) +#define BOT_LEASH_DISTANCE 250000 // as DSq value (500 units) + extern WorldServer worldserver; const int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this @@ -273,7 +275,7 @@ public: static bool IsValidRaceClassCombo(uint16 r, uint8 c); bool IsValidName(); static bool IsValidName(std::string& name); - void Spawn(Client* botCharacterOwner); + bool Spawn(Client* botCharacterOwner); virtual void SetLevel(uint8 in_level, bool command = false); virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); virtual bool Process(); @@ -337,7 +339,7 @@ public: bool IsStanding(); int GetBotWalkspeed() const { return (int)((float)_GetWalkSpeed() * 1.786f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143 int GetBotRunspeed() const { return (int)((float)_GetRunSpeed() * 1.786f); } - bool IsBotCasterAtCombatRange(Mob *target); + int GetBotFearSpeed() const { return (int)((float)_GetFearSpeed() * 1.786f); } bool UseDiscipline(uint32 spell_id, uint32 target); uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets); bool GetNeedsCured(Mob *tar); @@ -404,8 +406,8 @@ public: bool AIHealRotation(Mob* tar, bool useFastHeals); bool GetPauseAI() { return _pauseAI; } void SetPauseAI(bool pause_flag) { _pauseAI = pause_flag; } + void SetGuardMode(); - // Mob AI Virtual Override Methods virtual void AI_Process(); virtual void AI_Stop(); @@ -532,9 +534,7 @@ public: bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); } bool CanHeal(); int GetRawACNoShield(int &shield_ac); - bool GetHasBeenSummoned() { return _hasBeenSummoned; } - const glm::vec3 GetPreSummonLocation() const { return m_PreSummonLocation; } - + // new heal rotation code bool CreateHealRotation(uint32 cycle_duration_ms = 5000, bool fast_heals = false, bool adaptive_targeting = false, bool casting_override = false); bool DestroyHealRotation(); @@ -628,9 +628,6 @@ public: void SetBotStance(BotStanceType botStance) { _botStance = ((botStance != BotStanceUnknown) ? (botStance) : (BotStancePassive)); } void SetSpellRecastTimer(int timer_index, int32 recast_delay); void SetDisciplineRecastTimer(int timer_index, int32 recast_delay); - void SetHasBeenSummoned(bool s); - void SetPreSummonLocation(const glm::vec3& location) { m_PreSummonLocation = location; } - void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;} void SetShowHelm(bool showhelm) { _showhelm = showhelm; } void SetBeardColor(uint8 value) { beardcolor = value; } @@ -688,7 +685,6 @@ protected: virtual int32 CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 spell_id); virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client); virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); - virtual float GetMaxMeleeRangeToTarget(Mob* target); BotCastingRoles& GetCastingRoles() { return m_CastingRoles; } void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; } @@ -734,9 +730,7 @@ private: int32 max_end; int32 end_regen; uint32 timers[MaxTimer]; - bool _hasBeenSummoned; - glm::vec3 m_PreSummonLocation; - + Timer evade_timer; // can be moved to pTimers at some point BotCastingRoles m_CastingRoles; diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 5ba73d068..a91624df1 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -3047,13 +3047,7 @@ void bot_command_guard(Client *c, const Seperator *sep) sbl.remove(nullptr); for (auto bot_iter : sbl) { - bot_iter->WipeHateList(); - bot_iter->SetFollowID(0); - if (!bot_iter->GetPet()) - continue; - - bot_iter->GetPet()->WipeHateList(); - bot_iter->GetPet()->SetFollowID(0); + bot_iter->SetGuardMode(); } if (sbl.size() == 1) Bot::BotGroupSay(sbl.front(), "Guarding this position"); @@ -5055,7 +5049,11 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep) return; } - my_bot->Spawn(c); + if (!my_bot->Spawn(c)) { + c->Message(m_fail, "Failed to spawn bot '%s' (id: %i)", bot_name.c_str(), bot_id); + safe_delete(my_bot); + return; + } static const char* bot_spawn_message[16] = { "A solid weapon is my ally!", // WARRIOR / 'generic' @@ -5146,10 +5144,10 @@ void bot_subcommand_bot_summon(Client *c, const Seperator *sep) if (!bot_iter) continue; - Bot::BotGroupSay(bot_iter, "Whee!"); + //Bot::BotGroupSay(bot_iter, "Whee!"); bot_iter->WipeHateList(); - bot_iter->SetTarget(bot_iter->GetBotOwner()); + bot_iter->SetTarget(nullptr); bot_iter->Warp(glm::vec3(c->GetPosition())); bot_iter->DoAnim(0); @@ -5157,7 +5155,7 @@ void bot_subcommand_bot_summon(Client *c, const Seperator *sep) continue; bot_iter->GetPet()->WipeHateList(); - bot_iter->GetPet()->SetTarget(bot_iter); + bot_iter->GetPet()->SetTarget(nullptr); bot_iter->GetPet()->Warp(glm::vec3(c->GetPosition())); } @@ -5811,18 +5809,22 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep) return; } if (!leader_id) { - c->Message(m_fail, "Can not locate bot-group leader id for '%s'", botgroup_name_arg.c_str()); + c->Message(m_fail, "Cannot locate bot-group leader id for '%s'", botgroup_name_arg.c_str()); return; } auto botgroup_leader = Bot::LoadBot(leader_id); if (!botgroup_leader) { - c->Message(m_fail, "Could not spawn bot-group leader for '%s'", botgroup_name_arg.c_str()); + c->Message(m_fail, "Could not load bot-group leader for '%s'", botgroup_name_arg.c_str()); safe_delete(botgroup_leader); return; } - botgroup_leader->Spawn(c); + if (!botgroup_leader->Spawn(c)) { + c->Message(m_fail, "Could not spawn bot-group leader %s for '%s'", botgroup_leader->GetName(), botgroup_name_arg.c_str()); + safe_delete(botgroup_leader); + return; + } Group* group_inst = new Group(botgroup_leader); @@ -5841,7 +5843,12 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep) return; } - botgroup_member->Spawn(c); + if (!botgroup_member->Spawn(c)) { + c->Message(m_fail, "Could not spawn bot '%s' (id: %i)", botgroup_member->GetName(), member_iter); + safe_delete(botgroup_member); + return; + } + Bot::AddBotToGroup(botgroup_member, group_inst); } @@ -7078,7 +7085,6 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep) const EQEmu::ItemData* item = nullptr; bool is2Hweapon = false; - std::string item_link; EQEmu::SayLinkEngine linker; linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); @@ -7099,8 +7105,7 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep) } linker.SetItemInst(inst); - item_link = linker.GenerateLink(); - c->Message(m_message, "Using %s in my %s (slot %i)", item_link.c_str(), GetBotEquipSlotName(i), (i == 22 ? EQEmu::inventory::slotPowerSource : i)); + c->Message(m_message, "Using %s in my %s (slot %i)", linker.GenerateLink().c_str(), GetBotEquipSlotName(i), (i == 22 ? EQEmu::inventory::slotPowerSource : i)); ++inventory_count; } @@ -7243,8 +7248,8 @@ void bot_subcommand_inventory_window(Client *c, const Seperator *sep) std::string window_text; //std::string item_link; - //Client::TextLink linker; - //linker.SetLinkType(linker.linkItemInst); + //EQEmu::SayLinkEngine linker; + //linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= (EQEmu::legacy::EQUIPMENT_END + 1); ++i) { const EQEmu::ItemData* item = nullptr; diff --git a/zone/bot_database.cpp b/zone/bot_database.cpp index d8511c54c..4c5aabb82 100644 --- a/zone/bot_database.cpp +++ b/zone/bot_database.cpp @@ -273,7 +273,10 @@ bool BotDatabase::LoadBotID(const uint32 owner_id, const std::string& bot_name, if (!owner_id || bot_name.empty()) return false; - query = StringFormat("SELECT `bot_id` FROM `bot_data` WHERE `name` = '%s' LIMIT 1", bot_name.c_str()); + query = StringFormat( + "SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u' AND `name` = '%s' LIMIT 1", + owner_id, bot_name.c_str() + ); auto results = QueryDatabase(query); if (!results.Success()) return false; diff --git a/zone/client.cpp b/zone/client.cpp index 893a6b51b..cd2c7d478 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -215,7 +215,7 @@ Client::Client(EQStreamInterface* ieqs) linkdead_timer.Disable(); zonesummon_id = 0; zonesummon_ignorerestrictions = 0; - zoning = false; + bZoning = false; zone_mode = ZoneUnsolicited; casting_spell_id = 0; npcflag = false; @@ -254,7 +254,7 @@ Client::Client(EQStreamInterface* ieqs) mercSlot = 0; InitializeMercInfo(); SetMerc(0); - + if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true, false); logging_enabled = CLIENT_DEFAULT_LOGGING_ENABLED; //for good measure: @@ -336,6 +336,9 @@ Client::Client(EQStreamInterface* ieqs) for (int i = 0; i < InnateSkillMax; ++i) m_pp.InnateSkills[i] = InnateDisabled; + temp_pvp = false; + is_client_moving = false; + AI_Init(); } @@ -395,7 +398,7 @@ Client::~Client() { GetTarget()->IsTargeted(-1); //if we are in a group and we are not zoning, force leave the group - if(isgrouped && !zoning && is_zone_loaded) + if(isgrouped && !bZoning && is_zone_loaded) LeaveGroup(); UpdateWho(2); @@ -462,8 +465,8 @@ void Client::SendZoneInPackets() if (!GetHideMe()) entity_list.QueueClients(this, outapp, true); safe_delete(outapp); SetSpawned(); - if (GetPVP()) //force a PVP update until we fix the spawn struct - SendAppearancePacket(AT_PVP, GetPVP(), true, false); + if (GetPVP(false)) //force a PVP update until we fix the spawn struct + SendAppearancePacket(AT_PVP, GetPVP(false), true, false); //Send AA Exp packet: if (GetLevel() >= 51) @@ -1223,11 +1226,6 @@ void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num EffSkill = 100; cm->skill_in_language = EffSkill; - // Garble the message based on listener skill - if (ListenerSkill < 100) { - GarbleMessage(buffer, (100 - ListenerSkill)); - } - cm->chan_num = chan_num; strcpy(&cm->message[0], buffer); QueuePacket(&app); @@ -1960,7 +1958,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) ns->spawn.gm = GetGM() ? 1 : 0; ns->spawn.guildID = GuildID(); // ns->spawn.linkdead = IsLD() ? 1 : 0; -// ns->spawn.pvp = GetPVP() ? 1 : 0; +// ns->spawn.pvp = GetPVP(false) ? 1 : 0; ns->spawn.show_name = true; @@ -7580,7 +7578,27 @@ void Client::JoinGroupXTargets(Group *g) if (!g) return; + // test code for merge crashes - hopefully gcc won't optimize these out... + auto c1 = GetXTargetAutoMgr()->get_list().empty(); + auto c2 = GetXTargetAutoMgr()->get_list().size(); + auto c3 = GetXTargetAutoMgr()->get_list().begin(); + auto c4 = GetXTargetAutoMgr()->get_list().end(); + auto c5 = GetXTargetAutoMgr()->get_list().rbegin(); + auto c6 = GetXTargetAutoMgr()->get_list().rend(); + + auto g1 = g->GetXTargetAutoMgr()->get_list().empty(); + auto g2 = g->GetXTargetAutoMgr()->get_list().size(); + auto g3 = g->GetXTargetAutoMgr()->get_list().begin(); + auto g4 = g->GetXTargetAutoMgr()->get_list().end(); + auto g5 = g->GetXTargetAutoMgr()->get_list().rbegin(); + auto g6 = g->GetXTargetAutoMgr()->get_list().rend(); + if (!GetXTargetAutoMgr()->empty()) { + Log(Logs::Detail, Logs::Error, "XTarget Merge[clt] empty=%s, size=%u, (begin==end)=%s, (rbegin==rend)=%s", + (c1?"true":"false"), c2, (c3==c4?"true":"false"), (c5==c6?"true":"false")); + Log(Logs::Detail, Logs::Error, "XTarget Merge[grp] empty=%s, size=%u, (begin==end)=%s, (rbegin==rend)=%s", + (g1?"true":"false"), g2, (g3==g4?"true":"false"), (g5==g6?"true":"false")); + g->GetXTargetAutoMgr()->merge(*GetXTargetAutoMgr()); GetXTargetAutoMgr()->clear(); RemoveAutoXTargets(); @@ -7910,7 +7928,7 @@ void Client::GarbleMessage(char *message, uint8 variance) 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 += EQEmu::legacy::TEXT_LINK_BODY_LENGTH; } + if (!(delimiter_count & 1)) { i += EQEmu::constants::SayLinkBodySize; } ++delimiter_count; continue; } @@ -8894,9 +8912,9 @@ void Client::CheckRegionTypeChanges() return; if (last_region_type == RegionTypePVP) - SetPVP(true, false); - else if (GetPVP()) - SetPVP(false, false); + temp_pvp = true; + else if (temp_pvp) + temp_pvp = false; } void Client::ProcessAggroMeter() diff --git a/zone/client.h b/zone/client.h index 88622fcff..039844f82 100644 --- a/zone/client.h +++ b/zone/client.h @@ -395,7 +395,7 @@ public: void SetGM(bool toggle); void SetPVP(bool toggle, bool message = true); - inline bool GetPVP() const { return m_pp.pvp != 0; } + inline bool GetPVP(bool inc_temp = true) const { return m_pp.pvp != 0 || (inc_temp && temp_pvp); } inline bool GetGM() const { return m_pp.gm != 0; } inline void SetBaseClass(uint32 i) { m_pp.class_=i; } @@ -606,6 +606,10 @@ public: uint32 GetExperienceForKill(Mob *against); void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false); uint32 CalcEXP(uint8 conlevel = 0xFF); + void CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp); + void CalculateStandardAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp); + void CalculateLeadershipExp(uint32 &add_exp, uint8 conlevel); + void CalculateExp(uint32 in_add_exp, uint32 &add_exp, uint32 &add_aaxp, uint8 conlevel, bool resexp); void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false); void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0); void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp); @@ -651,6 +655,7 @@ public: void Sacrifice(Client* caster); void GoToDeath(); inline const int32 GetInstanceID() const { return zone->GetInstanceID(); } + void SetZoning(bool in) { bZoning = in; } FACTION_VALUE GetReverseFactionCon(Mob* iOther); FACTION_VALUE GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_race, uint32 p_class, uint32 p_deity, int32 pFaction, Mob* tnpc); @@ -1461,6 +1466,7 @@ private: PetInfo m_suspendedminion; // pet data for our suspended minion. MercInfo m_mercinfo[MAXMERCS]; // current mercenary InspectMessage_Struct m_inspect_message; + bool temp_pvp; void NPCSpawn(const Seperator* sep); uint32 GetEXPForLevel(uint16 level); @@ -1541,7 +1547,7 @@ private: bool npcflag; uint8 npclevel; bool feigned; - bool zoning; + bool bZoning; bool tgb; bool instalog; int32 last_reported_mana; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 8efe55f2b..fe8af2a98 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -72,6 +72,7 @@ extern PetitionList petition_list; extern EntityList entity_list; typedef void (Client::*ClientPacketProc)(const EQApplicationPacket *app); + //Use a map for connecting opcodes since it dosent get used a lot and is sparse std::map ConnectingOpcodes; //Use a static array for connected, for speed @@ -291,6 +292,7 @@ void MapOpcodes() ConnectedOpcodes[OP_MercenaryTimerRequest] = &Client::Handle_OP_MercenaryTimerRequest; ConnectedOpcodes[OP_MoveCoin] = &Client::Handle_OP_MoveCoin; ConnectedOpcodes[OP_MoveItem] = &Client::Handle_OP_MoveItem; + ConnectedOpcodes[OP_MoveMultipleItems] = &Client::Handle_OP_MoveMultipleItems; ConnectedOpcodes[OP_OpenContainer] = &Client::Handle_OP_OpenContainer; ConnectedOpcodes[OP_OpenGuildTributeMaster] = &Client::Handle_OP_OpenGuildTributeMaster; ConnectedOpcodes[OP_OpenInventory] = &Client::Handle_OP_OpenInventory; @@ -314,6 +316,7 @@ void MapOpcodes() ConnectedOpcodes[OP_PurchaseLeadershipAA] = &Client::Handle_OP_PurchaseLeadershipAA; ConnectedOpcodes[OP_PVPLeaderBoardDetailsRequest] = &Client::Handle_OP_PVPLeaderBoardDetailsRequest; ConnectedOpcodes[OP_PVPLeaderBoardRequest] = &Client::Handle_OP_PVPLeaderBoardRequest; + ConnectedOpcodes[OP_QueryUCSServerStatus] = &Client::Handle_OP_QueryUCSServerStatus; ConnectedOpcodes[OP_RaidInvite] = &Client::Handle_OP_RaidCommand; ConnectedOpcodes[OP_RandomReq] = &Client::Handle_OP_RandomReq; ConnectedOpcodes[OP_ReadBook] = &Client::Handle_OP_ReadBook; @@ -790,7 +793,7 @@ void Client::CompleteConnect() } if (zone) - zone->weatherSend(); + zone->weatherSend(this); TotalKarma = database.GetKarma(AccountID()); SendDisciplineTimers(); @@ -2860,41 +2863,60 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) DumpPacket(app); return; } + uint32 ApplyPoisonSuccessResult = 0; ApplyPoison_Struct* ApplyPoisonData = (ApplyPoison_Struct*)app->pBuffer; const EQEmu::ItemInstance* PrimaryWeapon = GetInv().GetItem(EQEmu::inventory::slotPrimary); const EQEmu::ItemInstance* SecondaryWeapon = GetInv().GetItem(EQEmu::inventory::slotSecondary); const EQEmu::ItemInstance* PoisonItemInstance = GetInv()[ApplyPoisonData->inventorySlot]; + const EQEmu::ItemData* poison=PoisonItemInstance->GetItem(); + const EQEmu::ItemData* primary=nullptr; + const EQEmu::ItemData* secondary=nullptr; + bool IsPoison = PoisonItemInstance && + (poison->ItemType == EQEmu::item::ItemTypePoison); - bool IsPoison = PoisonItemInstance && (PoisonItemInstance->GetItem()->ItemType == EQEmu::item::ItemTypePoison); - - if (!IsPoison) - { - Log(Logs::Detail, Logs::Spells, "Item used to cast spell effect from a poison item was missing from inventory slot %d " - "after casting, or is not a poison!", ApplyPoisonData->inventorySlot); - - Message(0, "Error: item not found for inventory slot #%i or is not a poison", ApplyPoisonData->inventorySlot); + if (PrimaryWeapon) { + primary=PrimaryWeapon->GetItem(); } - else if (GetClass() == ROGUE) - { - if ((PrimaryWeapon && PrimaryWeapon->GetItem()->ItemType == EQEmu::item::ItemType1HPiercing) || - (SecondaryWeapon && SecondaryWeapon->GetItem()->ItemType == EQEmu::item::ItemType1HPiercing)) { - float SuccessChance = (GetSkill(EQEmu::skills::SkillApplyPoison) + GetLevel()) / 400.0f; + + if (SecondaryWeapon) { + secondary=SecondaryWeapon->GetItem(); + } + + if (IsPoison && GetClass() == ROGUE) { + + // Live always checks for skillup, even when poison is too high + CheckIncreaseSkill(EQEmu::skills::SkillApplyPoison, nullptr, 10); + + if (poison->Proc.Level2 > GetLevel()) { + // Poison is too high to apply. + Message_StringID(clientMessageTradeskill, POISON_TOO_HIGH); + } + else if ((primary && + primary->ItemType == EQEmu::item::ItemType1HPiercing) || + (secondary && + secondary->ItemType == EQEmu::item::ItemType1HPiercing)) { + double ChanceRoll = zone->random.Real(0, 1); - CheckIncreaseSkill(EQEmu::skills::SkillApplyPoison, nullptr, 10); + // Poisons that use this skill (old world poisons) almost + // never fail to apply. I did 25 applies of a trivial 120+ + // poison with an apply skill of 48 and they all worked. + // Also did 25 straight poisons at apply skill 248 for very + // high end and they never failed. + // Apply poison ranging from 1-9, 28/30 worked for a level 18.. + // Poisons that don't proc until a level higher than the + // rogue simply won't apply at all, no skill check done. - if (ChanceRoll < SuccessChance) { + if (ChanceRoll < (.9 + GetLevel()/1000)) { ApplyPoisonSuccessResult = 1; - // NOTE: Someone may want to tweak the chance to proc the poison effect that is added to the weapon here. - // My thinking was that DEX should be apart of the calculation. - AddProcToWeapon(PoisonItemInstance->GetItem()->Proc.Effect, false, (GetDEX() / 100) + 103); + AddProcToWeapon(poison->Proc.Effect, false, + (GetDEX() / 100) + 103); } - - DeleteItemInInventory(ApplyPoisonData->inventorySlot, 1, true); - - Log(Logs::General, Logs::None, "Chance to Apply Poison was %f. Roll was %f. Result is %u.", SuccessChance, ChanceRoll, ApplyPoisonSuccessResult); } + + // Live always deletes the item, success or failure. Even if too high. + DeleteItemInInventory(ApplyPoisonData->inventorySlot, 1, true); } auto outapp = new EQApplicationPacket(OP_ApplyPoison, nullptr, sizeof(ApplyPoison_Struct)); @@ -3959,12 +3981,23 @@ void Client::Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app) void Client::Handle_OP_Bug(const EQApplicationPacket *app) { - if (app->size != sizeof(BugStruct)) - printf("Wrong size of BugStruct got %d expected %zu!\n", app->size, sizeof(BugStruct)); - else { - BugStruct* bug = (BugStruct*)app->pBuffer; - database.UpdateBug(bug); + if (!RuleB(Bugs, ReportingSystemActive)) { + Message(0, "Bug reporting is disabled on this server."); + return; } + + if (app->size != sizeof(BugReport_Struct)) { + printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct)); + } + else { + BugReport_Struct* bug_report = (BugReport_Struct*)app->pBuffer; + + if (RuleB(Bugs, UseOldReportingMethod)) + database.RegisterBug(bug_report); + else + database.RegisterBug(this, bug_report); + } + return; } @@ -4401,7 +4434,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) return; } - auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, ppu->delta_heading); + auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); boat->SetDelta(boat_delta); auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); @@ -4411,7 +4444,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) safe_delete(outapp); /* Update the boat's position on the server, without sending an update */ - boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ19toFloat(ppu->heading), false); + boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false); return; } else return; @@ -4556,7 +4589,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) } /* Update internal state */ - m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, ppu->delta_heading); + m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); if (IsTracking() && ((m_Position.x != ppu->x_pos) || (m_Position.y != ppu->y_pos))) { if (zone->random.Real(0, 100) < 70)//should be good @@ -4609,7 +4642,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) } } - float new_heading = EQ19toFloat(ppu->heading); + float new_heading = EQ12toFloat(ppu->heading); int32 new_animation = ppu->animation; /* Update internal server position from what the client has sent */ @@ -4628,7 +4661,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) if (is_client_moving || new_heading != m_Position.w || new_animation != animation) { animation = ppu->animation; - m_Position.w = EQ19toFloat(ppu->heading); + m_Position.w = EQ12toFloat(ppu->heading); /* Broadcast update to other clients */ auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); @@ -9855,6 +9888,11 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) return; } +void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app) +{ + Kick(); // TODO: lets not desync though +} + void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app) { // Does not exist in Ti client @@ -9954,22 +9992,18 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) Mob* mypet = this->GetPet(); Mob *target = entity_list.GetMob(pet->target); - if (!mypet || pet->command == PET_LEADER) - { - if (pet->command == PET_LEADER) - { - if (mypet && (!GetTarget() || GetTarget() == mypet)) - { + if (!mypet || pet->command == PET_LEADER) { + if (pet->command == PET_LEADER) { + // we either send the ID of an NPC we're interested in or no ID for our own pet + if (target) { + auto owner = target->GetOwner(); + if (owner) + target->Say_StringID(PET_LEADERIS, owner->GetCleanName()); + else + target->Say_StringID(I_FOLLOW_NOONE); + } else if (mypet) { mypet->Say_StringID(PET_LEADERIS, GetName()); } - else if ((mypet = GetTarget())) - { - Mob *Owner = mypet->GetOwner(); - if (Owner) - mypet->Say_StringID(PET_LEADERIS, Owner->GetCleanName()); - else if (mypet->IsNPC()) - mypet->Say_StringID(I_FOLLOW_NOONE); - } } return; @@ -10551,11 +10585,8 @@ void Client::Handle_OP_Petition(const EQApplicationPacket *app) void Client::Handle_OP_PetitionBug(const EQApplicationPacket *app) { - if (app->size != sizeof(PetitionBug_Struct)) - printf("Wrong size of BugStruct! Expected: %zu, Got: %i\n", sizeof(PetitionBug_Struct), app->size); - else { - Message(0, "Petition Bugs are not supported, please use /bug."); - } + Message(0, "Petition Bugs are not supported, please use /bug."); + return; } @@ -10975,6 +11006,84 @@ void Client::Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app) safe_delete(outapp); } +void Client::Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app) +{ + if (zone->IsUCSServerAvailable()) { + EQApplicationPacket* outapp = nullptr; + std::string buffer; + + std::string MailKey = database.GetMailKey(CharacterID(), true); + EQEmu::versions::UCSVersion ConnectionType = EQEmu::versions::ucsUnknown; + + // chat server packet + switch (ClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + ConnectionType = EQEmu::versions::ucsTitaniumChat; + break; + case EQEmu::versions::ClientVersion::SoF: + ConnectionType = EQEmu::versions::ucsSoFCombined; + break; + case EQEmu::versions::ClientVersion::SoD: + ConnectionType = EQEmu::versions::ucsSoDCombined; + break; + case EQEmu::versions::ClientVersion::UF: + ConnectionType = EQEmu::versions::ucsUFCombined; + break; + case EQEmu::versions::ClientVersion::RoF: + ConnectionType = EQEmu::versions::ucsRoFCombined; + break; + case EQEmu::versions::ClientVersion::RoF2: + ConnectionType = EQEmu::versions::ucsRoF2Combined; + break; + default: + ConnectionType = EQEmu::versions::ucsUnknown; + break; + } + + buffer = StringFormat("%s,%i,%s.%s,%c%s", + Config->ChatHost.c_str(), + Config->ChatPort, + Config->ShortName.c_str(), + GetName(), + ConnectionType, + MailKey.c_str() + ); + + outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; + + QueuePacket(outapp); + safe_delete(outapp); + + // mail server packet + switch (ClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + ConnectionType = EQEmu::versions::ucsTitaniumMail; + break; + default: + // retain value from previous switch + break; + } + + buffer = StringFormat("%s,%i,%s.%s,%c%s", + Config->MailHost.c_str(), + Config->MailPort, + Config->ShortName.c_str(), + GetName(), + ConnectionType, + MailKey.c_str() + ); + + outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; + + QueuePacket(outapp); + safe_delete(outapp); + } +} + void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) { if (app->size < sizeof(RaidGeneral_Struct)) { @@ -11684,10 +11793,24 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app) // make where clause segment for container(s) std::string containers; - if (tsf->some_id == 0) + uint32 combineObjectSlots; + if (tsf->some_id == 0) { containers += StringFormat(" = %u ", tsf->object_type); // world combiner so no item number - else + combineObjectSlots = 10; + } + else { containers += StringFormat(" in (%u, %u) ", tsf->object_type, tsf->some_id); // container in inventory + auto item = database.GetItem(tsf->some_id); + if (!item) + { + Log(Logs::General, Logs::Error, "Invalid container ID: %d. GetItem returned null. Defaulting to BagSlots = 10.\n", tsf->some_id); + combineObjectSlots = 10; + } + else + { + combineObjectSlots = item->BagSlots; + } + } std::string favoriteIDs; //gotta be big enough for 500 IDs bool first = true; @@ -11719,8 +11842,8 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app) "((tr.must_learn & 0x3 <> 0 AND crl.madecount IS NOT NULL) " "OR (tr.must_learn & 0x3 = 0)) " "GROUP BY tr.id " - "HAVING sum(if(tre.item_id %s AND tre.iscontainer > 0,1,0)) > 0 " - "LIMIT 100 ", CharacterID(), favoriteIDs.c_str(), containers.c_str()); + "HAVING sum(if(tre.item_id %s AND tre.iscontainer > 0,1,0)) > 0 AND SUM(tre.componentcount) <= %u " + "LIMIT 100 ", CharacterID(), favoriteIDs.c_str(), containers.c_str(), combineObjectSlots); TradeskillSearchResults(query, tsf->object_type, tsf->some_id); return; @@ -11742,13 +11865,25 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app) // make where clause segment for container(s) char containers[30]; + uint32 combineObjectSlots; if (rss->some_id == 0) { // world combiner so no item number snprintf(containers, 29, "= %u", rss->object_type); + combineObjectSlots = 10; } else { // container in inventory snprintf(containers, 29, "in (%u,%u)", rss->object_type, rss->some_id); + auto item = database.GetItem(rss->some_id); + if (!item) + { + Log(Logs::General, Logs::Error, "Invalid container ID: %d. GetItem returned null. Defaulting to BagSlots = 10.\n", rss->some_id); + combineObjectSlots = 10; + } + else + { + combineObjectSlots = item->BagSlots; + } } std::string searchClause; @@ -11773,10 +11908,10 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app) "AND crl.madecount IS NOT NULL) " "OR (tr.must_learn & 0x3 = 0)) " "GROUP BY tr.id " - "HAVING sum(if(tre.item_id %s AND tre.iscontainer > 0,1,0)) > 0 " + "HAVING sum(if(tre.item_id %s AND tre.iscontainer > 0,1,0)) > 0 AND SUM(tre.componentcount) <= %u " "LIMIT 200 ", CharacterID(), searchClause.c_str(), - rss->mintrivial, rss->maxtrivial, containers); + rss->mintrivial, rss->maxtrivial, containers, combineObjectSlots); TradeskillSearchResults(query, rss->object_type, rss->some_id); return; } diff --git a/zone/client_packet.h b/zone/client_packet.h index c63a57825..4f9902599 100644 --- a/zone/client_packet.h +++ b/zone/client_packet.h @@ -204,6 +204,7 @@ void Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app); void Handle_OP_MoveCoin(const EQApplicationPacket *app); void Handle_OP_MoveItem(const EQApplicationPacket *app); + void Handle_OP_MoveMultipleItems(const EQApplicationPacket *app); void Handle_OP_OpenContainer(const EQApplicationPacket *app); void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app); void Handle_OP_OpenInventory(const EQApplicationPacket *app); @@ -227,6 +228,7 @@ void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app); void Handle_OP_PVPLeaderBoardDetailsRequest(const EQApplicationPacket *app); void Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app); + void Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app); void Handle_OP_RaidCommand(const EQApplicationPacket *app); void Handle_OP_RandomReq(const EQApplicationPacket *app); void Handle_OP_ReadBook(const EQApplicationPacket *app); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index a0bdeead2..c5801044f 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -264,13 +264,21 @@ bool Client::Process() { if (distance <= scan_range) { close_mobs.insert(std::pair(mob, distance)); } - else if (mob->GetAggroRange() > scan_range) { + else if ((mob->GetAggroRange() * mob->GetAggroRange()) > scan_range) { close_mobs.insert(std::pair(mob, distance)); } } - if (force_spawn_updates && mob != this && distance <= client_update_range) - mob->SendPositionUpdateToClient(this); + if (force_spawn_updates && mob != this) { + + if (mob->is_distance_roamer) { + mob->SendPositionUpdateToClient(this); + continue; + } + + if (distance <= client_update_range) + mob->SendPositionUpdateToClient(this); + } } } @@ -647,17 +655,17 @@ bool Client::Process() { { //client logged out or errored out //ResetTrade(); - if (client_state != CLIENT_KICKED && !zoning && !instalog) { + if (client_state != CLIENT_KICKED && !bZoning && !instalog) { Save(); } client_state = CLIENT_LINKDEAD; - if (zoning || instalog || GetGM()) + if (bZoning || instalog || GetGM()) { Group *mygroup = GetGroup(); if (mygroup) { - if (!zoning) + if (!bZoning) { entity_list.MessageGroup(this, true, 15, "%s logged out.", GetName()); LeaveGroup(); @@ -676,7 +684,7 @@ bool Client::Process() { Raid *myraid = entity_list.GetRaidByClient(this); if (myraid) { - if (!zoning) + if (!bZoning) { //entity_list.MessageGroup(this,true,15,"%s logged out.",GetName()); myraid->MemberZoned(this); @@ -879,7 +887,7 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { uint8 handychance = 0; for (itr = merlist.begin(); itr != merlist.end() && i <= numItemSlots; ++itr) { MerchantList ml = *itr; - if (merch->CastToNPC()->GetMerchantProbability() > ml.probability) + if (ml.probability != 100 && zone->random.Int(1, 100) > ml.probability) continue; if (GetLevel() < ml.level_required) @@ -1055,7 +1063,8 @@ void Client::OPRezzAnswer(uint32 Action, uint32 SpellID, uint16 ZoneID, uint16 I SetMana(0); SetHP(GetMaxHP()/5); int rez_eff = 756; - if (GetRace() == BARBARIAN || GetRace() == DWARF || GetRace() == TROLL || GetRace() == OGRE) + if (RuleB(Character, UseOldRaceRezEffects) && + (GetRace() == BARBARIAN || GetRace() == DWARF || GetRace() == TROLL || GetRace() == OGRE)) rez_eff = 757; SpellOnTarget(rez_eff, this); // Rezz effects } @@ -1951,57 +1960,40 @@ void Client::CalcRestState() { void Client::DoTracking() { - if(TrackingID == 0) + if (TrackingID == 0) return; Mob *m = entity_list.GetMob(TrackingID); - if(!m || m->IsCorpse()) - { + if (!m || m->IsCorpse()) { Message_StringID(MT_Skills, TRACK_LOST_TARGET); - TrackingID = 0; - return; } float RelativeHeading = GetHeading() - CalculateHeadingToTarget(m->GetX(), m->GetY()); - if(RelativeHeading < 0) - RelativeHeading += 256; + if (RelativeHeading < 0) + RelativeHeading += 512; - if((RelativeHeading <= 16) || (RelativeHeading >= 240)) - { + if (RelativeHeading > 480) Message_StringID(MT_Skills, TRACK_STRAIGHT_AHEAD, m->GetCleanName()); - } - else if((RelativeHeading > 16) && (RelativeHeading <= 48)) - { - Message_StringID(MT_Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "right"); - } - else if((RelativeHeading > 48) && (RelativeHeading <= 80)) - { - Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "right"); - } - else if((RelativeHeading > 80) && (RelativeHeading <= 112)) - { - Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "right"); - } - else if((RelativeHeading > 112) && (RelativeHeading <= 144)) - { - Message_StringID(MT_Skills, TRACK_BEHIND_YOU, m->GetCleanName()); - } - else if((RelativeHeading > 144) && (RelativeHeading <= 176)) - { - Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "left"); - } - else if((RelativeHeading > 176) && (RelativeHeading <= 208)) - { - Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "left"); - } - else if((RelativeHeading > 208) && (RelativeHeading < 240)) - { + else if (RelativeHeading > 416) Message_StringID(MT_Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "left"); - } + else if (RelativeHeading > 352) + Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "left"); + else if (RelativeHeading > 288) + Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "left"); + else if (RelativeHeading > 224) + Message_StringID(MT_Skills, TRACK_BEHIND_YOU, m->GetCleanName()); + else if (RelativeHeading > 160) + Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "right"); + else if (RelativeHeading > 96) + Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "right"); + else if (RelativeHeading > 32) + Message_StringID(MT_Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "right"); + else if (RelativeHeading >= 0) + Message_StringID(MT_Skills, TRACK_STRAIGHT_AHEAD, m->GetCleanName()); } void Client::HandleRespawnFromHover(uint32 Option) diff --git a/zone/command.cpp b/zone/command.cpp index a65f9005e..ea1681566 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -67,10 +67,12 @@ #include "titles.h" #include "water_map.h" #include "worldserver.h" +#include "fastmath.h" extern QueryServ* QServ; extern WorldServer worldserver; extern TaskManager *taskmanager; +extern FastMath g_Math; void CatchSignal(int sig_num); @@ -292,7 +294,7 @@ int command_init(void) #endif command_add("path", "- view and edit pathing", 200, command_path) || - command_add("peekinv", "[worn/inv/cursor/trib/bank/trade/world/all] - Print out contents of your player target's inventory", 100, command_peekinv) || + command_add("peekinv", "[equip/gen/cursor/poss/limbo/curlim/trib/bank/shbank/allbank/trade/world/all] - Print out contents of your player target's inventory", 100, command_peekinv) || command_add("peqzone", "[zonename] - Go to specified zone, if you have > 75% health", 0, command_peqzone) || command_add("permaclass", "[classnum] - Change your or your player target's class (target is disconnected)", 80, command_permaclass) || command_add("permagender", "[gendernum] - Change your or your player target's gender (zone to take effect)", 80, command_permagender) || @@ -306,6 +308,7 @@ int command_init(void) command_add("profilereset", "- Reset profiling info", 250, command_profilereset) || #endif + command_add("push", "Lets you do spell push", 150, command_push) || command_add("pvp", "[on/off] - Set your or your player target's PVP status", 100, command_pvp) || command_add("qglobal", "[on/off/view] - Toggles qglobal functionality on an NPC", 100, command_qglobal) || command_add("questerrors", "Shows quest errors.", 100, command_questerrors) || @@ -317,6 +320,7 @@ int command_init(void) command_add("reloadallrules", "Executes a reload of all rules.", 80, command_reloadallrules) || command_add("reloademote", "Reloads NPC Emotes", 80, command_reloademote) || command_add("reloadlevelmods", nullptr, 255, command_reloadlevelmods) || + command_add("reloadmerchants", nullptr, 255, command_reloadmerchants) || command_add("reloadperlexportsettings", nullptr, 255, command_reloadperlexportsettings) || command_add("reloadqst", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) || command_add("reloadrulesworld", "Executes a reload of all rules in world specifically.", 80, command_reloadworldrules) || @@ -357,9 +361,11 @@ int command_init(void) command_add("showbonusstats", "[item|spell|all] Shows bonus stats for target from items or spells. Shows both by default.", 50, command_showbonusstats) || command_add("showbuffs", "- List buffs active on your target or you if no target", 50, command_showbuffs) || command_add("shownumhits", "Shows buffs numhits for yourself.", 0, command_shownumhits) || + command_add("shownpcgloballoot", "Show GlobalLoot entires on this npc", 50, command_shownpcgloballoot) || command_add("showskills", "- Show the values of your or your player target's skills", 50, command_showskills) || command_add("showspellslist", "Shows spell list of targeted NPC", 100, command_showspellslist) || command_add("showstats", "- Show details about you or your target", 50, command_showstats) || + command_add("showzonegloballoot", "Show GlobalLoot entires on this zone", 50, command_showzonegloballoot) || command_add("shutdown", "- Shut this zone process down", 150, command_shutdown) || command_add("size", "[size] - Change size of you or your target", 50, command_size) || command_add("spawn", "[name] [race] [level] [material] [hp] [gender] [class] [priweapon] [secweapon] [merchantid] - Spawn an NPC", 10, command_spawn) || @@ -376,6 +382,7 @@ int command_init(void) command_add("task", "(subcommand) - Task system commands", 150, command_task) || command_add("tattoo", "- Change the tattoo of your target (Drakkin Only)", 80, command_tattoo) || command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", 100, command_tempname) || + command_add("petname", "[newname] - Temporarily renames your pet. Leave name blank to restore the original name.", 100, command_petname) || command_add("texture", "[texture] [helmtexture] - Change your or your target's appearance, use 255 to show equipment", 10, command_texture) || command_add("time", "[HH] [MM] - Set EQ time", 90, command_time) || command_add("timers", "- Display persistent timers for target", 200, command_timers) || @@ -385,6 +392,7 @@ int command_init(void) command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", 150, command_traindisc) || command_add("trapinfo", "- Gets infomation about the traps currently spawned in the zone.", 81, command_trapinfo) || command_add("tune", "Calculate ideal statical values related to combat.", 100, command_tune) || + command_add("ucs", "- Attempts to reconnect to the UCS server", 0, command_ucs) || command_add("undyeme", "- Remove dye from all of your armor slots", 0, command_undyeme) || command_add("unfreeze", "- Unfreeze your target", 80, command_unfreeze) || command_add("unlock", "- Unlock the worldserver", 150, command_unlock) || @@ -2318,14 +2326,18 @@ void command_race(Client *c, const Seperator *sep) { Mob *t=c->CastToMob(); - // Need to figure out max race for LoY/LDoN: going with upper bound of 500 now for testing - if (sep->IsNumber(1) && atoi(sep->arg[1]) >= 0 && atoi(sep->arg[1]) <= 724) { - if ((c->GetTarget()) && c->Admin() >= commandRaceOthers) - t=c->GetTarget(); - t->SendIllusionPacket(atoi(sep->arg[1])); + if (sep->IsNumber(1)) { + auto race = atoi(sep->arg[1]); + if ((race >= 0 && race <= 732) || (race >= 2253 && race <= 2259)) { + if ((c->GetTarget()) && c->Admin() >= commandRaceOthers) + t = c->GetTarget(); + t->SendIllusionPacket(race); + } else { + c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)"); + } + } else { + c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)"); } - else - c->Message(0, "Usage: #race [0-724] (0 for back to normal)"); } void command_gender(Client *c, const Seperator *sep) @@ -2456,7 +2468,9 @@ void command_npctypespawn(Client *c, const Seperator *sep) if (npc && sep->IsNumber(2)) npc->SetNPCFactionID(atoi(sep->arg[2])); - npc->AddLootTable(); + npc->AddLootTable(); + if (npc->DropsGlobalLoot()) + npc->CheckGlobalLootTables(); entity_list.AddNPC(npc); } else @@ -2506,244 +2520,347 @@ void command_nukeitem(Client *c, const Seperator *sep) void command_peekinv(Client *c, const Seperator *sep) { + // this can be cleaned up once inventory is cleaned up enum { - peekWorn = 0x01, - peekInv = 0x02, - peekCursor = 0x04, - peekTrib = 0x08, - peekBank = 0x10, - peekTrade = 0x20, - peekWorld = 0x40 - } ; + peekNone = 0x0000, + peekEquip = 0x0001, + peekGen = 0x0002, + peekCursor = 0x0004, + peekLimbo = 0x0008, + peekTrib = 0x0010, + peekBank = 0x0020, + peekShBank = 0x0040, + peekTrade = 0x0080, + peekWorld = 0x0100, + peekOutOfScope = (peekWorld * 2) // less than + }; - if (!c->GetTarget() || !c->GetTarget()->IsClient()) { - c->Message(0, "You must have a PC target selected for this command"); + static char* scope_prefix[] = { "Equip", "Gen", "Cursor", "Limbo", "Trib", "Bank", "ShBank", "Trade", "World" }; + + static int16 scope_range[][2] = { + { EQEmu::legacy::EQUIPMENT_BEGIN, EQEmu::legacy::EQUIPMENT_END }, + { EQEmu::legacy::GENERAL_BEGIN, EQEmu::legacy::GENERAL_END }, + { EQEmu::legacy::SLOT_CURSOR, EQEmu::legacy::SLOT_CURSOR }, + { EQEmu::legacy::SLOT_INVALID, EQEmu::legacy::SLOT_INVALID }, + { EQEmu::legacy::TRIBUTE_BEGIN, EQEmu::legacy::TRIBUTE_END }, + { EQEmu::legacy::BANK_BEGIN, EQEmu::legacy::BANK_END }, + { EQEmu::legacy::SHARED_BANK_BEGIN, EQEmu::legacy::SHARED_BANK_END }, + { EQEmu::legacy::TRADE_BEGIN, EQEmu::legacy::TRADE_END }, + { EQEmu::inventory::slotBegin, (EQEmu::legacy::WORLD_SIZE - 1) } + }; + + static bool scope_bag[] = { false, true, true, true, false, true, true, true, true }; + + if (!c) + return; + + if (c->GetTarget() && !c->GetTarget()->IsClient()) { + c->Message(0, "You must target a PC for this command."); return; } - int scopeWhere = 0; + int scopeMask = peekNone; - if (strcasecmp(sep->arg[1], "all") == 0) { scopeWhere = ~0; } - else if (strcasecmp(sep->arg[1], "worn") == 0) { scopeWhere |= peekWorn; } - else if (strcasecmp(sep->arg[1], "inv") == 0) { scopeWhere |= peekInv; } - else if (strcasecmp(sep->arg[1], "cursor") == 0) { scopeWhere |= peekCursor; } - else if (strcasecmp(sep->arg[1], "trib") == 0) { scopeWhere |= peekTrib; } - else if (strcasecmp(sep->arg[1], "bank") == 0) { scopeWhere |= peekBank; } - else if (strcasecmp(sep->arg[1], "trade") == 0) { scopeWhere |= peekTrade; } - else if (strcasecmp(sep->arg[1], "world") == 0) { scopeWhere |= peekWorld; } + if (strcasecmp(sep->arg[1], "all") == 0) { scopeMask = (peekOutOfScope - 1); } + else if (strcasecmp(sep->arg[1], "equip") == 0) { scopeMask |= peekEquip; } + else if (strcasecmp(sep->arg[1], "gen") == 0) { scopeMask |= peekGen; } + else if (strcasecmp(sep->arg[1], "cursor") == 0) { scopeMask |= peekCursor; } + else if (strcasecmp(sep->arg[1], "poss") == 0) { scopeMask |= (peekEquip | peekGen | peekCursor); } + else if (strcasecmp(sep->arg[1], "limbo") == 0) { scopeMask |= peekLimbo; } + else if (strcasecmp(sep->arg[1], "curlim") == 0) { scopeMask |= (peekCursor | peekLimbo); } + else if (strcasecmp(sep->arg[1], "trib") == 0) { scopeMask |= peekTrib; } + else if (strcasecmp(sep->arg[1], "bank") == 0) { scopeMask |= peekBank; } + else if (strcasecmp(sep->arg[1], "shbank") == 0) { scopeMask |= peekShBank; } + else if (strcasecmp(sep->arg[1], "allbank") == 0) { scopeMask |= (peekBank | peekShBank); } + else if (strcasecmp(sep->arg[1], "trade") == 0) { scopeMask |= peekTrade; } + else if (strcasecmp(sep->arg[1], "world") == 0) { scopeMask |= peekWorld; } - if (scopeWhere == 0) { - c->Message(0, "Usage: #peekinv [worn|inv|cursor|trib|bank|trade|world|all]"); - c->Message(0, " Displays a portion of the targeted user's inventory"); - c->Message(0, " Caution: 'all' is a lot of information!"); + if (!scopeMask) { + c->Message(0, "Usage: #peekinv [equip|gen|cursor|poss|limbo|curlim|trib|bank|shbank|allbank|trade|world|all]"); + c->Message(0, "- Displays a portion of the targeted user's inventory"); + c->Message(0, "- Caution: 'all' is a lot of information!"); return; } - Client* targetClient = c->GetTarget()->CastToClient(); + Client* targetClient = c; + if (c->GetTarget()) + targetClient = c->GetTarget()->CastToClient(); + const EQEmu::ItemInstance* inst_main = nullptr; const EQEmu::ItemInstance* inst_sub = nullptr; + const EQEmu::ItemInstance* inst_aug = nullptr; const EQEmu::ItemData* item_data = nullptr; - std::string item_link; + EQEmu::SayLinkEngine linker; linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); - c->Message(0, "Displaying inventory for %s...", targetClient->GetName()); + c->Message(0, "Displaying inventory for %s...", targetClient->GetName()); - // worn - for (int16 indexMain = EQEmu::legacy::EQUIPMENT_BEGIN; (scopeWhere & peekWorn) && (indexMain <= EQEmu::legacy::EQUIPMENT_END); ++indexMain) { - inst_main = targetClient->GetInv().GetItem(indexMain); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); + Object* objectTradeskill = targetClient->GetTradeskillObject(); - item_link = linker.GenerateLink(); + bool itemsFound = false; - c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - } + for (int scopeIndex = 0, scopeBit = peekEquip; scopeBit < peekOutOfScope; ++scopeIndex, scopeBit <<= 1) { + if (scopeBit & ~scopeMask) + continue; - if ((scopeWhere & peekWorn) && (targetClient->ClientVersion() >= EQEmu::versions::ClientVersion::SoF)) { - inst_main = targetClient->GetInv().GetItem(EQEmu::inventory::slotPowerSource); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", - EQEmu::inventory::slotPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - } - - // inv - for (int16 indexMain = EQEmu::legacy::GENERAL_BEGIN; (scopeWhere & peekInv) && (indexMain <= EQEmu::legacy::GENERAL_END); ++indexMain) { - inst_main = targetClient->GetInv().GetItem(indexMain); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), "InvSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - - for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) { - inst_sub = inst_main->GetItem(indexSub); - item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); - linker.SetItemInst(inst_sub); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), " InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); + if (scopeBit & peekWorld) { + if (objectTradeskill == nullptr) { + c->Message(1, "No world tradeskill object selected..."); + continue; + } + else { + c->Message(0, "[WorldObject DBID: %i (entityid: %i)]", objectTradeskill->GetDBID(), objectTradeskill->GetID()); + } } - } - // cursor - if (scopeWhere & peekCursor) { - if (targetClient->GetInv().CursorEmpty()) { - linker.SetItemInst(nullptr); + for (int16 indexMain = scope_range[scopeIndex][0]; indexMain <= scope_range[scopeIndex][1]; ++indexMain) { + if (indexMain == EQEmu::legacy::SLOT_INVALID) + continue; - item_link = linker.GenerateLink(); + inst_main = ((scopeBit & peekWorld) ? objectTradeskill->GetItem(indexMain) : targetClient->GetInv().GetItem(indexMain)); + if (inst_main) { + itemsFound = true; + item_data = inst_main->GetItem(); + } + else { + item_data = nullptr; + } - c->Message(1, "CursorSlot: %i, Item: %i (%s), Charges: %i", - EQEmu::inventory::slotCursor, 0, item_link.c_str(), 0); + linker.SetItemInst(inst_main); + + c->Message( + (item_data == nullptr), + "%sSlot: %i, Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + ((scopeBit & peekWorld) ? (EQEmu::legacy::WORLD_BEGIN + indexMain) : indexMain), + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_main == nullptr) ? 0 : inst_main->GetCharges()) + ); + + if (inst_main && inst_main->IsClassCommon()) { + for (uint8 indexAug = EQEmu::inventory::socketBegin; indexAug < EQEmu::inventory::SocketCount; ++indexAug) { + inst_aug = inst_main->GetItem(indexAug); + if (!inst_aug) // extant only + continue; + + item_data = inst_aug->GetItem(); + linker.SetItemInst(inst_aug); + + c->Message( + (item_data == nullptr), + ".%sAugSlot: %i (Slot #%i, Aug idx #%i), Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + INVALID_INDEX, + ((scopeBit & peekWorld) ? (EQEmu::legacy::WORLD_BEGIN + indexMain) : indexMain), + indexAug, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()) + ); + } + } + + if (!scope_bag[scopeIndex] || !(inst_main && inst_main->IsClassBag())) + continue; + + for (uint8 indexSub = EQEmu::inventory::containerBegin; indexSub < EQEmu::inventory::ContainerCount; ++indexSub) { + inst_sub = inst_main->GetItem(indexSub); + if (!inst_sub) // extant only + continue; + + item_data = inst_sub->GetItem(); + linker.SetItemInst(inst_sub); + + c->Message( + (item_data == nullptr), + "..%sBagSlot: %i (Slot #%i, Bag idx #%i), Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + ((scopeBit & peekWorld) ? INVALID_INDEX : EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub)), + ((scopeBit & peekWorld) ? (EQEmu::legacy::WORLD_BEGIN + indexMain) : indexMain), + indexSub, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()) + ); + + if (inst_sub->IsClassCommon()) { + for (uint8 indexAug = EQEmu::inventory::socketBegin; indexAug < EQEmu::inventory::SocketCount; ++indexAug) { + inst_aug = inst_sub->GetItem(indexAug); + if (!inst_aug) // extant only + continue; + + item_data = inst_aug->GetItem(); + linker.SetItemInst(inst_aug); + + c->Message( + (item_data == nullptr), + "...%sAugSlot: %i (Slot #%i, Sub idx #%i, Aug idx #%i), Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + INVALID_INDEX, + ((scopeBit & peekWorld) ? INVALID_INDEX : EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub)), + indexSub, + indexAug, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()) + ); + } + } + } } - else { - int cursorDepth = 0; - for (auto it = targetClient->GetInv().cursor_cbegin(); (it != targetClient->GetInv().cursor_cend()); ++it, ++cursorDepth) { + + if ((scopeBit & peekEquip) && (targetClient->ClientVersion() >= EQEmu::versions::ClientVersion::SoF)) { + inst_main = targetClient->GetInv().GetItem(EQEmu::inventory::slotPowerSource); + if (inst_main) { + itemsFound = true; + item_data = inst_main->GetItem(); + } + else { + item_data = nullptr; + } + + linker.SetItemInst(inst_main); + + c->Message( + (item_data == nullptr), + "%sSlot: %i, Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + EQEmu::inventory::slotPowerSource, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_main == nullptr) ? 0 : inst_main->GetCharges()) + ); + + if (inst_main && inst_main->IsClassCommon()) { + for (uint8 indexAug = EQEmu::inventory::socketBegin; indexAug < EQEmu::inventory::SocketCount; ++indexAug) { + inst_aug = inst_main->GetItem(indexAug); + if (!inst_aug) // extant only + continue; + + item_data = inst_aug->GetItem(); + linker.SetItemInst(inst_aug); + + c->Message( + (item_data == nullptr), + ".%sAugSlot: %i (Slot #%i, Aug idx #%i), Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + INVALID_INDEX, + EQEmu::inventory::slotPowerSource, + indexAug, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()) + ); + } + } + } + + if (scopeBit & peekLimbo) { + int limboIndex = 0; + for (auto it = targetClient->GetInv().cursor_cbegin(); (it != targetClient->GetInv().cursor_cend()); ++it, ++limboIndex) { + if (it == targetClient->GetInv().cursor_cbegin()) + continue; + inst_main = *it; - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + if (inst_main) { + itemsFound = true; + item_data = inst_main->GetItem(); + } + else { + item_data = nullptr; + } + linker.SetItemInst(inst_main); - item_link = linker.GenerateLink(); + c->Message( + (item_data == nullptr), + "%sSlot: %i, Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + (8000 + limboIndex), + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_main == nullptr) ? 0 : inst_main->GetCharges()) + ); - c->Message((item_data == nullptr), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i", - EQEmu::inventory::slotCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); + if (inst_main && inst_main->IsClassCommon()) { + for (uint8 indexAug = EQEmu::inventory::socketBegin; indexAug < EQEmu::inventory::SocketCount; ++indexAug) { + inst_aug = inst_main->GetItem(indexAug); + if (!inst_aug) // extant only + continue; - for (uint8 indexSub = EQEmu::inventory::containerBegin; (cursorDepth == 0) && inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) { + item_data = inst_aug->GetItem(); + linker.SetItemInst(inst_aug); + + c->Message( + (item_data == nullptr), + ".%sAugSlot: %i (Slot #%i, Aug idx #%i), Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + INVALID_INDEX, + (8000 + limboIndex), + indexAug, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()) + ); + } + } + + if (!scope_bag[scopeIndex] || !(inst_main && inst_main->IsClassBag())) + continue; + + for (uint8 indexSub = EQEmu::inventory::containerBegin; indexSub < EQEmu::inventory::ContainerCount; ++indexSub) { inst_sub = inst_main->GetItem(indexSub); + if (!inst_sub) + continue; + item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); + linker.SetItemInst(inst_sub); - item_link = linker.GenerateLink(); + c->Message( + (item_data == nullptr), + "..%sBagSlot: %i (Slot #%i, Bag idx #%i), Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + INVALID_INDEX, + (8000 + limboIndex), + indexSub, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()) + ); - c->Message((item_data == nullptr), " CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - EQEmu::InventoryProfile::CalcSlotId(EQEmu::inventory::slotCursor, indexSub), EQEmu::inventory::slotCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); + if (inst_sub->IsClassCommon()) { + for (uint8 indexAug = EQEmu::inventory::socketBegin; indexAug < EQEmu::inventory::SocketCount; ++indexAug) { + inst_aug = inst_sub->GetItem(indexAug); + if (!inst_aug) // extant only + continue; + + item_data = inst_aug->GetItem(); + linker.SetItemInst(inst_aug); + + c->Message( + (item_data == nullptr), + "...%sAugSlot: %i (Slot #%i, Sub idx #%i, Aug idx #%i), Item: %i (%s), Charges: %i", + scope_prefix[scopeIndex], + INVALID_INDEX, + (8000 + limboIndex), + indexSub, + indexAug, + ((item_data == nullptr) ? 0 : item_data->ID), + linker.GenerateLink().c_str(), + ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()) + ); + } + } } } } } - // trib - for (int16 indexMain = EQEmu::legacy::TRIBUTE_BEGIN; (scopeWhere & peekTrib) && (indexMain <= EQEmu::legacy::TRIBUTE_END); ++indexMain) { - inst_main = targetClient->GetInv().GetItem(indexMain); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), "TributeSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - } - - // bank - for (int16 indexMain = EQEmu::legacy::BANK_BEGIN; (scopeWhere & peekBank) && (indexMain <= EQEmu::legacy::BANK_END); ++indexMain) { - inst_main = targetClient->GetInv().GetItem(indexMain); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), "BankSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - - for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) { - inst_sub = inst_main->GetItem(indexSub); - item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); - linker.SetItemInst(inst_sub); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), " BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); - } - } - - for (int16 indexMain = EQEmu::legacy::SHARED_BANK_BEGIN; (scopeWhere & peekBank) && (indexMain <= EQEmu::legacy::SHARED_BANK_END); ++indexMain) { - inst_main = targetClient->GetInv().GetItem(indexMain); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), "SharedBankSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - - for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) { - inst_sub = inst_main->GetItem(indexSub); - item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); - linker.SetItemInst(inst_sub); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), " SharedBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); - } - } - - // trade - for (int16 indexMain = EQEmu::legacy::TRADE_BEGIN; (scopeWhere & peekTrade) && (indexMain <= EQEmu::legacy::TRADE_END); ++indexMain) { - inst_main = targetClient->GetInv().GetItem(indexMain); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), "TradeSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - - for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) { - inst_sub = inst_main->GetItem(indexSub); - item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); - linker.SetItemInst(inst_sub); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), " TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); - } - } - - // world - if (scopeWhere & peekWorld) { - Object* objectTradeskill = targetClient->GetTradeskillObject(); - - if (objectTradeskill == nullptr) { - c->Message(1, "No world tradeskill object selected..."); - } - else { - c->Message(0, "[WorldObject DBID: %i (entityid: %i)]", objectTradeskill->GetDBID(), objectTradeskill->GetID()); - - for (int16 indexMain = EQEmu::inventory::slotBegin; indexMain < EQEmu::legacy::TYPE_WORLD_SIZE; ++indexMain) { - inst_main = objectTradeskill->GetItem(indexMain); - item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); - linker.SetItemInst(inst_main); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), "WorldSlot: %i, Item: %i (%s), Charges: %i", - (EQEmu::legacy::WORLD_BEGIN + indexMain), ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - - for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsType(EQEmu::item::ItemClassBag) && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) { - inst_sub = inst_main->GetItem(indexSub); - item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); - linker.SetItemInst(inst_sub); - - item_link = linker.GenerateLink(); - - c->Message((item_data == nullptr), " WorldBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - INVALID_INDEX, indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); - } - } - } - } + if (!itemsFound) + c->Message(0, "No items found."); } void command_interrogateinv(Client *c, const Seperator *sep) @@ -2995,6 +3112,11 @@ void command_reloadworld(Client *c, const Seperator *sep) safe_delete(pack); } +void command_reloadmerchants(Client *c, const Seperator *sep) { + entity_list.ReloadMerchants(); + c->Message(15, "Reloading merchants."); +} + void command_reloadlevelmods(Client *c, const Seperator *sep) { if (sep->arg[1][0] == 0) @@ -3850,6 +3972,12 @@ void command_showstats(Client *c, const Seperator *sep) c->ShowStats(c); } +void command_showzonegloballoot(Client *c, const Seperator *sep) +{ + c->Message(0, "GlobalLoot for %s (%d:%d)", zone->GetShortName(), zone->GetZoneID(), zone->GetInstanceVersion()); + zone->ShowZoneGlobalLoot(c); +} + void command_mystats(Client *c, const Seperator *sep) { if (c->GetTarget() && c->GetPet()) { @@ -4062,6 +4190,33 @@ void command_unfreeze(Client *c, const Seperator *sep) c->Message(0, "ERROR: Unfreeze requires a target."); } +void command_push(Client *c, const Seperator *sep) +{ + Mob *t = c; + if (c->GetTarget() != nullptr) + t = c->GetTarget(); + + if (!sep->arg[1] || !sep->IsNumber(1)) { + c->Message(0, "ERROR: Must provide at least a push back."); + return; + } + + float back = atof(sep->arg[1]); + float up = 0.0f; + + if (sep->arg[2] && sep->IsNumber(2)) + up = atof(sep->arg[2]); + + if (t->IsNPC()) { + t->IncDeltaX(back * g_Math.FastSin(c->GetHeading())); + t->IncDeltaY(back * g_Math.FastCos(c->GetHeading())); + t->IncDeltaZ(up); + t->SetForcedMovement(6); + } else if (t->IsClient()) { + // TODO: send packet to push + } +} + void command_pvp(Client *c, const Seperator *sep) { bool state=atobool(sep->arg[1]); @@ -4159,6 +4314,26 @@ void command_tempname(Client *c, const Seperator *sep) } } +void command_petname(Client *c, const Seperator *sep) +{ + Mob *target; + target = c->GetTarget(); + + if(!target) + c->Message(0, "Usage: #petname newname (requires a target)"); + else if(target->IsPet() && (target->GetOwnerID() == c->GetID()) && strlen(sep->arg[1]) > 0) + { + char *oldname = strdup(target->GetName()); + target->TempName(sep->arg[1]); + c->Message(0, "Renamed %s to %s", oldname, sep->arg[1]); + free(oldname); + } + else { + target->TempName(); + c->Message(0, "Restored the original name"); + } +} + void command_npcspecialattk(Client *c, const Seperator *sep) { if (c->GetTarget()==0 || c->GetTarget()->IsClient() || strlen(sep->arg[1]) <= 0 || strlen(sep->arg[2]) <= 0) @@ -4363,9 +4538,7 @@ void command_iteminfo(Client *c, const Seperator *sep) linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); linker.SetItemInst(inst); - auto item_link = linker.GenerateLink(); - - c->Message(0, "*** Item Info for [%s] ***", item_link.c_str()); + c->Message(0, "*** Item Info for [%s] ***", linker.GenerateLink().c_str()); c->Message(0, ">> ID: %u, ItemUseType: %u, ItemClassType: %u", item->ID, item->ItemType, item->ItemClass); c->Message(0, ">> IDFile: '%s', IconID: %u", item->IDFile, item->Icon); c->Message(0, ">> Size: %u, Weight: %u, Price: %u, LDoNPrice: %u", item->Size, item->Weight, item->Price, item->LDoNPrice); @@ -5509,9 +5682,9 @@ void command_summonitem(Client *c, const Seperator *sep) std::string cmd_msg = sep->msg; size_t link_open = cmd_msg.find('\x12'); size_t link_close = cmd_msg.find_last_of('\x12'); - if (link_open != link_close && (cmd_msg.length() - link_open) > EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { + if (link_open != link_close && (cmd_msg.length() - link_open) > EQEmu::constants::SayLinkBodySize) { EQEmu::SayLinkBody_Struct link_body; - EQEmu::saylink::DegenerateLinkBody(link_body, cmd_msg.substr(link_open + 1, EQEmu::legacy::TEXT_LINK_BODY_LENGTH)); + EQEmu::saylink::DegenerateLinkBody(link_body, cmd_msg.substr(link_open + 1, EQEmu::constants::SayLinkBodySize)); itemid = link_body.item_id; } else if (!sep->IsNumber(1)) { @@ -5620,7 +5793,6 @@ void command_itemsearch(Client *c, const Seperator *sep) const char *search_criteria=sep->argplus[1]; const EQEmu::ItemData* item = nullptr; - std::string item_link; EQEmu::SayLinkEngine linker; linker.SetLinkType(EQEmu::saylink::SayLinkItemData); @@ -5629,9 +5801,7 @@ void command_itemsearch(Client *c, const Seperator *sep) if (item) { linker.SetItemData(item); - item_link = linker.GenerateLink(); - - c->Message(0, "%u: %s", item->ID, item_link.c_str()); + c->Message(0, "%u: %s", item->ID, linker.GenerateLink().c_str()); } else { c->Message(0, "Item #%s not found", search_criteria); @@ -5654,9 +5824,7 @@ void command_itemsearch(Client *c, const Seperator *sep) if (pdest != nullptr) { linker.SetItemData(item); - item_link = linker.GenerateLink(); - - c->Message(0, "%u: %s", item->ID, item_link.c_str()); + c->Message(0, "%u: %s", item->ID, linker.GenerateLink().c_str()); ++count; } @@ -7160,6 +7328,90 @@ void command_undye(Client *c, const Seperator *sep) } } +void command_ucs(Client *c, const Seperator *sep) +{ + if (!c) + return; + + Log(Logs::Detail, Logs::UCS_Server, "Character %s attempting ucs reconnect while ucs server is %savailable", + c->GetName(), (zone->IsUCSServerAvailable() ? "" : "un")); + + if (zone->IsUCSServerAvailable()) { + EQApplicationPacket* outapp = nullptr; + std::string buffer; + + std::string MailKey = database.GetMailKey(c->CharacterID(), true); + EQEmu::versions::UCSVersion ConnectionType = EQEmu::versions::ucsUnknown; + + // chat server packet + switch (c->ClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + ConnectionType = EQEmu::versions::ucsTitaniumChat; + break; + case EQEmu::versions::ClientVersion::SoF: + ConnectionType = EQEmu::versions::ucsSoFCombined; + break; + case EQEmu::versions::ClientVersion::SoD: + ConnectionType = EQEmu::versions::ucsSoDCombined; + break; + case EQEmu::versions::ClientVersion::UF: + ConnectionType = EQEmu::versions::ucsUFCombined; + break; + case EQEmu::versions::ClientVersion::RoF: + ConnectionType = EQEmu::versions::ucsRoFCombined; + break; + case EQEmu::versions::ClientVersion::RoF2: + ConnectionType = EQEmu::versions::ucsRoF2Combined; + break; + default: + ConnectionType = EQEmu::versions::ucsUnknown; + break; + } + + buffer = StringFormat("%s,%i,%s.%s,%c%s", + Config->ChatHost.c_str(), + Config->ChatPort, + Config->ShortName.c_str(), + c->GetName(), + ConnectionType, + MailKey.c_str() + ); + + outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; + + c->QueuePacket(outapp); + safe_delete(outapp); + + // mail server packet + switch (c->ClientVersion()) { + case EQEmu::versions::ClientVersion::Titanium: + ConnectionType = EQEmu::versions::ucsTitaniumMail; + break; + default: + // retain value from previous switch + break; + } + + buffer = StringFormat("%s,%i,%s.%s,%c%s", + Config->MailHost.c_str(), + Config->MailPort, + Config->ShortName.c_str(), + c->GetName(), + ConnectionType, + MailKey.c_str() + ); + + outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; + + c->QueuePacket(outapp); + safe_delete(outapp); + } +} + void command_undyeme(Client *c, const Seperator *sep) { if(c) { @@ -8722,7 +8974,7 @@ void command_object(Client *c, const Seperator *sep) od.x = c->GetX(); od.y = c->GetY(); od.z = c->GetZ() - (c->GetSize() * 0.625f); - od.heading = c->GetHeading() * 2.0f; // GetHeading() is half of actual. Compensate by doubling. + od.heading = c->GetHeading(); std::string query; if (id) { @@ -8827,11 +9079,9 @@ void command_object(Client *c, const Seperator *sep) // Bump player back to avoid getting stuck inside new object - // GetHeading() returns half of the actual heading, for some reason, so we'll double it here for - // computation - x2 = 10.0f * sin(c->GetHeading() * 2.0f / 256.0f * 3.14159265f); - y2 = 10.0f * cos(c->GetHeading() * 2.0f / 256.0f * 3.14159265f); - c->MovePC(c->GetX() - x2, c->GetY() - y2, c->GetZ(), c->GetHeading() * 2); + x2 = 10.0f * sin(c->GetHeading() / 256.0f * 3.14159265f); + y2 = 10.0f * cos(c->GetHeading() / 256.0f * 3.14159265f); + c->MovePC(c->GetX() - x2, c->GetY() - y2, c->GetZ(), c->GetHeading()); c->Message(0, "Spawning object with tentative id %u at location (%.1f, %.1f, %.1f heading %.1f). Use " "'#object Save' to save to database when satisfied with placement.", @@ -9149,14 +9399,13 @@ void command_object(Client *c, const Seperator *sep) (c->GetSize() * 0.625f); // Compensate for #loc bumping up Z coordinate by 62.5% of character's size. - o->SetHeading(c->GetHeading() * 2.0f); // Compensate for GetHeading() returning half of actual + o->SetHeading(c->GetHeading()); // Bump player back to avoid getting stuck inside object - // GetHeading() returns half of the actual heading, for some reason - x2 = 10.0f * sin(c->GetHeading() * 2.0f / 256.0f * 3.14159265f); - y2 = 10.0f * cos(c->GetHeading() * 2.0f / 256.0f * 3.14159265f); - c->MovePC(c->GetX() - x2, c->GetY() - y2, c->GetZ(), c->GetHeading() * 2.0f); + x2 = 10.0f * std::sin(c->GetHeading() / 256.0f * 3.14159265f); + y2 = 10.0f * std::cos(c->GetHeading() / 256.0f * 3.14159265f); + c->MovePC(c->GetX() - x2, c->GetY() - y2, c->GetZ(), c->GetHeading()); } // Move to x, y, z [h] else { od.x = atof(sep->arg[3]); @@ -10414,6 +10663,20 @@ void command_shownumhits(Client *c, const Seperator *sep) return; } +void command_shownpcgloballoot(Client *c, const Seperator *sep) +{ + auto tar = c->GetTarget(); + + if (!tar || !tar->IsNPC()) { + c->Message(0, "You must target an NPC to use this command."); + return; + } + + auto npc = tar->CastToNPC(); + c->Message(0, "GlobalLoot for %s (%d)", npc->GetName(), npc->GetNPCTypeID()); + zone->ShowNPCGlobalLoot(c, npc); +} + void command_tune(Client *c, const Seperator *sep) { //Work in progress - Kayen @@ -10787,7 +11050,7 @@ void command_hotfix(Client *c, const Seperator *sep) { } worldserver.SendPacket(&pack); - c->Message(0, "Hotfix applied"); + if (c) c->Message(0, "Hotfix applied"); }); t1.detach(); diff --git a/zone/command.h b/zone/command.h index dca70d767..d3bae6c0c 100644 --- a/zone/command.h +++ b/zone/command.h @@ -211,6 +211,7 @@ void command_profiledump(Client *c, const Seperator *sep); void command_profilereset(Client *c, const Seperator *sep); #endif +void command_push(Client *c, const Seperator *sep); void command_pvp(Client *c, const Seperator *sep); void command_qglobal(Client *c, const Seperator *sep); void command_qtest(Client *c, const Seperator *sep); @@ -224,6 +225,7 @@ void command_reloadaa(Client *c, const Seperator *sep); void command_reloadallrules(Client *c, const Seperator *sep); void command_reloademote(Client* c, const Seperator *sep); void command_reloadlevelmods(Client *c, const Seperator *sep); +void command_reloadmerchants(Client *c, const Seperator *sep); void command_reloadperlexportsettings(Client *c, const Seperator *sep); void command_reloadqst(Client *c, const Seperator *sep); void command_reloadstatic(Client *c, const Seperator *sep); @@ -266,10 +268,12 @@ void command_setxp(Client *c, const Seperator *sep); void command_showbonusstats(Client *c, const Seperator *sep); void command_showbuffs(Client *c, const Seperator *sep); void command_shownumhits(Client *c, const Seperator *sep); +void command_shownpcgloballoot(Client *c, const Seperator *sep); void command_showpetspell(Client *c, const Seperator *sep); void command_showskills(Client *c, const Seperator *sep); void command_showspellslist(Client *c, const Seperator *sep); void command_showstats(Client *c, const Seperator *sep); +void command_showzonegloballoot(Client *c, const Seperator *sep); void command_shutdown(Client *c, const Seperator *sep); void command_size(Client *c, const Seperator *sep); void command_spawn(Client *c, const Seperator *sep); @@ -287,6 +291,7 @@ void command_synctod(Client *c, const Seperator *sep); void command_task(Client *c, const Seperator *sep); void command_tattoo(Client *c, const Seperator *sep); void command_tempname(Client *c, const Seperator *sep); +void command_petname(Client *c, const Seperator *sep); void command_testspawn(Client *c, const Seperator *sep); void command_testspawnkill(Client *c, const Seperator *sep); void command_texture(Client *c, const Seperator *sep); @@ -298,6 +303,7 @@ void command_titlesuffix(Client *c, const Seperator *sep); void command_traindisc(Client *c, const Seperator *sep); void command_trapinfo(Client* c, const Seperator *sep); void command_tune(Client *c, const Seperator *sep); +void command_ucs(Client *c, const Seperator *sep); void command_undye(Client *c, const Seperator *sep); void command_undyeme(Client *c, const Seperator *sep); void command_unfreeze(Client *c, const Seperator *sep); diff --git a/zone/common.h b/zone/common.h index f7b157115..df6b22637 100644 --- a/zone/common.h +++ b/zone/common.h @@ -194,7 +194,8 @@ enum { CASTING_RESIST_DIFF = 43, COUNTER_AVOID_DAMAGE = 44, PROX_AGGRO = 45, - MAX_SPECIAL_ATTACK = 46 + IMMUNE_RANGED_ATTACKS = 46, + MAX_SPECIAL_ATTACK = 47 }; typedef enum { //fear states diff --git a/zone/corpse.cpp b/zone/corpse.cpp index a8f3e7ba1..63031ec45 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -1253,20 +1253,20 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app) linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); linker.SetItemInst(inst); - auto item_link = linker.GenerateLink(); + linker.GenerateLink(); - client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str()); + client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, linker.Link().c_str()); if (!IsPlayerCorpse()) { Group *g = client->GetGroup(); if (g != nullptr) { g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, - client->GetName(), item_link.c_str()); + client->GetName(), linker.Link().c_str()); } else { Raid *r = client->GetRaid(); if (r != nullptr) { r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, - client->GetName(), item_link.c_str()); + client->GetName(), linker.Link().c_str()); } } } diff --git a/zone/effects.cpp b/zone/effects.cpp index 2741a924b..6b0c2a2ad 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -611,6 +611,10 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { return false; } + // the client does this check before calling CastSpell, should prevent discs being eaten + if (spell.buffdurationformula != 0 && spell.targettype == ST_Self && HasDiscBuff()) + return false; + //Check the disc timer pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.EndurTimerIndex; if(!p_timers.Expired(&database, DiscTimer, false)) { // lets not set the reuse timer in case CastSpell fails (or we would have to turn off the timer, but CastSpell will set it as well) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index b440fdd3b..0c8ef58b9 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -146,7 +146,7 @@ XS(XS__echo) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: echo(id#, str)"); + Perl_croak(aTHX_ "Usage: echo(color_id, message)"); quest_manager.echo(SvUV(ST(0)), SvPV_nolen(ST(1))); @@ -162,7 +162,7 @@ XS(XS__say) { else if (items == 2) quest_manager.say(SvPV_nolen(ST(0)), (int)SvIV(ST(1))); else - Perl_croak(aTHX_ "Usage: say(str [, language])"); + Perl_croak(aTHX_ "Usage: say(message [, language_id])"); XSRETURN_EMPTY; } @@ -172,7 +172,7 @@ XS(XS__me) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: %s(str)", "me"); + Perl_croak(aTHX_ "Usage: %s(message)", "me"); quest_manager.me(SvPV_nolen(ST(0))); @@ -188,7 +188,7 @@ XS(XS__summonitem) else if(items == 2) quest_manager.summonitem(SvUV(ST(0)), SvUV(ST(1))); else - Perl_croak(aTHX_ "Usage: summonitem(itemid, [charges])"); + Perl_croak(aTHX_ "Usage: summonitem(item_id, [charges])"); XSRETURN_EMPTY; } @@ -197,12 +197,12 @@ XS(XS__write) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: write(file, str)"); + Perl_croak(aTHX_ "Usage: write(file, message)"); char * file = (char *)SvPV_nolen(ST(0)); - char * str = (char *)SvPV_nolen(ST(1)); + char * message = (char *)SvPV_nolen(ST(1)); - quest_manager.write(file, str); + quest_manager.write(file, message); XSRETURN_EMPTY; } @@ -212,17 +212,17 @@ XS(XS__spawn) { dXSARGS; if (items != 6) - Perl_croak(aTHX_ "Usage: spawn(npc_type, grid, unused, x, y, z)"); + Perl_croak(aTHX_ "Usage: spawn(npc_type_id, grid_id, int_unused, x, y, z)"); uint16 RETVAL; dXSTARG; - int npc_type = (int)SvIV(ST(0)); - int grid = (int)SvIV(ST(1)); - int unused = (int)SvIV(ST(2)); + int npc_type_id = (int)SvIV(ST(0)); + int grid_id = (int)SvIV(ST(1)); + int int_unused = (int)SvIV(ST(2)); auto position = glm::vec4((float)SvNV(ST(3)), (float)SvNV(ST(4)), (float)SvNV(ST(5)), 0.0f); - Mob *r = quest_manager.spawn2(npc_type, grid, unused, position); + Mob *r = quest_manager.spawn2(npc_type_id, grid_id, int_unused, position); RETVAL = (r != nullptr) ? r->GetID() : 0; XSprePUSH; PUSHu((UV)RETVAL); @@ -234,17 +234,17 @@ XS(XS__spawn2) { dXSARGS; if (items != 7) - Perl_croak(aTHX_ "Usage: spawn2(npc_type, grid, unused, x, y, z, heading)"); + Perl_croak(aTHX_ "Usage: spawn2(npc_type_id, grid_id, int_unused, x, y, z, heading)"); uint16 RETVAL; dXSTARG; - int npc_type = (int)SvIV(ST(0)); - int grid = (int)SvIV(ST(1)); - int unused = (int)SvIV(ST(2)); + int npc_type_id = (int)SvIV(ST(0)); + int grid_id = (int)SvIV(ST(1)); + int int_unused = (int)SvIV(ST(2)); auto position = glm::vec4((float)SvNV(ST(3)), (float)SvNV(ST(4)), (float)SvNV(ST(5)), (float)SvNV(ST(6))); - Mob *r = quest_manager.spawn2(npc_type, grid, unused, position); + Mob *r = quest_manager.spawn2(npc_type_id, grid_id, int_unused, position); RETVAL = (r != nullptr) ? r->GetID() : 0; XSprePUSH; PUSHu((UV)RETVAL); @@ -256,14 +256,14 @@ XS(XS__unique_spawn) { dXSARGS; if (items != 6 && items != 7) - Perl_croak(aTHX_ "Usage: unique_spawn(npc_type, grid, unused, x, y, z, [heading])"); + Perl_croak(aTHX_ "Usage: unique_spawn(npc_type_id, grid_id, int_unused, x, y, z, [heading])"); uint16 RETVAL; dXSTARG; - int npc_type = (int)SvIV(ST(0)); - int grid = (int)SvIV(ST(1)); - int unused = (int)SvIV(ST(2)); + int npc_type_id = (int)SvIV(ST(0)); + int grid_id = (int)SvIV(ST(1)); + int int_unused = (int)SvIV(ST(2)); float x = (float)SvNV(ST(3)); float y = (float)SvNV(ST(4)); float z = (float)SvNV(ST(5)); @@ -271,7 +271,7 @@ XS(XS__unique_spawn) if(items == 7) heading = (float)SvNV(ST(6)); - Mob *r = quest_manager.unique_spawn(npc_type, grid, unused, glm::vec4(x, y, z, heading)); + Mob *r = quest_manager.unique_spawn(npc_type_id, grid_id, int_unused, glm::vec4(x, y, z, heading)); RETVAL = (r != nullptr) ? r->GetID() : 0; XSprePUSH; PUSHu((UV)RETVAL); @@ -330,12 +330,12 @@ XS(XS__setstat) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: setstat(stat, value)"); + Perl_croak(aTHX_ "Usage: setstat(stat_id, int_value)"); - int stat = (int)SvIV(ST(0)); - int value = (int)SvIV(ST(1)); + int stat_id = (int)SvIV(ST(0)); + int int_value = (int)SvIV(ST(1)); - quest_manager.setstat(stat, value); + quest_manager.setstat(stat_id, int_value); XSRETURN_EMPTY; } @@ -345,12 +345,12 @@ XS(XS__incstat) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: incstat(stat, value)"); + Perl_croak(aTHX_ "Usage: incstat(stat_id, int_value)"); - int stat = (int)SvIV(ST(0)); - int value = (int)SvIV(ST(1)); + int stat_id = (int)SvIV(ST(0)); + int int_value = (int)SvIV(ST(1)); - quest_manager.incstat(stat, value); + quest_manager.incstat(stat_id, int_value); XSRETURN_EMPTY; } @@ -391,7 +391,7 @@ XS(XS__addloot) if(items < 1 || items > 3) Perl_croak(aTHX_ "Usage: addloot(item_id, charges = 0, equipitem = true)"); - uint32 itemid = (uint32)SvUV(ST(0)); + uint32 item_id = (uint32)SvUV(ST(0)); uint16 charges = 0; bool equipitem = true; @@ -400,7 +400,7 @@ XS(XS__addloot) if (items > 2) equipitem = (bool)SvTRUE(ST(2)); - quest_manager.addloot(itemid, charges, equipitem); + quest_manager.addloot(item_id, charges, equipitem); XSRETURN_EMPTY; } @@ -480,11 +480,11 @@ XS(XS__emote) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: emote(str)"); + Perl_croak(aTHX_ "Usage: emote(message)"); - char * str = (char *)SvPV_nolen(ST(0)); + char * message = (char *)SvPV_nolen(ST(0)); - quest_manager.emote(str); + quest_manager.emote(message); XSRETURN_EMPTY; } @@ -494,11 +494,11 @@ XS(XS__shout) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: shout(str)"); + Perl_croak(aTHX_ "Usage: shout(message)"); - char * str = (char *)SvPV_nolen(ST(0)); + char * message = (char *)SvPV_nolen(ST(0)); - quest_manager.shout(str); + quest_manager.shout(message); XSRETURN_EMPTY; } @@ -508,11 +508,11 @@ XS(XS__shout2) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: shout2(str)"); + Perl_croak(aTHX_ "Usage: shout2(message)"); - char * str = (char *)SvPV_nolen(ST(0)); + char * message = (char *)SvPV_nolen(ST(0)); - quest_manager.shout2(str); + quest_manager.shout2(message); XSRETURN_EMPTY; } @@ -522,16 +522,16 @@ XS(XS__gmsay) { dXSARGS; if ((items < 1) || (items > 5)) - Perl_croak(aTHX_ "Usage: gmsay(str, color, send_to_world?)"); + Perl_croak(aTHX_ "Usage: gmsay(message, color_id, send_to_world)"); - char * str = (char *)SvPV_nolen(ST(0)); - int color = 7; + char * message = (char *)SvPV_nolen(ST(0)); + int color_id = 7; bool send_to_world = 0; uint32 to_guilddbid = 0; uint16 to_minstatus = 80; if (items > 1) { - color = (int)SvIV(ST(1)); + color_id = (int)SvIV(ST(1)); } if (items > 2) { @@ -544,7 +544,7 @@ XS(XS__gmsay) if (items > 4) to_minstatus = (int)SvUV(ST(4)); - quest_manager.gmsay(str, color, send_to_world, to_guilddbid, to_minstatus); + quest_manager.gmsay(message, color_id, send_to_world, to_guilddbid, to_minstatus); XSRETURN_EMPTY; } @@ -554,17 +554,17 @@ XS(XS__depop) { dXSARGS; if (items < 0 || items > 1) - Perl_croak(aTHX_ "Usage: depop(npc_type= 0)"); + Perl_croak(aTHX_ "Usage: depop(npc_type_id = 0)"); - int npc_type; + int npc_type_id; if (items < 1) - npc_type = 0; + npc_type_id = 0; else - npc_type = (int)SvIV(ST(0)); + npc_type_id = (int)SvIV(ST(0)); - quest_manager.depop(npc_type); + quest_manager.depop(npc_type_id); XSRETURN_EMPTY; } @@ -574,17 +574,17 @@ XS(XS__depop_withtimer) { dXSARGS; if (items < 0 || items > 1) - Perl_croak(aTHX_ "Usage: depop_withtimer(npc_type= 0)"); + Perl_croak(aTHX_ "Usage: depop_withtimer(npc_type_id= 0)"); - int npc_type; + int npc_type_id; if (items < 1) - npc_type = 0; + npc_type_id = 0; else - npc_type = (int)SvIV(ST(0)); + npc_type_id = (int)SvIV(ST(0)); - quest_manager.depop_withtimer(npc_type); + quest_manager.depop_withtimer(npc_type_id); XSRETURN_EMPTY; } @@ -594,17 +594,17 @@ XS(XS__depopall) { dXSARGS; if (items < 0 || items > 1) - Perl_croak(aTHX_ "Usage: depopall(npc_type= 0)"); + Perl_croak(aTHX_ "Usage: depopall(npc_type_id= 0)"); - int npc_type; + int npc_type_id; if (items < 1) - npc_type = 0; + npc_type_id = 0; else - npc_type = (int)SvIV(ST(0)); + npc_type_id = (int)SvIV(ST(0)); - quest_manager.depopall(npc_type); + quest_manager.depopall(npc_type_id); XSRETURN_EMPTY; } @@ -614,12 +614,12 @@ XS(XS__settarget) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: settarget(type, target_id)"); + Perl_croak(aTHX_ "Usage: settarget(target_enum, target_id)"); - char * type = (char *)SvPV_nolen(ST(0)); + char * target_enum = (char *)SvPV_nolen(ST(0)); int target_id = (int)SvIV(ST(1)); - quest_manager.settarget(type, target_id); + quest_manager.settarget(target_enum, target_id); XSRETURN_EMPTY; } @@ -935,18 +935,18 @@ XS(XS__movepc) if (items != 4 && items != 5) Perl_croak(aTHX_ "Usage: movepc(zone_id, x, y, z [,heading])"); - int zoneid = (int)SvIV(ST(0)); + int zone_id = (int)SvIV(ST(0)); float x = (float)SvNV(ST(1)); float y = (float)SvNV(ST(2)); float z = (float)SvNV(ST(3)); if (items == 4) - quest_manager.movepc(zoneid, x, y, z, 0.0f); + quest_manager.movepc(zone_id, x, y, z, 0.0f); else { float heading = (float)SvNV(ST(4)); - quest_manager.movepc(zoneid, x, y, z, heading); + quest_manager.movepc(zone_id, x, y, z, heading); } XSRETURN_EMPTY; @@ -973,14 +973,14 @@ XS(XS__movegrp) { dXSARGS; if (items != 4) - Perl_croak(aTHX_ "Usage: movegrp(zoneid, x, y, z)"); + Perl_croak(aTHX_ "Usage: movegrp(zone_id, x, y, z)"); - int zoneid = (int)SvIV(ST(0)); + int zone_id = (int)SvIV(ST(0)); float x = (float)SvNV(ST(1)); float y = (float)SvNV(ST(2)); float z = (float)SvNV(ST(3)); - quest_manager.movegrp(zoneid, x, y, z); + quest_manager.movegrp(zone_id, x, y, z); XSRETURN_EMPTY; } @@ -1004,12 +1004,12 @@ XS(XS__addskill) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: addskill(skill_id, value)"); + Perl_croak(aTHX_ "Usage: addskill(skill_id, int_value)"); int skill_id = (int)SvIV(ST(0)); - int value = (int)SvIV(ST(1)); + int int_value = (int)SvIV(ST(1)); - quest_manager.addskill(skill_id, value); + quest_manager.addskill(skill_id, int_value); XSRETURN_EMPTY; } @@ -1019,12 +1019,12 @@ XS(XS__setlanguage) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: setlanguage(skill_id, value)"); + Perl_croak(aTHX_ "Usage: setlanguage(skill_id, int_value)"); int skill_id = (int)SvIV(ST(0)); - int value = (int)SvIV(ST(1)); + int int_value = (int)SvIV(ST(1)); - quest_manager.setlanguage(skill_id, value); + quest_manager.setlanguage(skill_id, int_value); XSRETURN_EMPTY; } @@ -1034,12 +1034,12 @@ XS(XS__setskill) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: setskill(skill_id, value)"); + Perl_croak(aTHX_ "Usage: setskill(skill_id, int_value)"); int skill_id = (int)SvIV(ST(0)); - int value = (int)SvIV(ST(1)); + int int_value = (int)SvIV(ST(1)); - quest_manager.setskill(skill_id, value); + quest_manager.setskill(skill_id, int_value); XSRETURN_EMPTY; } @@ -1049,11 +1049,11 @@ XS(XS__setallskill) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: setallskill(value)"); + Perl_croak(aTHX_ "Usage: setallskill(int_value)"); - int value = (int)SvIV(ST(0)); + int int_value = (int)SvIV(ST(0)); - quest_manager.setallskill(value); + quest_manager.setallskill(int_value); XSRETURN_EMPTY; } @@ -1118,10 +1118,10 @@ XS(XS__faction) { dXSARGS; if (items < 2 || items > 3) - Perl_croak(aTHX_ "Usage: faction(faction_id, faction_value, temp)"); + Perl_croak(aTHX_ "Usage: faction(faction_id, int_value, temp)"); int faction_id = (int)SvIV(ST(0)); - int faction_value = (int)SvIV(ST(1)); + int int_value = (int)SvIV(ST(1)); int temp; if(items == 2) @@ -1129,7 +1129,7 @@ XS(XS__faction) else temp = (int)SvIV(ST(2)); - quest_manager.faction(faction_id, faction_value, temp); + quest_manager.faction(faction_id, int_value, temp); XSRETURN_EMPTY; } @@ -1153,12 +1153,12 @@ XS(XS__setguild) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: setguild(new_guild_id, new_rank)"); + Perl_croak(aTHX_ "Usage: setguild(new_guild_id, guild_rank_id)"); unsigned long new_guild_id = (unsigned long)SvUV(ST(0)); - int new_rank = (int)SvIV(ST(1)); + int guild_rank_id = (int)SvIV(ST(1)); - quest_manager.setguild(new_guild_id, new_rank); + quest_manager.setguild(new_guild_id, guild_rank_id); XSRETURN_EMPTY; } @@ -1168,12 +1168,12 @@ XS(XS__createguild) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: createguild(guild_name, leader)"); + Perl_croak(aTHX_ "Usage: createguild(guild_name, leader_name)"); char * guild_name = (char *)SvPV_nolen(ST(0)); - char * leader = (char *)SvPV_nolen(ST(1)); + char * leader_name = (char *)SvPV_nolen(ST(1)); - quest_manager.CreateGuild(guild_name, leader); + quest_manager.CreateGuild(guild_name, leader_name); XSRETURN_EMPTY; } @@ -1265,14 +1265,14 @@ XS(XS__setglobal) { dXSARGS; if (items != 4) - Perl_croak(aTHX_ "Usage: setglobal(varname, newvalue, options, duration)"); + Perl_croak(aTHX_ "Usage: setglobal(key, str_value, options, duration)"); - char * varname = (char *)SvPV_nolen(ST(0)); - char * newvalue = (char *)SvPV_nolen(ST(1)); + char * key = (char *)SvPV_nolen(ST(0)); + char * str_value = (char *)SvPV_nolen(ST(1)); int options = (int)SvIV(ST(2)); char * duration = (char *)SvPV_nolen(ST(3)); - quest_manager.setglobal(varname, newvalue, options, duration); + quest_manager.setglobal(key, str_value, options, duration); XSRETURN_EMPTY; } @@ -1282,16 +1282,16 @@ XS(XS__targlobal) { dXSARGS; if (items != 6) - Perl_croak(aTHX_ "Usage: targlobal(varname, value, duration, npcid, charid, zoneid)"); + Perl_croak(aTHX_ "Usage: targlobal(key, str_value, duration, npc_id, char_id, zone_id)"); - char * varname = (char *)SvPV_nolen(ST(0)); - char * value = (char *)SvPV_nolen(ST(1)); + char * key = (char *)SvPV_nolen(ST(0)); + char * str_value = (char *)SvPV_nolen(ST(1)); char * duration = (char *)SvPV_nolen(ST(2)); - int npcid = (int)SvIV(ST(3)); - int charid = (int)SvIV(ST(4)); - int zoneid = (int)SvIV(ST(5)); + int npc_id = (int)SvIV(ST(3)); + int char_id = (int)SvIV(ST(4)); + int zone_id = (int)SvIV(ST(5)); - quest_manager.targlobal(varname, value, duration, npcid, charid, zoneid); + quest_manager.targlobal(key, str_value, duration, npc_id, char_id, zone_id); XSRETURN_EMPTY; } @@ -1301,11 +1301,11 @@ XS(XS__delglobal) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: delglobal(varname)"); + Perl_croak(aTHX_ "Usage: delglobal(key)"); - char * varname = (char *)SvPV_nolen(ST(0)); + char * key = (char *)SvPV_nolen(ST(0)); - quest_manager.delglobal(varname); + quest_manager.delglobal(key); XSRETURN_EMPTY; } @@ -1328,12 +1328,12 @@ XS(XS__rebind) { dXSARGS; if (items != 4) - Perl_croak(aTHX_ "Usage: rebind(zoneid, x, y, z)"); + Perl_croak(aTHX_ "Usage: rebind(zone_id, x, y, z)"); - int zoneid = (int)SvIV(ST(0)); + int zone_id = (int)SvIV(ST(0)); auto location = glm::vec3((float)SvNV(ST(1)),(float)SvNV(ST(2)),(float)SvNV(ST(3))); - quest_manager.rebind(zoneid, location); + quest_manager.rebind(zone_id, location); XSRETURN_EMPTY; } @@ -1384,7 +1384,7 @@ XS(XS__moveto) { dXSARGS; if (items != 3 && items != 4 && items != 5) - Perl_croak(aTHX_ "Usage: moveto(x, y, z, [mth, saveguard?])"); + Perl_croak(aTHX_ "Usage: moveto(x, y, z, [heading], [saveguard?])"); float x = (float)SvNV(ST(0)); float y = (float)SvNV(ST(1)); @@ -1425,12 +1425,12 @@ XS(XS__addldonpoints) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: addldonpoints(points, theme)"); + Perl_croak(aTHX_ "Usage: addldonpoints(points, theme_id)"); long points = (long)SvIV(ST(0)); - unsigned long theme = (unsigned long)SvUV(ST(1)); + unsigned long theme_id = (unsigned long)SvUV(ST(1)); - quest_manager.addldonpoints(points, theme); + quest_manager.addldonpoints(points, theme_id); XSRETURN_EMPTY; } @@ -1440,12 +1440,12 @@ XS(XS__addldonwin) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: addldonwin(wins, theme)"); + Perl_croak(aTHX_ "Usage: addldonwin(wins, theme_id)"); long wins = (long)SvIV(ST(0)); - unsigned long theme = (unsigned long)SvUV(ST(1)); + unsigned long theme_id = (unsigned long)SvUV(ST(1)); - quest_manager.addldonwin(wins, theme); + quest_manager.addldonwin(wins, theme_id); XSRETURN_EMPTY; } @@ -1455,12 +1455,12 @@ XS(XS__addldonloss) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: addldonloss(losses, theme)"); + Perl_croak(aTHX_ "Usage: addldonloss(losses, theme_id)"); long losses = (long)SvIV(ST(0)); - unsigned long theme = (unsigned long)SvUV(ST(1)); + unsigned long theme_id = (unsigned long)SvUV(ST(1)); - quest_manager.addldonloss(losses, theme); + quest_manager.addldonloss(losses, theme_id); XSRETURN_EMPTY; } @@ -1512,12 +1512,12 @@ XS(XS__respawn) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: respawn(npc_type, grid)"); + Perl_croak(aTHX_ "Usage: respawn(npc_type_id, grid_id)"); - int npc_type = (int)SvIV(ST(0)); - int grid = (int)SvIV(ST(1)); + int npc_type_id = (int)SvIV(ST(0)); + int grid_id = (int)SvIV(ST(1)); - quest_manager.respawn(npc_type, grid); + quest_manager.respawn(npc_type_id, grid_id); XSRETURN_EMPTY; } @@ -1543,19 +1543,19 @@ XS(XS__set_proximity) { dXSARGS; if (items != 4 && items != 6) - Perl_croak(aTHX_ "Usage: set_proximity(minx, maxx, miny, maxy [, minz, maxz])"); + Perl_croak(aTHX_ "Usage: set_proximity(min_x, max_x, min_y, max_y [, min_z, max_z])"); - float minx = (float)SvNV(ST(0)); - float maxx = (float)SvNV(ST(1)); - float miny = (float)SvNV(ST(2)); - float maxy = (float)SvNV(ST(3)); + float min_x = (float)SvNV(ST(0)); + float max_x = (float)SvNV(ST(1)); + float min_y = (float)SvNV(ST(2)); + float max_y = (float)SvNV(ST(3)); if(items == 4) - quest_manager.set_proximity(minx, maxx, miny, maxy); + quest_manager.set_proximity(min_x, max_x, min_y, max_y); else { - float minz = (float)SvNV(ST(4)); - float maxz = (float)SvNV(ST(5)); - quest_manager.set_proximity(minx, maxx, miny, maxy, minz, maxz); + float min_z = (float)SvNV(ST(4)); + float max_z = (float)SvNV(ST(5)); + quest_manager.set_proximity(min_x, max_x, min_y, max_y, min_z, max_z); } XSRETURN_EMPTY; @@ -1602,7 +1602,7 @@ XS(XS__setanim) //Cisyouc: mob->setappearance() addition { dXSARGS; if(items != 2) - Perl_croak(aTHX_ "Usage: quest::setanim(npc_type, animnum);"); + Perl_croak(aTHX_ "Usage: quest::setanim(npc_type_id, anim_num);"); quest_manager.setanim(SvUV(ST(0)), SvUV(ST(1))); @@ -1626,24 +1626,24 @@ XS(XS__spawn_condition) { dXSARGS; if (items < 3 || items > 4) - Perl_croak(aTHX_ "Usage: spawn_condition(zone_short, [instance_id], condition_id, value)"); + Perl_croak(aTHX_ "Usage: spawn_condition(zone_short, [instance_id], condition_id, int_value)"); if(items == 3) { char * zone_short = (char *)SvPV_nolen(ST(0)); - uint16 cond_id = (int)SvUV(ST(1)); - int16 value = (int)SvIV(ST(2)); + uint16 condition_id = (int)SvUV(ST(1)); + int16 int_value = (int)SvIV(ST(2)); - quest_manager.spawn_condition(zone_short, zone->GetInstanceID(), cond_id, value); + quest_manager.spawn_condition(zone_short, zone->GetInstanceID(), condition_id, int_value); } else { char * zone_short = (char *)SvPV_nolen(ST(0)); uint32 instance_id = (int)SvUV(ST(1)); - uint16 cond_id = (int)SvUV(ST(2)); - int16 value = (int)SvIV(ST(3)); + uint16 condition_id = (int)SvUV(ST(2)); + int16 int_value = (int)SvIV(ST(3)); - quest_manager.spawn_condition(zone_short, instance_id, cond_id, value); + quest_manager.spawn_condition(zone_short, instance_id, condition_id, int_value); } XSRETURN_EMPTY; } @@ -1689,14 +1689,14 @@ XS(XS__toggle_spawn_event) { dXSARGS; if (items != 4) - Perl_croak(aTHX_ "Usage: toggle_spawn_event(event_id, enabled?, strict, reset_base)"); + Perl_croak(aTHX_ "Usage: toggle_spawn_event(event_id, is_enabled, is_strict, reset_base)"); uint32 event_id = (int)SvIV(ST(0)); - bool enabled = ((int)SvIV(ST(1))) == 0?false:true; - bool strict = ((int)SvIV(ST(2))) == 0?false:true; + bool is_enabled = ((int)SvIV(ST(1))) == 0?false:true; + bool is_strict = ((int)SvIV(ST(2))) == 0?false:true; bool reset_base = ((int)SvIV(ST(3))) == 0?false:true; - quest_manager.toggle_spawn_event(event_id, enabled, strict, reset_base); + quest_manager.toggle_spawn_event(event_id, is_enabled, is_strict, reset_base); XSRETURN_EMPTY; } @@ -1825,22 +1825,22 @@ XS(XS__forcedooropen) { dXSARGS; if (items < 1 || items > 2) - Perl_croak(aTHX_ "Usage: forcedooropen(doorid [, altmode=0])"); + Perl_croak(aTHX_ "Usage: forcedooropen(door_id, [alt_mode=0])"); if (items == 1) { - uint32 did = (int)SvIV(ST(0)); + uint32 door_id = (int)SvIV(ST(0)); - quest_manager.forcedooropen(did, false); + quest_manager.forcedooropen(door_id, false); XSRETURN_EMPTY; } else { - uint32 did = (int)SvIV(ST(0)); - bool am = (int)SvIV(ST(1)) == 0?false:true; + uint32 door_id = (int)SvIV(ST(0)); + bool alt_mode = (int)SvIV(ST(1)) == 0?false:true; - quest_manager.forcedooropen(did, am); + quest_manager.forcedooropen(door_id, alt_mode); XSRETURN_EMPTY; } @@ -1851,22 +1851,22 @@ XS(XS__forcedoorclose) { dXSARGS; if (items < 1 || items > 2) - Perl_croak(aTHX_ "Usage: forcedoorclose(doorid [, altmode=0])"); + Perl_croak(aTHX_ "Usage: forcedoorclose(door_id, [alt_mode=0])"); if (items == 1) { - uint32 did = (int)SvIV(ST(0)); + uint32 door_id = (int)SvIV(ST(0)); - quest_manager.forcedoorclose(did, false); + quest_manager.forcedoorclose(door_id, false); XSRETURN_EMPTY; } else { - uint32 did = (int)SvIV(ST(0)); - bool am = (int)SvIV(ST(1)) == 0?false:true; + uint32 door_id = (int)SvIV(ST(0)); + bool alt_mode = (int)SvIV(ST(1)) == 0?false:true; - quest_manager.forcedoorclose(did, am); + quest_manager.forcedoorclose(door_id, alt_mode); XSRETURN_EMPTY; } @@ -1877,11 +1877,11 @@ XS(XS__toggledoorstate) { dXSARGS; if (items !=1) - Perl_croak(aTHX_ "Usage: toggledoorstate(doorid)"); + Perl_croak(aTHX_ "Usage: toggledoorstate(door_id)"); - uint32 did = (int)SvIV(ST(0)); + uint32 door_id = (int)SvIV(ST(0)); - quest_manager.toggledoorstate(did); + quest_manager.toggledoorstate(door_id); XSRETURN_EMPTY; } @@ -1891,14 +1891,14 @@ XS(XS__isdooropen) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: isdooropen(doorid)"); + Perl_croak(aTHX_ "Usage: isdooropen(door_id)"); bool RETVAL; dXSTARG; - uint32 doorid = (int)SvIV(ST(0)); + uint32 door_id = (int)SvIV(ST(0)); - RETVAL = quest_manager.isdooropen(doorid); + RETVAL = quest_manager.isdooropen(door_id); XSprePUSH; PUSHu((IV)RETVAL); XSRETURN(1); @@ -1955,19 +1955,19 @@ XS(XS__AddNode) if (items < 3 || items > 5) Perl_croak(aTHX_ "Usage: AddNode(x, y, z, [best_z], [requested_id])"); - int x = (int)SvIV(ST(0)); - int y = (int)SvIV(ST(1)); - int z = (int)SvIV(ST(2)); + float x = (float)SvNV(ST(0)); + float y = (float)SvNV(ST(1)); + float z = (float)SvNV(ST(2)); int best_z = 0; int requested_id = 0; if (items == 4) { - best_z = (int)SvIV(ST(3)); + best_z = (float)SvNV(ST(3)); } else if (items == 5) { - best_z = (int)SvIV(ST(3)); + best_z = (float)SvNV(ST(3)); requested_id = (int)SvIV(ST(4)); } @@ -2009,11 +2009,11 @@ XS(XS__npcsize) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: npcsize(newsize)"); + Perl_croak(aTHX_ "Usage: npcsize(size)"); - int newsize = (int)SvIV(ST(0)); + int size = (int)SvIV(ST(0)); - quest_manager.npcsize(newsize); + quest_manager.npcsize(size); XSRETURN_EMPTY; } @@ -2023,11 +2023,11 @@ XS(XS__npctexture) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: npctexture(newtexture)"); + Perl_croak(aTHX_ "Usage: npctexture(texture_id)"); - int newtexture = (int)SvIV(ST(0)); + int texture_id = (int)SvIV(ST(0)); - quest_manager.npctexture(newtexture); + quest_manager.npctexture(texture_id); XSRETURN_EMPTY; } @@ -2079,11 +2079,11 @@ XS(XS__playertexture) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: playertexture(newtexture)"); + Perl_croak(aTHX_ "Usage: playertexture(texture_id)"); - int newtexture = (int)SvIV(ST(0)); + int texture_id = (int)SvIV(ST(0)); - quest_manager.playertexture(newtexture); + quest_manager.playertexture(texture_id); XSRETURN_EMPTY; } @@ -2093,12 +2093,12 @@ XS(XS__playerfeature) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: playerfeature(feature, setting)"); + Perl_croak(aTHX_ "Usage: playerfeature(str_value, int_value)"); - char * feature = (char *)SvPV_nolen(ST(0)); - int setting = (int)SvIV(ST(1)); + char * str_value = (char *)SvPV_nolen(ST(0)); + int int_value = (int)SvIV(ST(1)); - quest_manager.playerfeature(feature, setting); + quest_manager.playerfeature(str_value, int_value); XSRETURN_EMPTY; } @@ -2108,12 +2108,12 @@ XS(XS__npcfeature) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: npcfeature(feature, setting)"); + Perl_croak(aTHX_ "Usage: npcfeature(str_value, int_value)"); - char * feature = (char *)SvPV_nolen(ST(0)); - int setting = (int)SvIV(ST(1)); + char * str_value = (char *)SvPV_nolen(ST(0)); + int int_value = (int)SvIV(ST(1)); - quest_manager.npcfeature(feature, setting); + quest_manager.npcfeature(str_value, int_value); XSRETURN_EMPTY; } @@ -2168,17 +2168,17 @@ XS(XS__createBot) if(items != 6) { - Perl_croak(aTHX_ "Usage: createBot(firstname, lastname, level, race, class, gender)"); + Perl_croak(aTHX_ "Usage: createBot(firstname, lastname, level, race_id, class_id, gender_id)"); } char *firstname = (char *)SvPV_nolen(ST(0)); char *lastname = (char *)SvPV_nolen(ST(1)); int level = (int) SvIV(ST(2)); - int race = (int) SvIV(ST(3)); - int botclass = (int) SvIV(ST(4)); - int gender = (int) SvIV(ST(5)); + int race_id = (int) SvIV(ST(3)); + int class_id = (int) SvIV(ST(4)); + int gender_id = (int) SvIV(ST(5)); - RETVAL = quest_manager.createBot(firstname, lastname, level, race, botclass, gender); + RETVAL = quest_manager.createBot(firstname, lastname, level, race_id, class_id, gender_id); XSprePUSH; PUSHu((IV)RETVAL); XSRETURN(1); } @@ -2196,20 +2196,20 @@ XS(XS__taskselector) } quest_manager.taskselector(items, tasks); } else { - Perl_croak(aTHX_ "Usage: taskselector(taskid1, taskid2, ..., taskid%i)", MAXCHOOSERENTRIES); + Perl_croak(aTHX_ "Usage: taskselector(task_id1, task_id2, ..., task_id%i)", MAXCHOOSERENTRIES); } XSRETURN_EMPTY; } -XS(XS__tasksetselector); -XS(XS__tasksetselector) +XS(XS__task_setselector); +XS(XS__task_setselector) { dXSARGS; if(items == 1) { - int tasksetid = (int)SvIV(ST(0)); - quest_manager.tasksetselector(tasksetid); + int task_setid = (int)SvIV(ST(0)); + quest_manager.tasksetselector(task_setid); } else { - Perl_croak(aTHX_ "Usage: tasksetselector(tasksetid)"); + Perl_croak(aTHX_ "Usage: task_setselector(task_setid)"); } XSRETURN_EMPTY; @@ -2225,7 +2225,7 @@ XS(XS__enabletask) } quest_manager.enabletask(items, tasks); } else { - Perl_croak(aTHX_ "Usage: enabletask(taskid1, taskid2, ..., taskid10"); + Perl_croak(aTHX_ "Usage: enabletask(task_id1, task_id2, ..., task_id10"); } XSRETURN_EMPTY; @@ -2241,7 +2241,7 @@ XS(XS__disabletask) } quest_manager.disabletask(items, tasks); } else { - Perl_croak(aTHX_ "Usage: disabletask(taskid1, taskid2, ..., taskid10"); + Perl_croak(aTHX_ "Usage: disabletask(task_id1, task_id2, ..., task_id10"); } XSRETURN_EMPTY; @@ -2255,10 +2255,10 @@ XS(XS__istaskenabled) dXSTARG; if(items == 1) { - unsigned int taskid = (int)SvIV(ST(0)); - RETVAL = quest_manager.istaskenabled(taskid); + unsigned int task_id = (int)SvIV(ST(0)); + RETVAL = quest_manager.istaskenabled(task_id); } else { - Perl_croak(aTHX_ "Usage: istaskenabled(taskid)"); + Perl_croak(aTHX_ "Usage: istaskenabled(task_id)"); } XSprePUSH; PUSHu((IV)RETVAL); @@ -2273,10 +2273,10 @@ XS(XS__istaskactive) dXSTARG; if(items == 1) { - unsigned int task = (int)SvIV(ST(0)); - RETVAL = quest_manager.istaskactive(task); + unsigned int task_id = (int)SvIV(ST(0)); + RETVAL = quest_manager.istaskactive(task_id); } else { - Perl_croak(aTHX_ "Usage: istaskactive(task)"); + Perl_croak(aTHX_ "Usage: istaskactive(task_id)"); } XSprePUSH; PUSHu((IV)RETVAL); @@ -2291,11 +2291,11 @@ XS(XS__istaskactivityactive) dXSTARG; if(items == 2) { - unsigned int task = (int)SvIV(ST(0)); - unsigned int activity = (int)SvIV(ST(1)); - RETVAL = quest_manager.istaskactivityactive(task, activity); + unsigned int task_id = (int)SvIV(ST(0)); + unsigned int activity_id = (int)SvIV(ST(1)); + RETVAL = quest_manager.istaskactivityactive(task_id, activity_id); } else { - Perl_croak(aTHX_ "Usage: istaskactivityactive(task,activity)"); + Perl_croak(aTHX_ "Usage: istaskactivityactive(task_id, activity_id)"); } XSprePUSH; PUSHu((IV)RETVAL); @@ -2310,12 +2310,12 @@ XS(XS__gettaskactivitydonecount) dXSTARG; if(items == 2) { - unsigned int task = (int)SvIV(ST(0)); - unsigned int activity = (int)SvIV(ST(1)); - RETVAL = quest_manager.gettaskactivitydonecount(task, activity); + unsigned int task_id = (int)SvIV(ST(0)); + unsigned int activity_id = (int)SvIV(ST(1)); + RETVAL = quest_manager.gettaskactivitydonecount(task_id, activity_id); XSprePUSH; PUSHu((UV)RETVAL); } else { - Perl_croak(aTHX_ "Usage: gettaskactivitydonecount(task,activity)"); + Perl_croak(aTHX_ "Usage: gettaskactivitydonecount(task_id, activity_id)"); } XSRETURN(1); @@ -2324,24 +2324,24 @@ XS(XS__updatetaskactivity); XS(XS__updatetaskactivity) { dXSARGS; - unsigned int task, activity; + unsigned int task_id, activity_id; 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, false); + task_id = (int)SvIV(ST(0)); + activity_id = (int)SvIV(ST(1)); + quest_manager.updatetaskactivity(task_id, activity_id, count, false); } else if (items == 3 || items == 4) { - task = (int)SvIV(ST(0)); - activity = (int)SvIV(ST(1)); + task_id = (int)SvIV(ST(0)); + activity_id = (int)SvIV(ST(1)); count = (int)SvIV(ST(2)); if (items == 4){ bool ignore_quest_update = (bool)SvTRUE(ST(3)); } - quest_manager.updatetaskactivity(task, activity, count, ignore_quest_update); + quest_manager.updatetaskactivity(task_id, activity_id, count, ignore_quest_update); } else { - Perl_croak(aTHX_ "Usage: updatetaskactivity(task, activity, [count], [ignore_quest_update])"); + Perl_croak(aTHX_ "Usage: updatetaskactivity(task_id, activity_id, [count], [ignore_quest_update])"); } XSRETURN_EMPTY; @@ -2353,11 +2353,13 @@ XS(XS__resettaskactivity) dXSARGS; unsigned int task, activity; if(items == 2) { - task = (int)SvIV(ST(0)); - activity = (int)SvIV(ST(1)); - quest_manager.resettaskactivity(task, activity); + int task_id = (int)SvIV(ST(0)); + int activity_id = (int)SvIV(ST(1)); + + quest_manager.resettaskactivity(task_id, activity_id); + } else { - Perl_croak(aTHX_ "Usage: resettaskactivity(task, activity)"); + Perl_croak(aTHX_ "Usage: resettaskactivity(task_id, activity_id)"); } XSRETURN_EMPTY; @@ -2367,12 +2369,12 @@ XS(XS__taskexploredarea); XS(XS__taskexploredarea) { dXSARGS; - unsigned int exploreid; + unsigned int explore_id; if(items == 1) { - exploreid = (int)SvIV(ST(0)); - quest_manager.taskexploredarea(exploreid); + explore_id = (int)SvIV(ST(0)); + quest_manager.taskexploredarea(explore_id); } else { - Perl_croak(aTHX_ "Usage: taskexplorearea(exploreid)"); + Perl_croak(aTHX_ "Usage: taskexplorearea(explore_id)"); } XSRETURN_EMPTY; @@ -2382,10 +2384,10 @@ XS(XS__assigntask); XS(XS__assigntask) { dXSARGS; - unsigned int taskid; + unsigned int task_id; bool enforce_level_requirement = false; if(items == 1 || items == 2) { - taskid = (int)SvIV(ST(0)); + task_id = (int)SvIV(ST(0)); if (items == 2) { if ((int)SvIV(ST(1)) == 1) @@ -2393,9 +2395,9 @@ XS(XS__assigntask) enforce_level_requirement = true; } } - quest_manager.assigntask(taskid, enforce_level_requirement); + quest_manager.assigntask(task_id, enforce_level_requirement); } else { - Perl_croak(aTHX_ "Usage: assigntask(taskid, enforce_level_requirement)"); + Perl_croak(aTHX_ "Usage: assigntask(task_id, enforce_level_requirement)"); } XSRETURN_EMPTY; @@ -2405,12 +2407,12 @@ XS(XS__failtask); XS(XS__failtask) { dXSARGS; - unsigned int taskid; + unsigned int task_id; if(items == 1) { - taskid = (int)SvIV(ST(0)); - quest_manager.failtask(taskid); + task_id = (int)SvIV(ST(0)); + quest_manager.failtask(task_id); } else { - Perl_croak(aTHX_ "Usage: failtask(taskid)"); + Perl_croak(aTHX_ "Usage: failtask(task_id)"); } XSRETURN_EMPTY; @@ -2424,10 +2426,10 @@ XS(XS__tasktimeleft) dXSTARG; if(items == 1) { - unsigned int taskid = (int)SvIV(ST(0)); - RETVAL = quest_manager.tasktimeleft(taskid); + unsigned int task_id = (int)SvIV(ST(0)); + RETVAL = quest_manager.tasktimeleft(task_id); } else { - Perl_croak(aTHX_ "Usage: tasktimeleft(taskid)"); + Perl_croak(aTHX_ "Usage: tasktimeleft(task_id)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2443,10 +2445,10 @@ XS(XS__istaskcompleted) dXSTARG; if(items == 1) { - unsigned int taskid = (int)SvIV(ST(0)); - RETVAL = quest_manager.istaskcompleted(taskid); + unsigned int task_id = (int)SvIV(ST(0)); + RETVAL = quest_manager.istaskcompleted(task_id); } else { - Perl_croak(aTHX_ "Usage: istaskcompleted(taskid)"); + Perl_croak(aTHX_ "Usage: istaskcompleted(task_id)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2462,10 +2464,10 @@ XS(XS__enabledtaskcount) dXSTARG; if(items == 1) { - unsigned int taskset = (int)SvIV(ST(0)); - RETVAL = quest_manager.enabledtaskcount(taskset); + unsigned int task_set = (int)SvIV(ST(0)); + RETVAL = quest_manager.enabledtaskcount(task_set); } else { - Perl_croak(aTHX_ "Usage: enabledtaskcount(taskset)"); + Perl_croak(aTHX_ "Usage: enabledtaskcount(task_set)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2481,10 +2483,10 @@ XS(XS__firsttaskinset) dXSTARG; if(items == 1) { - unsigned int taskset = (int)SvIV(ST(0)); - RETVAL = quest_manager.firsttaskinset(taskset); + unsigned int task_set = (int)SvIV(ST(0)); + RETVAL = quest_manager.firsttaskinset(task_set); } else { - Perl_croak(aTHX_ "Usage: firsttaskinset(taskset)"); + Perl_croak(aTHX_ "Usage: firsttaskinset(task_set)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2500,10 +2502,10 @@ XS(XS__lasttaskinset) dXSTARG; if(items == 1) { - unsigned int taskset = (int)SvIV(ST(0)); - RETVAL = quest_manager.lasttaskinset(taskset); + unsigned int task_set = (int)SvIV(ST(0)); + RETVAL = quest_manager.lasttaskinset(task_set); } else { - Perl_croak(aTHX_ "Usage: lasttaskinset(taskset)"); + Perl_croak(aTHX_ "Usage: lasttaskinset(task_set)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2519,11 +2521,11 @@ XS(XS__nexttaskinset) dXSTARG; if(items == 2) { - unsigned int taskset = (int)SvIV(ST(0)); - unsigned int taskid = (int)SvIV(ST(1)); - RETVAL = quest_manager.nexttaskinset(taskset, taskid); + unsigned int task_set = (int)SvIV(ST(0)); + unsigned int task_id = (int)SvIV(ST(1)); + RETVAL = quest_manager.nexttaskinset(task_set, task_id); } else { - Perl_croak(aTHX_ "Usage: nexttaskinset(taskset, taskid)"); + Perl_croak(aTHX_ "Usage: nexttaskinset(task_set, task_id)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2556,10 +2558,10 @@ XS(XS__activespeakactivity) dXSTARG; if(items == 1) { - unsigned int taskid = (int)SvIV(ST(0)); - RETVAL = quest_manager.activespeakactivity(taskid); + unsigned int task_id = (int)SvIV(ST(0)); + RETVAL = quest_manager.activespeakactivity(task_id); } else { - Perl_croak(aTHX_ "Usage: activespeakactivity(taskid)"); + Perl_croak(aTHX_ "Usage: activespeakactivity(task_id)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2575,10 +2577,10 @@ XS(XS__activetasksinset) dXSTARG; if(items == 1) { - unsigned int taskset = (int)SvIV(ST(0)); - RETVAL = quest_manager.activetasksinset(taskset); + unsigned int task_set = (int)SvIV(ST(0)); + RETVAL = quest_manager.activetasksinset(task_set); } else { - Perl_croak(aTHX_ "Usage: activetasksinset(taskset)"); + Perl_croak(aTHX_ "Usage: activetasksinset(task_set)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2594,10 +2596,10 @@ XS(XS__completedtasksinset) dXSTARG; if(items == 1) { - unsigned int taskset = (int)SvIV(ST(0)); - RETVAL = quest_manager.completedtasksinset(taskset); + unsigned int task_set = (int)SvIV(ST(0)); + RETVAL = quest_manager.completedtasksinset(task_set); } else { - Perl_croak(aTHX_ "Usage: completedtasksinset(taskset)"); + Perl_croak(aTHX_ "Usage: completedtasksinset(task_set)"); } XSprePUSH; PUSHi((IV)RETVAL); @@ -2628,15 +2630,15 @@ XS(XS__istaskappropriate) XS(XS__popup); // prototype to pass -Wmissing-prototypes XS(XS__popup) { dXSARGS; - int popupid = 0; + int popup_id = 0; int buttons = 0; int duration = 0; if((items < 2) || (items > 5)) - Perl_croak(aTHX_ "Usage: popup(windowtitle, text, popupid, buttons, duration)"); + Perl_croak(aTHX_ "Usage: popup(window_title, message, popup_id, buttons, duration)"); if(items >= 3) - popupid = (int)SvIV(ST(2)); + popup_id = (int)SvIV(ST(2)); if(items >= 4) buttons = (int)SvIV(ST(3)); @@ -2644,7 +2646,7 @@ XS(XS__istaskappropriate) if(items == 5) duration = (int)SvIV(ST(4)); - quest_manager.popup(SvPV_nolen(ST(0)), SvPV_nolen(ST(1)), popupid, buttons, duration); + quest_manager.popup(SvPV_nolen(ST(0)), SvPV_nolen(ST(1)), popup_id, buttons, duration); XSRETURN_EMPTY; } @@ -2666,12 +2668,12 @@ XS(XS__ze) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: ze(type, str)"); + Perl_croak(aTHX_ "Usage: ze(channel_id, message)"); - int type = (int)SvIV(ST(0)); - char * str = (char *)SvPV_nolen(ST(1)); + int channel_id = (int)SvIV(ST(0)); + char * message = (char *)SvPV_nolen(ST(1)); - quest_manager.ze(type, str); + quest_manager.ze(channel_id, message); XSRETURN_EMPTY; } @@ -2681,12 +2683,12 @@ XS(XS__we) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: we(type, str)"); + Perl_croak(aTHX_ "Usage: we(channel_id, message)"); - int type = (int)SvIV(ST(0)); - char * str = (char *)SvPV_nolen(ST(1)); + int channel_id = (int)SvIV(ST(0)); + char * message = (char *)SvPV_nolen(ST(1)); - quest_manager.we(type, str); + quest_manager.we(channel_id, message); XSRETURN_EMPTY; } @@ -2718,9 +2720,9 @@ XS(XS__CreateGroundObject) { dXSARGS; if (items != 5 && items != 6) - Perl_croak(aTHX_ "Usage: creategroundobject(itemid, x, y, z, heading, [decay_time])"); + Perl_croak(aTHX_ "Usage: creategroundobject(item_id, x, y, z, heading, [decay_time])"); - int itemid = (int)SvIV(ST(0)); + int item_id = (int)SvIV(ST(0)); float x = (float)SvNV(ST(1)); float y = (float)SvNV(ST(2)); float z = (float)SvNV(ST(3)); @@ -2728,10 +2730,10 @@ XS(XS__CreateGroundObject) uint16 id = 0; if(items == 5) - id = quest_manager.CreateGroundObject(itemid, glm::vec4(x, y, z, heading)); + id = quest_manager.CreateGroundObject(item_id, glm::vec4(x, y, z, heading)); else{ uint32 decay_time = (uint32)SvIV(ST(5)); - id = quest_manager.CreateGroundObject(itemid, glm::vec4(x, y, z, heading), decay_time); + id = quest_manager.CreateGroundObject(item_id, glm::vec4(x, y, z, heading), decay_time); } XSRETURN_IV(id); @@ -2742,24 +2744,24 @@ XS(XS__CreateGroundObjectFromModel) { dXSARGS; if (items < 5 || items > 7) - Perl_croak(aTHX_ "Usage: creategroundobjectfrommodel(modelname, x, y, z, heading, [type], [decay_time])"); + Perl_croak(aTHX_ "Usage: creategroundobjectfrommodel(modelname, x, y, z, heading, [object_type], [decay_time])"); char * modelname = (char *)SvPV_nolen(ST(0)); float x = (float)SvNV(ST(1)); float y = (float)SvNV(ST(2)); float z = (float)SvNV(ST(3)); float heading = (float)SvNV(ST(4)); - uint32 type = 0; + uint32 object_type = 0; uint32 decay_time = 0; uint16 id = 0; if (items > 5) - type = (uint32)SvIV(ST(5)); + object_type = (uint32)SvIV(ST(5)); if (items > 6) decay_time = (uint32)SvIV(ST(6)); - id = quest_manager.CreateGroundObjectFromModel(modelname, glm::vec4(x, y, z, heading), type, decay_time); + id = quest_manager.CreateGroundObjectFromModel(modelname, glm::vec4(x, y, z, heading), object_type, decay_time); XSRETURN_IV(id); } @@ -2768,24 +2770,24 @@ XS(XS__CreateDoor) { dXSARGS; if (items < 5 || items > 7) - Perl_croak(aTHX_ "Usage: createdoor(modelname, x, y, z, heading, [type], [size])"); + Perl_croak(aTHX_ "Usage: createdoor(modelname, x, y, z, heading, [object_type], [size])"); char * modelname = (char *)SvPV_nolen(ST(0)); float x = (float)SvNV(ST(1)); float y = (float)SvNV(ST(2)); float z = (float)SvNV(ST(3)); float heading = (float)SvNV(ST(4)); - uint32 type = 58; + uint32 object_type = 58; uint32 size = 100; uint16 id = 0; if (items > 5) - type = (uint32)SvIV(ST(5)); + object_type = (uint32)SvIV(ST(5)); if (items > 6) size = (uint32)SvIV(ST(6)); - id = quest_manager.CreateDoor(modelname, x, y, z, heading, type, size); + id = quest_manager.CreateDoor(modelname, x, y, z, heading, object_type, size); XSRETURN_IV(id); } @@ -2794,7 +2796,7 @@ XS(XS__ModifyNPCStat) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: ModifyNPCStat(identifier, newValue)"); + Perl_croak(aTHX_ "Usage: ModifyNPCStat(stat_id, str_value)"); quest_manager.ModifyNPCStat(SvPV_nolen(ST(0)), SvPV_nolen(ST(1))); @@ -2806,13 +2808,13 @@ XS(XS__collectitems) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: collectitems(item_id, remove?)"); + Perl_croak(aTHX_ "Usage: collectitems(item_id, remove_item)"); uint32 item_id = (int)SvIV(ST(0)); - bool remove = ((int)SvIV(ST(1))) == 0?false:true; + bool remove_item = ((int)SvIV(ST(1))) == 0?false:true; int quantity = - quest_manager.collectitems(item_id, remove); + quest_manager.collectitems(item_id, remove_item); XSRETURN_IV(quantity); } @@ -2822,12 +2824,12 @@ XS(XS__UpdateSpawnTimer) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: UpdateSpawnTimer(Spawn2_ID, Updated_Time_Till_Repop)"); + Perl_croak(aTHX_ "Usage: UpdateSpawnTimer(spawn2_id, updated_time_till_repop)"); - uint32 id = (int)SvIV(ST(0)); - uint32 duration = (int)SvIV(ST(1)); + uint32 spawn2_id = (int)SvIV(ST(0)); + uint32 updated_time_till_repop = (int)SvIV(ST(1)); - quest_manager.UpdateSpawnTimer(id, duration); + quest_manager.UpdateSpawnTimer(spawn2_id, updated_time_till_repop); XSRETURN_EMPTY; } @@ -2836,15 +2838,15 @@ XS(XS__MerchantSetItem); XS(XS__MerchantSetItem) { dXSARGS; if (items != 2 && items != 3) - Perl_croak(aTHX_ "Usage: MerchantSetItem(NPCid, itemid [, quantity])"); + Perl_croak(aTHX_ "Usage: MerchantSetItem(npc_id, item_id [, quantity])"); - uint32 NPCid = (int)SvUV(ST(0)); - uint32 itemid = (int)SvUV(ST(1)); + uint32 npc_id = (int)SvUV(ST(0)); + uint32 item_id = (int)SvUV(ST(1)); uint32 quantity = 0; if (items == 3) quantity = (int)SvUV(ST(2)); - quest_manager.MerchantSetItem(NPCid, itemid, quantity); + quest_manager.MerchantSetItem(npc_id, item_id, quantity); XSRETURN_EMPTY; } @@ -2853,11 +2855,11 @@ XS(XS__MerchantCountItem); XS(XS__MerchantCountItem) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: MerchantCountItem(NPCid, itemid)"); + Perl_croak(aTHX_ "Usage: MerchantCountItem(npc_id, item_id)"); - uint32 NPCid = (int)SvUV(ST(0)); - uint32 itemid = (int)SvUV(ST(1)); - uint32 quantity = quest_manager.MerchantCountItem(NPCid, itemid); + uint32 npc_id = (int)SvUV(ST(0)); + uint32 item_id = (int)SvUV(ST(1)); + uint32 quantity = quest_manager.MerchantCountItem(npc_id, item_id); XSRETURN_UV(quantity); } @@ -2866,15 +2868,15 @@ XS(XS__varlink); XS(XS__varlink) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: varlink(itemID)"); + Perl_croak(aTHX_ "Usage: varlink(item_id)"); dXSTARG; Const_char * RETVAL; char text[250]; - uint32 itemID; - itemID = (int)SvUV(ST(0)); + uint32 item_id; + item_id = (int)SvUV(ST(0)); - RETVAL = quest_manager.varlink(text, itemID); + RETVAL = quest_manager.varlink(text, item_id); sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; XSRETURN(1); @@ -2910,11 +2912,11 @@ XS(XS__UpdateInstanceTimer); XS(XS__UpdateInstanceTimer) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: UpdateInstanceTimer(instance_id, new_duration)"); + Perl_croak(aTHX_ "Usage: UpdateInstanceTimer(instance_id, duration)"); uint16 instance_id = (uint16)SvUV(ST(0)); - uint32 new_duration = (uint32)SvUV(ST(1)); - quest_manager.UpdateInstanceTimer(instance_id, new_duration); + uint32 duration = (uint32)SvUV(ST(1)); + quest_manager.UpdateInstanceTimer(instance_id, duration); XSRETURN_EMPTY; } @@ -2964,29 +2966,29 @@ XS(XS__GetCharactersInInstance) { Const_char * RETVAL; uint16 instance_id = (int)SvUV(ST(0)); - std::list charid_list; - std::string charid_string; + std::list char_id_list; + std::string char_id_string; - database.GetCharactersInInstance(instance_id, charid_list); + database.GetCharactersInInstance(instance_id, char_id_list); - if (charid_list.size() > 0) + if (char_id_list.size() > 0) { - charid_string = itoa(charid_list.size()); - charid_string += " player(s) in instance: "; - auto iter = charid_list.begin(); - while (iter != charid_list.end()) + char_id_string = itoa(char_id_list.size()); + char_id_string += " player(s) in instance: "; + auto iter = char_id_list.begin(); + while (iter != char_id_list.end()) { char char_name[64]; database.GetCharName(*iter, char_name); - charid_string += char_name; - charid_string += "("; - charid_string += itoa(*iter); - charid_string += ")"; + char_id_string += char_name; + char_id_string += "("; + char_id_string += itoa(*iter); + char_id_string += ")"; ++iter; - if (iter != charid_list.end()) - charid_string += ", "; + if (iter != char_id_list.end()) + char_id_string += ", "; } - RETVAL = charid_string.c_str(); + RETVAL = char_id_string.c_str(); } else RETVAL = "No players in that instance."; @@ -3062,7 +3064,7 @@ XS(XS__MovePCInstance) if (items != 5 && items != 6) Perl_croak(aTHX_ "Usage: MovePCInstance(zone_id, instance_id, x, y, z [,heading])"); - int zoneid = (int)SvIV(ST(0)); + int zone_id = (int)SvIV(ST(0)); int instanceid = (int)SvIV(ST(1)); float x = (float)SvNV(ST(2)); float y = (float)SvNV(ST(3)); @@ -3070,12 +3072,12 @@ XS(XS__MovePCInstance) if (items == 4) { - quest_manager.MovePCInstance(zoneid, instanceid, glm::vec4(x, y, z, 0.0f)); + quest_manager.MovePCInstance(zone_id, instanceid, glm::vec4(x, y, z, 0.0f)); } else { float heading = (float)SvNV(ST(5)); - quest_manager.MovePCInstance(zoneid, instanceid, glm::vec4(x, y, z, heading)); + quest_manager.MovePCInstance(zone_id, instanceid, glm::vec4(x, y, z, heading)); } XSRETURN_EMPTY; @@ -3111,23 +3113,23 @@ XS(XS__saylink); XS(XS__saylink) { dXSARGS; if (items < 1 || items > 3) - Perl_croak(aTHX_ "Usage: saylink(phrase,[silent?],[linkname])"); + Perl_croak(aTHX_ "Usage: saylink(message, [silent?], [link_name])"); dXSTARG; Const_char * RETVAL; - char text[250]; - char text2[250]; + char message[250]; + char link_name[250]; bool silent = false; - strcpy(text,(char *)SvPV_nolen(ST(0))); + strcpy(message,(char *)SvPV_nolen(ST(0))); if(items >= 2) { silent = ((int)SvIV(ST(1))) == 0 ? false : true; } if (items == 3) - strcpy(text2,(char *)SvPV_nolen(ST(2))); + strcpy(link_name,(char *)SvPV_nolen(ST(2))); else - strcpy(text2,text); + strcpy(link_name,message); - RETVAL = quest_manager.saylink(text, silent, text2); + RETVAL = quest_manager.saylink(message, silent, link_name); sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; XSRETURN(1); } @@ -3318,21 +3320,21 @@ XS(XS__wearchange) { dXSARGS; if (items < 2) - Perl_croak(aTHX_ "Usage: wearchange(slot, texture, [hero_forge_model], [elite_material])"); + Perl_croak(aTHX_ "Usage: wearchange(slot, texture_id, [hero_forge_model_id], [elite_material_id])"); uint8 slot = (int)SvUV(ST(0)); - uint16 texture = (int)SvUV(ST(1)); + uint16 texture_id = (int)SvUV(ST(1)); - uint32 hero_forge_model = 0; - uint32 elite_material = 0; + uint32 hero_forge_model_id= 0; + uint32 elite_material_id = 0; if (items > 2) - hero_forge_model = (int)SvUV(ST(2)); + hero_forge_model_id= (int)SvUV(ST(2)); if (items > 3) - elite_material = (int)SvUV(ST(3)); + elite_material_id = (int)SvUV(ST(3)); - quest_manager.wearchange(slot, texture, hero_forge_model, elite_material); + quest_manager.wearchange(slot, texture_id, hero_forge_model_id, elite_material_id); XSRETURN_EMPTY; } @@ -3342,14 +3344,14 @@ XS(XS__voicetell) { dXSARGS; if (items != 4) - Perl_croak(aTHX_ "Usage: voicetell(clientname, type, race, gender)"); + Perl_croak(aTHX_ "Usage: voicetell(client_name, macro_id, race_id, gender_id)"); - char * str = (char *)SvPV_nolen(ST(0)); - int macronum = (int)SvIV(ST(1)); - int racenum = (int)SvIV(ST(2)); - int gendernum = (int)SvIV(ST(3)); + char * client_name = (char *)SvPV_nolen(ST(0)); + int macro_id = (int)SvIV(ST(1)); + int race_id = (int)SvIV(ST(2)); + int gender_id = (int)SvIV(ST(3)); - quest_manager.voicetell(str, macronum, racenum, gendernum); + quest_manager.voicetell(client_name, macro_id, race_id, gender_id); XSRETURN_EMPTY; } @@ -3426,20 +3428,20 @@ XS(XS__GetTimeSeconds) XSRETURN_UV(seconds); } -XS(XS__crosszonesignalclientbycharid); -XS(XS__crosszonesignalclientbycharid) +XS(XS__crosszonesignalclientbychar_id); +XS(XS__crosszonesignalclientbychar_id) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: crosszonesignalclientbycharid(char_id, data)"); + Perl_croak(aTHX_ "Usage: crosszonesignalclientbychar_id(char_id, int_value)"); if (items == 2) { int char_id = (int)SvIV(ST(0)); - uint32 data = (uint32)SvIV(ST(1)); - quest_manager.CrossZoneSignalPlayerByCharID(char_id, data); + uint32 int_value = (uint32)SvIV(ST(1)); + quest_manager.CrossZoneSignalPlayerByCharID(char_id, int_value); } else { - Perl_croak(aTHX_ "Usage: crosszonesignalclientbycharid(char_id, data)"); + Perl_croak(aTHX_ "Usage: crosszonesignalclientbychar_id(char_id, int_value)"); } XSRETURN_EMPTY; @@ -3451,14 +3453,14 @@ XS(XS__crosszonesignalclientbyname) dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: crosszonesignalclientbycharid(Name, data)"); + Perl_croak(aTHX_ "Usage: crosszonesignalclientbychar_id(name, int_value)"); if (items == 2) { - char *Name = (char *)SvPV_nolen(ST(0)); - uint32 data = (uint32)SvIV(ST(1)); - quest_manager.CrossZoneSignalPlayerByName(Name, data); + char *name = (char *)SvPV_nolen(ST(0)); + uint32 int_value = (uint32)SvIV(ST(1)); + quest_manager.CrossZoneSignalPlayerByName(name, int_value); } else { - Perl_croak(aTHX_ "Usage: crosszonesignalclientbycharid(Name, data)"); + Perl_croak(aTHX_ "Usage: crosszonesignalclientbychar_id(name, int_value)"); } XSRETURN_EMPTY; @@ -3471,15 +3473,15 @@ XS(XS__crosszonemessageplayerbyname) dXSARGS; if (items != 3) - Perl_croak(aTHX_ "Usage: crosszonemessageplayerbyname(Type, Name, Message)"); + Perl_croak(aTHX_ "Usage: crosszonemessageplayerbyname(channel_id, name, message)"); if (items == 3) { - uint32 Type = (uint32)SvIV(ST(0)); - char *Name = (char *)SvPV_nolen(ST(1)); - char *Message = (char *)SvPV_nolen(ST(2)); - quest_manager.CrossZoneMessagePlayerByName(Type, Name, Message); + uint32 channel_id = (uint32)SvIV(ST(0)); + char *name = (char *)SvPV_nolen(ST(1)); + char *message = (char *)SvPV_nolen(ST(2)); + quest_manager.CrossZoneMessagePlayerByName(channel_id, name, message); } else { - Perl_croak(aTHX_ "Usage: crosszonemessageplayerbyname(Type, Name, Message)"); + Perl_croak(aTHX_ "Usage: crosszonemessageplayerbyname(channel_id, name, message)"); } XSRETURN_EMPTY; @@ -3531,11 +3533,11 @@ XS(XS__clear_npctype_cache) dXSARGS; if (items != 1) { - Perl_croak(aTHX_ "Usage: clear_npctype_cache(npc_id)"); + Perl_croak(aTHX_ "Usage: clear_npctype_cache(npc_type_id)"); } else { - int32 npctype_id = (int32)SvIV(ST(0)); - quest_manager.ClearNPCTypeCache(npctype_id); + int32 npc_type_id = (int32)SvIV(ST(0)); + quest_manager.ClearNPCTypeCache(npc_type_id); } XSRETURN_EMPTY; @@ -3571,12 +3573,12 @@ XS(XS__qs_player_event) { dXSARGS; if (items != 2){ - Perl_croak(aTHX_ "Usage: qs_player_event(char_id, event_desc)"); + Perl_croak(aTHX_ "Usage: qs_player_event(char_id, message)"); } else{ int char_id = (int)SvIV(ST(0)); - std::string event_desc = (std::string)SvPV_nolen(ST(1)); - QServ->PlayerLogEvent(Player_Log_Quest, char_id, event_desc); + std::string message = (std::string)SvPV_nolen(ST(1)); + QServ->PlayerLogEvent(Player_Log_Quest, char_id, message); } XSRETURN_EMPTY; } @@ -3587,31 +3589,31 @@ XS(XS__crosszonesetentityvariablebynpctypeid) dXSARGS; if (items != 3) - Perl_croak(aTHX_ "Usage: crosszonesetentityvariablebynpctypeid(npctype_id, id, m_var)"); + Perl_croak(aTHX_ "Usage: crosszonesetentityvariablebynpctypeid(npc_type_id, key, str_value)"); if (items == 3) { - uint32 npctype_id = (uint32)SvIV(ST(0)); - const char *id = (const char *)SvPV_nolen(ST(1)); - const char *m_var = (const char *)SvPV_nolen(ST(2)); - quest_manager.CrossZoneSetEntityVariableByNPCTypeID(npctype_id, id, m_var); + uint32 npc_type_id = (uint32)SvIV(ST(0)); + const char *key = (const char *)SvPV_nolen(ST(1)); + const char *str_value = (const char *)SvPV_nolen(ST(2)); + quest_manager.CrossZoneSetEntityVariableByNPCTypeID(npc_type_id, key, str_value); } XSRETURN_EMPTY; } -XS(XS__crosszonesetentityvariablebyclientname); -XS(XS__crosszonesetentityvariablebyclientname) +XS(XS__crosszonesetentityvariablebyclient_name); +XS(XS__crosszonesetentityvariablebyclient_name) { dXSARGS; if (items != 3) - Perl_croak(aTHX_ "Usage: crosszonesetentityvariablebyclientname(clientname, id, m_var)"); + Perl_croak(aTHX_ "Usage: crosszonesetentityvariablebyclient_name(client_name, key, str_value)"); if (items == 3) { - const char *clientname = (const char *)SvPV_nolen(ST(0)); - const char *id = (const char *)SvPV_nolen(ST(1)); - const char *m_var = (const char *)SvPV_nolen(ST(2)); - quest_manager.CrossZoneSetEntityVariableByClientName(clientname, id, m_var); + const char *client_name = (const char *)SvPV_nolen(ST(0)); + const char *key = (const char *)SvPV_nolen(ST(1)); + const char *str_value = (const char *)SvPV_nolen(ST(2)); + quest_manager.CrossZoneSetEntityVariableByClientName(client_name, key, str_value); } XSRETURN_EMPTY; @@ -3623,12 +3625,12 @@ XS(XS__crosszonesignalnpcbynpctypeid) dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: crosszonesignalnpcbynpctypeid(npctype_id, data)"); + Perl_croak(aTHX_ "Usage: crosszonesignalnpcbynpctypeid(npc_type_id, int_value)"); if (items == 2) { - uint32 npctype_id = (uint32)SvIV(ST(0)); - uint32 data = (uint32)SvIV(ST(1)); - quest_manager.CrossZoneSignalNPCByNPCTypeID(npctype_id, data); + uint32 npc_type_id = (uint32)SvIV(ST(0)); + uint32 int_value = (uint32)SvIV(ST(1)); + quest_manager.CrossZoneSignalNPCByNPCTypeID(npc_type_id, int_value); } XSRETURN_EMPTY; @@ -3639,16 +3641,16 @@ XS(XS__worldwidemarquee) { dXSARGS; if (items != 6) - Perl_croak(aTHX_ "Usage: worldwidemarquee(type, priority, fadein, fadeout, duration, message)"); + Perl_croak(aTHX_ "Usage: worldwidemarquee(color_id, priority, fade_in, fade_out, duration, message)"); if (items == 6) { - uint32 type = (uint32)SvIV(ST(0)); + uint32 color_id = (uint32)SvIV(ST(0)); uint32 priority = (uint32)SvIV(ST(1)); - uint32 fadein = (uint32)SvIV(ST(2)); - uint32 fadeout = (uint32)SvIV(ST(3)); + uint32 fade_in = (uint32)SvIV(ST(2)); + uint32 fade_out = (uint32)SvIV(ST(3)); uint32 duration = (uint32)SvIV(ST(4)); char* message = (char *)SvPV_nolen(ST(5)); - quest_manager.WorldWideMarquee(type, priority, fadein, fadeout, duration, message); + quest_manager.WorldWideMarquee(color_id, priority, fade_in, fade_out, duration, message); } XSRETURN_EMPTY; @@ -3688,11 +3690,11 @@ XS(XS__UpdateZoneHeader); XS(XS__UpdateZoneHeader) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: UpdateZoneHeader(type, value)"); + Perl_croak(aTHX_ "Usage: UpdateZoneHeader(key, str_value)"); - std::string type = (std::string)SvPV_nolen(ST(0)); - std::string value = (std::string)SvPV_nolen(ST(1)); - quest_manager.UpdateZoneHeader(type, value); + std::string key = (std::string)SvPV_nolen(ST(0)); + std::string str_value = (std::string)SvPV_nolen(ST(1)); + quest_manager.UpdateZoneHeader(key, str_value); XSRETURN_EMPTY; } @@ -3784,8 +3786,8 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "createguild"), XS__createguild, file); newXS(strcpy(buf, "crosszonemessageplayerbyname"), XS__crosszonemessageplayerbyname, file); newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file); - newXS(strcpy(buf, "crosszonesetentityvariablebyclientname"), XS__crosszonesetentityvariablebyclientname, file); - newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file); + newXS(strcpy(buf, "crosszonesetentityvariablebyclient_name"), XS__crosszonesetentityvariablebyclient_name, file); + newXS(strcpy(buf, "crosszonesignalclientbychar_id"), XS__crosszonesignalclientbychar_id, file); newXS(strcpy(buf, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, file); newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file); newXS(strcpy(buf, "worldwidemarquee"), XS__worldwidemarquee, file); @@ -3917,7 +3919,7 @@ EXTERN_C XS(boot_quest) 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, "task_setselector"), XS__task_setselector, 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); diff --git a/zone/entity.cpp b/zone/entity.cpp index 0ab10982a..e54042d5a 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -644,7 +644,6 @@ void EntityList::AddCorpse(Corpse *corpse, uint32 in_id) void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) { npc->SetID(GetFreeID()); - npc->SetMerchantProbability((uint8) zone->random.Int(0, 99)); parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); @@ -3257,7 +3256,7 @@ void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate) for (auto &e : npc_list) { auto &npc = e.second; - if (!npc->CheckAggro(target) || npc->IsFeared()) + if (!npc->CheckAggro(target) || npc->IsFeared() || npc->IsPet()) continue; if (zone->random.Roll(50)) // witness check -- place holder @@ -4871,3 +4870,12 @@ void EntityList::SendAlternateAdvancementStats() { c.second->SendAlternateAdvancementPoints(); } } + +void EntityList::ReloadMerchants() { + for (auto it = npc_list.begin();it != npc_list.end(); ++it) { + NPC *cur = it->second; + if (cur->MerchantType != 0) { + zone->LoadNewMerchantData(cur->MerchantType); + } + } +} diff --git a/zone/entity.h b/zone/entity.h index dccbb45b3..ec29b3581 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -244,6 +244,7 @@ public: void AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z); void RemoveArea(int id); void ClearAreas(); + void ReloadMerchants(); void ProcessProximitySay(const char *Message, Client *c, uint8 language = 0); void SendAATimer(uint32 charid,UseAA_Struct* uaa); Doors *FindDoor(uint8 door_id); diff --git a/zone/exp.cpp b/zone/exp.cpp index 7d9a02fa8..2902610a8 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -37,6 +37,49 @@ extern QueryServ* QServ; +static uint32 ScaleAAXPBasedOnCurrentAATotal(int earnedAA, uint32 add_aaxp) +{ + float baseModifier = RuleR(AA, ModernAAScalingStartPercent); + int aaMinimum = RuleI(AA, ModernAAScalingAAMinimum); + int aaLimit = RuleI(AA, ModernAAScalingAALimit); + + // Are we within the scaling window? + if (earnedAA >= aaLimit || earnedAA < aaMinimum) + { + Log(Logs::Detail, Logs::None, "Not within AA scaling window."); + + // At or past the limit. We're done. + return add_aaxp; + } + + // We're not at the limit yet. How close are we? + int remainingAA = aaLimit - earnedAA; + + // We might not always be X - 0 + int scaleRange = aaLimit - aaMinimum; + + // Normalize and get the effectiveness based on the range and the character's + // current spent AA. + float normalizedScale = (float)remainingAA / scaleRange; + + // Scale. + uint32 totalWithExpMod = add_aaxp * (baseModifier / 100) * normalizedScale; + + // Are we so close to the scale limit that we're earning more XP without scaling? This + // will happen when we get very close to the limit. In this case, just grant the unscaled + // amount. + if (totalWithExpMod < add_aaxp) + { + return add_aaxp; + } + + Log(Logs::Detail, + Logs::None, + "Total before the modifier %d :: NewTotal %d :: ScaleRange: %d, SpentAA: %d, RemainingAA: %d, normalizedScale: %0.3f", + add_aaxp, totalWithExpMod, scaleRange, earnedAA, remainingAA, normalizedScale); + + return totalWithExpMod; +} static uint32 MaxBankedGroupLeadershipPoints(int Level) { @@ -174,187 +217,302 @@ uint32 Client::GetExperienceForKill(Mob *against) return 0; } -void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { +float static GetConLevelModifierPercent(uint8 conlevel) +{ + switch (conlevel) + { + case CON_GREEN: + return (float)RuleI(Character, GreenModifier) / 100; + break; + case CON_LIGHTBLUE: + return (float)RuleI(Character, LightBlueModifier) / 100; + break; + case CON_BLUE: + return (float)RuleI(Character, BlueModifier) / 100; + break; + case CON_WHITE: + return (float)RuleI(Character, WhiteModifier) / 100; + break; + case CON_YELLOW: + return (float)RuleI(Character, YellowModifier) / 100; + break; + case CON_RED: + return (float)RuleI(Character, RedModifier) / 100; + break; + default: + return 0; + } +} - this->EVENT_ITEM_ScriptStopReturn(); - - uint32 add_exp = in_add_exp; - - if(!resexp && (XPRate != 0)) - add_exp = static_cast(in_add_exp * (static_cast(XPRate) / 100.0f)); - - if (m_epp.perAA<0 || m_epp.perAA>100) - m_epp.perAA=0; // stop exploit with sanity check - - uint32 add_aaxp; - if(resexp) { +void Client::CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp) +{ + // Functionally this is the same as having the case in the switch, but this is + // cleaner to read. + if (CON_GRAY == conlevel || resexp) + { add_aaxp = 0; - } else { + return; + } + // For this, we ignore the provided value of add_aaxp because it doesn't + // apply. XP per AA is normalized such that there are X white con kills + // per AA. + + uint32 whiteConKillsPerAA = RuleI(AA, NormalizedAANumberOfWhiteConPerAA); + uint32 xpPerAA = RuleI(AA, ExpPerPoint); + + float colorModifier = GetConLevelModifierPercent(conlevel); + float percentToAAXp = (float)m_epp.perAA / 100; + + // Normalize the amount of AA XP we earned for this kill. + add_aaxp = percentToAAXp * (xpPerAA / (whiteConKillsPerAA / colorModifier)); +} + +void Client::CalculateStandardAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp) +{ + if (!resexp) + { + //if XP scaling is based on the con of a monster, do that now. + if (RuleB(Character, UseXPConScaling)) + { + if (conlevel != 0xFF && !resexp) + { + add_aaxp *= GetConLevelModifierPercent(conlevel); + } + } + } //end !resexp + + float aatotalmod = 1.0; + if (zone->newzone_data.zone_exp_multiplier >= 0) { + aatotalmod *= zone->newzone_data.zone_exp_multiplier; + } + + // Shouldn't race not affect AA XP? + if (RuleB(Character, UseRaceClassExpBonuses)) + { + if (GetBaseRace() == HALFLING) { + aatotalmod *= 1.05; + } + + if (GetClass() == ROGUE || GetClass() == WARRIOR) { + aatotalmod *= 1.05; + } + } + + // why wasn't this here? Where should it be? + if (zone->IsHotzone()) + { + aatotalmod += RuleR(Zone, HotZoneBonus); + } + + if (RuleB(Zone, LevelBasedEXPMods)) { + if (zone->level_exp_mod[GetLevel()].ExpMod) { + add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod; + } + } + + add_aaxp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod); +} + +void Client::CalculateLeadershipExp(uint32 &add_exp, uint8 conlevel) +{ + if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED)) + { + add_exp = static_cast(static_cast(add_exp) * 0.8f); + + if (GetGroup()) + { + if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()) + && RuleI(Character, KillsPerGroupLeadershipAA) > 0) + { + uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA); + Client *mentoree = GetGroup()->GetMentoree(); + if (GetGroup()->GetMentorPercent() && mentoree && + mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) + { + uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f); + exp -= mentor_exp; + mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down + mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); + } + if (exp > 0) + { + // possible if you mentor 100% to the other client + AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it + Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); + } + } + else + { + Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS); + } + } + else + { + Raid *raid = GetRaid(); + // Raid leaders CAN NOT gain group AA XP, other group leaders can though! + if (raid->IsLeader(this)) + { + if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel()) + && RuleI(Character, KillsPerRaidLeadershipAA) > 0) + { + AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA)); + Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP); + } + else + { + Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS); + } + } + else + { + if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()) + && RuleI(Character, KillsPerGroupLeadershipAA) > 0) + { + uint32 group_id = raid->GetGroup(this); + uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA); + Client *mentoree = raid->GetMentoree(group_id); + if (raid->GetMentorPercent(group_id) && mentoree && + mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) + { + uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f); + exp -= mentor_exp; + mentoree->AddLeadershipEXP(mentor_exp, 0); + mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); + } + if (exp > 0) + { + AddLeadershipEXP(exp, 0); + Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); + } + } + else + { + Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS); + } + } + } + } +} + +void Client::CalculateExp(uint32 in_add_exp, uint32 &add_exp, uint32 &add_aaxp, uint8 conlevel, bool resexp) +{ + add_exp = in_add_exp; + + if (!resexp && (XPRate != 0)) + { + add_exp = static_cast(in_add_exp * (static_cast(XPRate) / 100.0f)); + } + + // Make sure it was initialized. + add_aaxp = 0; + + if (!resexp) + { //figure out how much of this goes to AAs add_aaxp = add_exp * m_epp.perAA / 100; + //take that amount away from regular exp add_exp -= add_aaxp; float totalmod = 1.0; float zemmod = 1.0; + //get modifiers - if(RuleR(Character, ExpMultiplier) >= 0){ + if (RuleR(Character, ExpMultiplier) >= 0) { totalmod *= RuleR(Character, ExpMultiplier); } - if(zone->newzone_data.zone_exp_multiplier >= 0){ + //add the zone exp modifier. + if (zone->newzone_data.zone_exp_multiplier >= 0) { zemmod *= zone->newzone_data.zone_exp_multiplier; } - if(RuleB(Character,UseRaceClassExpBonuses)) + if (RuleB(Character, UseRaceClassExpBonuses)) { - if(GetBaseRace() == HALFLING){ + if (GetBaseRace() == HALFLING) { totalmod *= 1.05; } - if(GetClass() == ROGUE || GetClass() == WARRIOR){ + if (GetClass() == ROGUE || GetClass() == WARRIOR) { totalmod *= 1.05; } } - if(zone->IsHotzone()) + //add hotzone modifier if one has been set. + if (zone->IsHotzone()) { totalmod += RuleR(Zone, HotZoneBonus); } add_exp = uint32(float(add_exp) * totalmod * zemmod); - if(RuleB(Character,UseXPConScaling)) + //if XP scaling is based on the con of a monster, do that now. + if (RuleB(Character, UseXPConScaling)) { - if (conlevel != 0xFF && !resexp) { - switch (conlevel) - { - case CON_GRAY: - add_exp = 0; - add_aaxp = 0; - return; - case CON_GREEN: - add_exp = add_exp * RuleI(Character, GreenModifier) / 100; - add_aaxp = add_aaxp * RuleI(Character, GreenModifier) / 100; - break; - case CON_LIGHTBLUE: - add_exp = add_exp * RuleI(Character, LightBlueModifier)/100; - add_aaxp = add_aaxp * RuleI(Character, LightBlueModifier)/100; - break; - case CON_BLUE: - add_exp = add_exp * RuleI(Character, BlueModifier)/100; - add_aaxp = add_aaxp * RuleI(Character, BlueModifier)/100; - break; - case CON_WHITE: - add_exp = add_exp * RuleI(Character, WhiteModifier)/100; - add_aaxp = add_aaxp * RuleI(Character, WhiteModifier)/100; - break; - case CON_YELLOW: - add_exp = add_exp * RuleI(Character, YellowModifier)/100; - add_aaxp = add_aaxp * RuleI(Character, YellowModifier)/100; - break; - case CON_RED: - add_exp = add_exp * RuleI(Character, RedModifier)/100; - add_aaxp = add_aaxp * RuleI(Character, RedModifier)/100; - break; - } + if (conlevel != 0xFF && !resexp) + { + add_exp = add_exp * GetConLevelModifierPercent(conlevel); } } - if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED)) { - add_exp = static_cast(static_cast(add_exp) * 0.8f); - - if (GetGroup()) { - if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()) - && RuleI(Character, KillsPerGroupLeadershipAA) > 0) { - uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA); - Client *mentoree = GetGroup()->GetMentoree(); - if (GetGroup()->GetMentorPercent() && mentoree && - mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) { - uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f); - exp -= mentor_exp; - mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down - mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); - } - if (exp > 0) { // possible if you mentor 100% to the other client - AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it - Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); - } - } else { - Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS); - } - } else { - Raid *raid = GetRaid(); - // Raid leaders CAN NOT gain group AA XP, other group leaders can though! - if (raid->IsLeader(this)) { - if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel()) - && RuleI(Character, KillsPerRaidLeadershipAA) > 0) { - AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA)); - Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP); - } else { - Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS); - } - } else { - if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()) - && RuleI(Character, KillsPerGroupLeadershipAA) > 0) { - uint32 group_id = raid->GetGroup(this); - uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA); - Client *mentoree = raid->GetMentoree(group_id); - if (raid->GetMentorPercent(group_id) && mentoree && - mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) { - uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f); - exp -= mentor_exp; - mentoree->AddLeadershipEXP(mentor_exp, 0); - mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); - } - if (exp > 0) { - AddLeadershipEXP(exp, 0); - Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); - } - } else { - Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS); - } - } - } - - } - + // Calculate any changes to leadership experience. + CalculateLeadershipExp(add_exp, conlevel); } //end !resexp - float aatotalmod = 1.0; - if(zone->newzone_data.zone_exp_multiplier >= 0){ - aatotalmod *= zone->newzone_data.zone_exp_multiplier; - } - - - - if(RuleB(Character,UseRaceClassExpBonuses)) - { - if(GetBaseRace() == HALFLING){ - aatotalmod *= 1.05; - } - - if(GetClass() == ROGUE || GetClass() == WARRIOR){ - aatotalmod *= 1.05; - } - } - - if(RuleB(Zone, LevelBasedEXPMods)){ - if(zone->level_exp_mod[GetLevel()].ExpMod){ + if (RuleB(Zone, LevelBasedEXPMods)) { + if (zone->level_exp_mod[GetLevel()].ExpMod) { add_exp *= zone->level_exp_mod[GetLevel()].ExpMod; - add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod; } } - uint32 exp = GetEXP() + add_exp; + add_exp = GetEXP() + add_exp; +} - uint32 aaexp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod); +void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { + + this->EVENT_ITEM_ScriptStopReturn(); + + uint32 exp = 0; + uint32 aaexp = 0; + + if (m_epp.perAA<0 || m_epp.perAA>100) + m_epp.perAA=0; // stop exploit with sanity check + + // Calculate regular XP + CalculateExp(in_add_exp, exp, aaexp, conlevel, resexp); + + // Calculate regular AA XP + if (!RuleB(AA, NormalizedAAEnabled)) + { + CalculateStandardAAExp(aaexp, conlevel, resexp); + } + else + { + CalculateNormalizedAAExp(aaexp, conlevel, resexp); + } + + // Are we also doing linear AA acceleration? + if (RuleB(AA, ModernAAScalingEnabled) && aaexp > 0) + { + aaexp = ScaleAAXPBasedOnCurrentAATotal(GetAAPoints(), aaexp); + } + + // Get current AA XP total uint32 had_aaexp = GetAAXP(); - aaexp += had_aaexp; - if(aaexp < had_aaexp) - aaexp = had_aaexp; //watch for wrap + // Add it to the XP we just earned. + aaexp += had_aaexp; + + // Make sure our new total (existing + just earned) isn't lower than the + // existing total. If it is, we overflowed the bounds of uint32 and wrapped. + // Reset to the existing total. + if (aaexp < had_aaexp) + { + aaexp = had_aaexp; //watch for wrap + } + + // Now update our character's normal and AA xp SetEXP(exp, aaexp, resexp); } @@ -673,6 +831,8 @@ void Client::SetLevel(uint8 set_level, bool command) SetHP(CalcMaxHP()); // Why not, lets give them a free heal } + if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true); + DoTributeUpdate(); SendHPUpdate(); SetMana(CalcMaxMana()); diff --git a/zone/fastmath.cpp b/zone/fastmath.cpp new file mode 100644 index 000000000..0da87dc87 --- /dev/null +++ b/zone/fastmath.cpp @@ -0,0 +1,35 @@ +#if defined(_MSC_VER) +#define _USE_MATH_DEFINES +#endif +#include +#include "fastmath.h" + +FastMath g_Math; + +// This should match EQ's sin/cos LUTs +// Some values didn't match on linux, but they were the "same" float :P +FastMath::FastMath() +{ + int ci = 0; + int si = 128; + float res; + do { + res = std::cos(static_cast(ci) * M_PI * 2 / 512); + lut_cos[ci] = res; + if (si == 512) + si = 0; + lut_sin[si] = res; + ++ci; + ++si; + } while (ci < 512); + + lut_sin[0] = 0.0f; + lut_sin[128] = 1.0f; + lut_sin[256] = 0.0f; + lut_sin[384] = -1.0f; + + lut_cos[0] = 1.0f; + lut_cos[128] = 0.0f; + lut_cos[384] = 0.0f; +} + diff --git a/zone/fastmath.h b/zone/fastmath.h new file mode 100644 index 000000000..083198e48 --- /dev/null +++ b/zone/fastmath.h @@ -0,0 +1,18 @@ +#ifndef FASTMATH_H +#define FASTMATH_H + +class FastMath +{ +private: + float lut_cos[512]; + float lut_sin[512]; + +public: + FastMath(); + + inline float FastSin(float a) { return lut_sin[static_cast(a) & 0x1ff]; } + inline float FastCos(float a) { return lut_cos[static_cast(a) & 0x1ff]; } + +}; + +#endif /* !FASTMATH_H */ diff --git a/zone/forage.cpp b/zone/forage.cpp index be93d39ae..4dc3bc04f 100644 --- a/zone/forage.cpp +++ b/zone/forage.cpp @@ -277,20 +277,23 @@ void Client::GoFish() food_id = database.GetZoneFishing(m_pp.zone_id, fishing_skill, npc_id, npc_chance); //check for add NPC - if(npc_chance > 0 && npc_id) { - if(npc_chance < zone->random.Int(0, 99)) { - const NPCType* tmp = database.LoadNPCTypesData(npc_id); - if(tmp != nullptr) { - auto positionNPC = GetPosition(); - positionNPC.x = positionNPC.x + 3; - auto npc = new NPC(tmp, nullptr, positionNPC, FlyMode3); - npc->AddLootTable(); + if (npc_chance > 0 && npc_id) { + if (npc_chance < zone->random.Int(0, 99)) { + const NPCType *tmp = database.LoadNPCTypesData(npc_id); + if (tmp != nullptr) { + auto positionNPC = GetPosition(); + positionNPC.x = positionNPC.x + 3; + auto npc = new NPC(tmp, nullptr, positionNPC, FlyMode3); + npc->AddLootTable(); + if (npc->DropsGlobalLoot()) + npc->CheckGlobalLootTables(); - npc->AddToHateList(this, 1, 0, false); // no help yelling + npc->AddToHateList(this, 1, 0, false); // no help yelling - entity_list.AddNPC(npc); + entity_list.AddNPC(npc); - Message(MT_Emote, "You fish up a little more than you bargained for..."); + Message(MT_Emote, + "You fish up a little more than you bargained for..."); } } } diff --git a/zone/global_loot_manager.cpp b/zone/global_loot_manager.cpp new file mode 100644 index 000000000..8e990c0ac --- /dev/null +++ b/zone/global_loot_manager.cpp @@ -0,0 +1,98 @@ +#include "global_loot_manager.h" +#include "npc.h" +#include "client.h" + +std::vector GlobalLootManager::GetGlobalLootTables(NPC *mob) const +{ + // we may be able to add a cache here if performance is an issue, but for now + // just return NRVO'd vector + // The cache would have to be keyed by NPCType and level (for NPCs with Max Level set) + std::vector tables; + + for (auto &e : m_entries) { + if (e.PassesRules(mob)) { + tables.push_back(e.GetLootTableID()); + } + } + + return tables; +} + +void GlobalLootManager::ShowZoneGlobalLoot(Client *to) const +{ + for (auto &e : m_entries) + to->Message(0, " %s : %d table %d", e.GetDescription().c_str(), e.GetID(), e.GetLootTableID()); +} + +void GlobalLootManager::ShowNPCGlobalLoot(Client *to, NPC *who) const +{ + for (auto &e : m_entries) { + if (e.PassesRules(who)) + to->Message(0, " %s : %d table %d", e.GetDescription().c_str(), e.GetID(), e.GetLootTableID()); + } +} + +bool GlobalLootEntry::PassesRules(NPC *mob) const +{ + bool bRace = false; + bool bPassesRace = false; + bool bBodyType = false; + bool bPassesBodyType = false; + bool bClass = false; + bool bPassesClass = false; + + for (auto &r : m_rules) { + switch (r.type) { + case GlobalLoot::RuleTypes::LevelMin: + if (mob->GetLevel() < r.value) + return false; + break; + case GlobalLoot::RuleTypes::LevelMax: + if (mob->GetLevel() > r.value) + return false; + break; + case GlobalLoot::RuleTypes::Raid: // value == 0 must not be raid, value != 0 must be raid + if (mob->IsRaidTarget() && !r.value) + return false; + if (!mob->IsRaidTarget() && r.value) + return false; + break; + case GlobalLoot::RuleTypes::Rare: + if (mob->IsRareSpawn() && !r.value) + return false; + if (!mob->IsRareSpawn() && r.value) + return false; + break; + case GlobalLoot::RuleTypes::Race: // can have multiple races per rule set + bRace = true; // we must pass race + if (mob->GetRace() == r.value) + bPassesRace = true; + break; + case GlobalLoot::RuleTypes::Class: // can have multiple classes per rule set + bClass = true; // we must pass class + if (mob->GetClass() == r.value) + bPassesClass = true; + break; + case GlobalLoot::RuleTypes::BodyType: // can have multiple bodytypes per rule set + bBodyType = true; // we must pass BodyType + if (mob->GetBodyType() == r.value) + bPassesBodyType = true; + break; + default: + break; + } + } + + if (bRace && !bPassesRace) + return false; + + if (bClass && !bPassesClass) + return false; + + if (bBodyType && !bPassesBodyType) + return false; + + // we abort as early as possible if we fail a rule, so if we get here, we passed + return true; +} + diff --git a/zone/global_loot_manager.h b/zone/global_loot_manager.h new file mode 100644 index 000000000..fec5a7215 --- /dev/null +++ b/zone/global_loot_manager.h @@ -0,0 +1,61 @@ +#ifndef GLOBAL_LOOT_MANAGER_H +#define GLOBAL_LOOT_MANAGER_H + +#include +#include + +class NPC; +class Client; + +namespace GlobalLoot { + +enum class RuleTypes { + LevelMin = 0, + LevelMax = 1, + Race = 2, + Class = 3, + BodyType = 4, + Rare = 5, + Raid = 6, + Max +}; + +struct Rule { + RuleTypes type; + int value; + Rule(RuleTypes t, int v) : type(t), value(v) { } +}; + +}; + +class GlobalLootEntry { + int m_id; + int m_loottable_id; + std::string m_description; + std::vector m_rules; +public: + GlobalLootEntry(int id, int loottable, std::string des) + : m_id(id), m_loottable_id(loottable), m_description(std::move(des)) + { } + bool PassesRules(NPC *mob) const; + inline int GetLootTableID() const { return m_loottable_id; } + inline int GetID() const { return m_id; } + inline const std::string &GetDescription() const { return m_description; } + inline void SetLootTableID(int in) { m_loottable_id = in; } + inline void SetID(int in) { m_id = in; } + inline void SetDescription(const std::string &in) { m_description = in; } + inline void AddRule(GlobalLoot::RuleTypes rule, int value) { m_rules.emplace_back(rule, value); } +}; + +class GlobalLootManager { + std::vector m_entries; + +public: + std::vector GetGlobalLootTables(NPC *mob) const; + inline void Clear() { m_entries.clear(); } + inline void AddEntry(GlobalLootEntry &in) { m_entries.push_back(in); } + void ShowZoneGlobalLoot(Client *to) const; + void ShowNPCGlobalLoot(Client *to, NPC *who) const; +}; + +#endif /* !GLOBAL_LOOT_MANAGER_H */ diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 10b46a356..5af9da7d9 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -107,6 +107,7 @@ void HateList::SetHateAmountOnEnt(Mob* other, uint32 in_hate, uint32 in_damage) entity->hatelist_damage = in_damage; if (in_hate > 0) entity->stored_hate_amount = in_hate; + entity->last_modified = Timer::GetCurrentTime(); } } @@ -192,6 +193,7 @@ void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, entity->hatelist_damage += (in_damage >= 0) ? in_damage : 0; entity->stored_hate_amount += in_hate; entity->is_entity_frenzy = in_is_entity_frenzied; + entity->last_modified = Timer::GetCurrentTime(); } else if (iAddIfNotExist) { entity = new struct_HateList; @@ -199,6 +201,8 @@ void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, entity->hatelist_damage = (in_damage >= 0) ? in_damage : 0; entity->stored_hate_amount = in_hate; entity->is_entity_frenzy = in_is_entity_frenzied; + entity->oor_count = 0; + entity->last_modified = Timer::GetCurrentTime(); list.push_back(entity); parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "1", 0); @@ -646,3 +650,45 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent iter++; } } + +void HateList::RemoveStaleEntries(int time_ms, float dist) +{ + auto it = list.begin(); + + auto cur_time = Timer::GetCurrentTime(); + + auto dist2 = dist * dist; + + while (it != list.end()) { + auto m = (*it)->entity_on_hatelist; + if (m) { + bool remove = false; + + if (cur_time - (*it)->last_modified > time_ms) + remove = true; + + if (!remove && DistanceSquaredNoZ(hate_owner->GetPosition(), m->GetPosition()) > dist2) { + (*it)->oor_count++; + if ((*it)->oor_count == 2) + remove = true; + } else if ((*it)->oor_count != 0) { + (*it)->oor_count = 0; + } + + if (remove) { + parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0); + + if (m->IsClient()) { + m->CastToClient()->DecrementAggroCount(); + m->CastToClient()->RemoveXTarget(hate_owner, true); + } + + delete (*it); + it = list.erase(it); + continue; + } + } + ++it; + } +} + diff --git a/zone/hate_list.h b/zone/hate_list.h index f0e2b7618..0ac1840ac 100644 --- a/zone/hate_list.h +++ b/zone/hate_list.h @@ -31,6 +31,8 @@ struct struct_HateList int32 hatelist_damage; uint32 stored_hate_amount; bool is_entity_frenzy; + int8 oor_count; // count on how long we've been out of range + uint32 last_modified; // we need to remove this if it gets higher than 10 mins }; class HateList @@ -65,6 +67,7 @@ public: 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(); + void RemoveStaleEntries(int time_ms, float dist); protected: diff --git a/zone/heal_rotation.cpp b/zone/heal_rotation.cpp index c9bf54189..489d1ab45 100644 --- a/zone/heal_rotation.cpp +++ b/zone/heal_rotation.cpp @@ -169,9 +169,10 @@ bool HealRotation::ClearMemberPool() m_casting_target_poke = false; m_active_heal_target = false; - ClearTargetPool(); + if (!ClearTargetPool()) + Log(Logs::General, Logs::Error, "HealRotation::ClearTargetPool() failed to clear m_target_pool (size: %u)", m_target_pool.size()); - auto clear_list = m_member_pool; + auto clear_list = const_cast&>(m_member_pool); for (auto member_iter : clear_list) member_iter->LeaveHealRotationMemberPool(); @@ -183,13 +184,23 @@ bool HealRotation::ClearTargetPool() m_hot_target = nullptr; m_hot_active = false; m_is_active = false; - - auto clear_list = m_target_pool; + + auto clear_list = const_cast&>(m_target_pool); for (auto target_iter : clear_list) target_iter->LeaveHealRotationTargetPool(); - m_casting_target_poke = false; - bias_targets(); + //m_casting_target_poke = false; + //bias_targets(); + + // strange crash point... + // bias_targets() should be returning on m_target_pool.empty() + // and setting this two properties as below + m_casting_target_poke = true; + m_active_heal_target = false; + // instead, the list retains mob shared_ptrs and + // attempts to process them - and crashes program + // predominate when adaptive_healing = true + // (shared_ptr now has a delayed gc action? this did work before...) return m_target_pool.empty(); } diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 49e8e83b5..17cfc1aa1 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1326,7 +1326,7 @@ int Client::GetItemLinkHash(const EQEmu::ItemInstance* inst) { return hash; } -// This appears to still be in use... The core of this should be incorporated into class Client::TextLink +// This appears to still be in use... The core of this should be incorporated into class EQEmu::SayLinkEngine void Client::SendItemLink(const EQEmu::ItemInstance* inst, bool send_to_all) { /* diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 08d16e412..961d66781 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -26,6 +26,7 @@ #include "mob.h" #include "npc.h" #include "zonedb.h" +#include "global_loot_manager.h" #include #include @@ -37,10 +38,14 @@ // Queries the loottable: adds item & coin to the npc void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) { const LootTable_Struct* lts = nullptr; - *copper = 0; - *silver = 0; - *gold = 0; - *plat = 0; + // global loot passes nullptr for these + bool bGlobal = copper == nullptr && silver == nullptr && gold == nullptr && plat == nullptr; + if (!bGlobal) { + *copper = 0; + *silver = 0; + *gold = 0; + *plat = 0; + } lts = database.GetLootTable(loottable_id); if (!lts) @@ -55,17 +60,19 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite } uint32 cash = 0; - if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) { - float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash); - float avg_cash_roll = (float)zone->random.Real(0.0, 1.0); + if (!bGlobal) { + if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) { + float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash); + float avg_cash_roll = (float)zone->random.Real(0.0, 1.0); - if(avg_cash_roll < upper_chance) { - cash = zone->random.Int(lts->avgcoin, max_cash); + if(avg_cash_roll < upper_chance) { + cash = zone->random.Int(lts->avgcoin, max_cash); + } else { + cash = zone->random.Int(min_cash, lts->avgcoin); + } } else { - cash = zone->random.Int(min_cash, lts->avgcoin); + cash = zone->random.Int(min_cash, max_cash); } - } else { - cash = zone->random.Int(min_cash, max_cash); } if(cash != 0) { @@ -80,6 +87,7 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite *copper = cash; } + uint32 global_loot_multiplier = RuleI(Zone, GlobalLootMultiplier); // Do items @@ -336,7 +344,8 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch eslot = EQEmu::textures::weaponPrimary; if (item2->Damage > 0) { SendAddPlayerState(PlayerState::PrimaryWeaponEquipped); - SetFacestab(true); + if (!RuleB(Combat, ClassicNPCBackstab)) + SetFacestab(true); } if (item2->IsType2HWeapon()) SetTwoHanderEquipped(true); @@ -443,3 +452,76 @@ void NPC::AddLootTable(uint32 ldid) { database.AddLootTableToNPC(this,ldid, &itemlist, &copper, &silver, &gold, &platinum); } } + +void NPC::CheckGlobalLootTables() +{ + auto tables = zone->GetGlobalLootTables(this); + + for (auto &id : tables) + database.AddLootTableToNPC(this, id, &itemlist, nullptr, nullptr, nullptr, nullptr); +} + +void ZoneDatabase::LoadGlobalLoot() +{ + auto query = StringFormat("SELECT id, loottable_id, description, min_level, max_level, rare, raid, race, " + "class, bodytype, zone FROM global_loot WHERE enabled = 1"); + + auto results = QueryDatabase(query); + if (!results.Success() || results.RowCount() == 0) + return; + + // we might need this, lets not keep doing it in a loop + auto zoneid = std::to_string(zone->GetZoneID()); + for (auto row = results.begin(); row != results.end(); ++row) { + // checking zone limits + if (row[10]) { + auto zones = SplitString(row[10], '|'); + + auto it = std::find(zones.begin(), zones.end(), zoneid); + if (it == zones.end()) // not in here, skip + continue; + } + + GlobalLootEntry e(atoi(row[0]), atoi(row[1]), row[2] ? row[2] : ""); + + auto min_level = atoi(row[3]); + if (min_level) + e.AddRule(GlobalLoot::RuleTypes::LevelMin, min_level); + + auto max_level = atoi(row[4]); + if (max_level) + e.AddRule(GlobalLoot::RuleTypes::LevelMax, max_level); + + // null is not used + if (row[5]) + e.AddRule(GlobalLoot::RuleTypes::Rare, atoi(row[5])); + + // null is not used + if (row[6]) + e.AddRule(GlobalLoot::RuleTypes::Raid, atoi(row[6])); + + if (row[7]) { + auto races = SplitString(row[7], '|'); + + for (auto &r : races) + e.AddRule(GlobalLoot::RuleTypes::Race, std::stoi(r)); + } + + if (row[8]) { + auto classes = SplitString(row[8], '|'); + + for (auto &c : classes) + e.AddRule(GlobalLoot::RuleTypes::Class, std::stoi(c)); + } + + if (row[9]) { + auto bodytypes = SplitString(row[9], '|'); + + for (auto &b : bodytypes) + e.AddRule(GlobalLoot::RuleTypes::Class, std::stoi(b)); + } + + zone->AddGlobalLootEntry(e); + } +} + diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index aad0be464..ec22fec1b 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1464,7 +1464,6 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float LuaCreateNPCParse(healscale, float, 0); LuaCreateNPCParse(no_target_hotkey, bool, false); LuaCreateNPCParse(raid_target, bool, false); - LuaCreateNPCParse(probability, uint8, 0); NPC* npc = new NPC(npc_type, nullptr, glm::vec4(x, y, z, heading), FlyMode3); npc->GiveNPCTypeData(npc_type); diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 8b88ba12f..3793e6b9d 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -282,6 +282,16 @@ void Lua_Mob::GMMove(double x, double y, double z, double heading, bool send_upd self->GMMove(static_cast(x), static_cast(y), static_cast(z), static_cast(heading), send_update); } +void Lua_Mob::TryMoveAlong(float distance, float angle) { + Lua_Safe_Call_Void(); + self->TryMoveAlong(distance, angle); +} + +void Lua_Mob::TryMoveAlong(float distance, float angle, bool send) { + Lua_Safe_Call_Void(); + self->TryMoveAlong(distance, angle, send); +} + bool Lua_Mob::HasProcs() { Lua_Safe_Call_Bool(); return self->HasProcs(); @@ -1605,6 +1615,76 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { beard, aa_title, drakkin_heritage, drakkin_tattoo, drakkin_details, size); } +void Lua_Mob::ChangeRace(int in) { + Lua_Safe_Call_Void(); + self->ChangeRace(in); +} + +void Lua_Mob::ChangeGender(int in) { + Lua_Safe_Call_Void(); + self->ChangeGender(in); +} + +void Lua_Mob::ChangeTexture(int in) { + Lua_Safe_Call_Void(); + self->ChangeTexture(in); +} + +void Lua_Mob::ChangeHelmTexture(int in) { + Lua_Safe_Call_Void(); + self->ChangeHelmTexture(in); +} + +void Lua_Mob::ChangeHairColor(int in) { + Lua_Safe_Call_Void(); + self->ChangeHairColor(in); +} + +void Lua_Mob::ChangeBeardColor(int in) { + Lua_Safe_Call_Void(); + self->ChangeBeardColor(in); +} + +void Lua_Mob::ChangeEyeColor1(int in) { + Lua_Safe_Call_Void(); + self->ChangeEyeColor1(in); +} + +void Lua_Mob::ChangeEyeColor2(int in) { + Lua_Safe_Call_Void(); + self->ChangeEyeColor2(in); +} + +void Lua_Mob::ChangeHairStyle(int in) { + Lua_Safe_Call_Void(); + self->ChangeHairStyle(in); +} + +void Lua_Mob::ChangeLuclinFace(int in) { + Lua_Safe_Call_Void(); + self->ChangeLuclinFace(in); +} + +void Lua_Mob::ChangeBeard(int in) { + Lua_Safe_Call_Void(); + self->ChangeBeard(in); +} + +void Lua_Mob::ChangeDrakkinHeritage(int in) { + Lua_Safe_Call_Void(); + self->ChangeDrakkinHeritage(in); +} + +void Lua_Mob::ChangeDrakkinTattoo(int in) { + Lua_Safe_Call_Void(); + self->ChangeDrakkinTattoo(in); +} + +void Lua_Mob::ChangeDrakkinDetails(int in) { + Lua_Safe_Call_Void(); + self->ChangeDrakkinDetails(in); +} + void Lua_Mob::CameraEffect(uint32 duration, uint32 intensity) { Lua_Safe_Call_Void(); self->CameraEffect(duration, intensity); @@ -2127,6 +2207,8 @@ luabind::scope lua_register_mob() { .def("GMMove", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::GMMove) .def("GMMove", (void(Lua_Mob::*)(double,double,double,double))&Lua_Mob::GMMove) .def("GMMove", (void(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::GMMove) + .def("TryMoveAlong", (void(Lua_Mob::*)(float,float))&Lua_Mob::TryMoveAlong) + .def("TryMoveAlong", (void(Lua_Mob::*)(float,float,bool))&Lua_Mob::TryMoveAlong) .def("HasProcs", &Lua_Mob::HasProcs) .def("IsInvisible", (bool(Lua_Mob::*)(void))&Lua_Mob::IsInvisible) .def("IsInvisible", (bool(Lua_Mob::*)(Lua_Mob))&Lua_Mob::IsInvisible) @@ -2356,6 +2438,20 @@ luabind::scope lua_register_mob() { .def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace) .def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender) .def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::adl::object))&Lua_Mob::SendIllusionPacket) + .def("ChangeRace", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeRace) + .def("ChangeGender", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeGender) + .def("ChangeTexture", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeTexture) + .def("ChangeHelmTexture", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeHelmTexture) + .def("ChangeHairColor", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeHairColor) + .def("ChangeBeardColor", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeBeardColor) + .def("ChangeEyeColor1", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeEyeColor1) + .def("ChangeEyeColor2", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeEyeColor2) + .def("ChangeHairStyle", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeHairStyle) + .def("ChangeLuclinFace", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeLuclinFace) + .def("ChangeBeard", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeBeard) + .def("ChangeDrakkinHeritage", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeDrakkinHeritage) + .def("ChangeDrakkinTattoo", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeDrakkinTattoo) + .def("ChangeDrakkinDetails", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeDrakkinDetails) .def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32))&Lua_Mob::CameraEffect) .def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client))&Lua_Mob::CameraEffect) .def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client,bool))&Lua_Mob::CameraEffect) @@ -2499,7 +2595,8 @@ luabind::scope lua_register_special_abilities() { luabind::value("allow_to_tank", static_cast(ALLOW_TO_TANK)), luabind::value("ignore_root_aggro_rules", static_cast(IGNORE_ROOT_AGGRO_RULES)), luabind::value("casting_resist_diff", static_cast(CASTING_RESIST_DIFF)), - luabind::value("counter_avoid_damage", static_cast(COUNTER_AVOID_DAMAGE)) + luabind::value("counter_avoid_damage", static_cast(COUNTER_AVOID_DAMAGE)), + luabind::value("immune_ranged_attacks", static_cast(IMMUNE_RANGED_ATTACKS)) ]; } diff --git a/zone/lua_mob.h b/zone/lua_mob.h index 493f5e1e8..17dbc5c43 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -74,6 +74,8 @@ public: void GMMove(double x, double y, double z); void GMMove(double x, double y, double z, double heading); void GMMove(double x, double y, double z, double heading, bool send_update); + void TryMoveAlong(float distance, float heading); + void TryMoveAlong(float distance, float heading, bool send); bool HasProcs(); bool IsInvisible(); bool IsInvisible(Lua_Mob other); @@ -304,6 +306,20 @@ public: void SetRace(int in); void SetGender(int in); void SendIllusionPacket(luabind::adl::object illusion); + void ChangeRace(int in); + void ChangeGender(int in); + void ChangeTexture(int in); + void ChangeHelmTexture(int in); + void ChangeHairColor(int in); + void ChangeBeardColor(int in); + void ChangeEyeColor1(int in); + void ChangeEyeColor2(int in); + void ChangeHairStyle(int in); + void ChangeLuclinFace(int in); + void ChangeBeard(int in); + void ChangeDrakkinHeritage(int in); + void ChangeDrakkinTattoo(int in); + void ChangeDrakkinDetails(int in); void CameraEffect(uint32 duration, uint32 intensity); void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c); void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c, bool global); diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 50ff597f6..a16d78361 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -420,7 +420,12 @@ void Lua_NPC::ModifyNPCStat(const char *stat, const char *value) { void Lua_NPC::AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust) { Lua_Safe_Call_Void(); - self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust); + self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, 0, 0); +} + +void Lua_NPC::AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust, int min_hp, int max_hp) { + Lua_Safe_Call_Void(); + self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, min_hp, max_hp); } void Lua_NPC::RemoveAISpell(int spell_id) { @@ -488,16 +493,6 @@ void Lua_NPC::MerchantCloseShop() { self->MerchantCloseShop(); } -void Lua_NPC::SetMerchantProbability(uint8 amt) { - Lua_Safe_Call_Void(); - self->SetMerchantProbability(amt); -} - -uint8 Lua_NPC::GetMerchantProbability() { - Lua_Safe_Call_Int(); - return self->GetMerchantProbability(); -} - int Lua_NPC::GetRawAC() { Lua_Safe_Call_Int(); return self->GetRawAC(); @@ -595,6 +590,7 @@ luabind::scope lua_register_npc() { .def("SetSwarmTarget", (void(Lua_NPC::*)(int))&Lua_NPC::SetSwarmTarget) .def("ModifyNPCStat", (void(Lua_NPC::*)(const char*,const char*))&Lua_NPC::ModifyNPCStat) .def("AddAISpell", (void(Lua_NPC::*)(int,int,int,int,int,int))&Lua_NPC::AddAISpell) + .def("AddAISpell", (void(Lua_NPC::*)(int,int,int,int,int,int,int,int))&Lua_NPC::AddAISpell) .def("RemoveAISpell", (void(Lua_NPC::*)(int))&Lua_NPC::RemoveAISpell) .def("SetSpellFocusDMG", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusDMG) .def("SetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusHeal) @@ -608,8 +604,6 @@ luabind::scope lua_register_npc() { .def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore) .def("MerchantOpenShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantOpenShop) .def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop) - .def("SetMerchantProbability", (void(Lua_NPC::*)(void))&Lua_NPC::SetMerchantProbability) - .def("GetMerchantProbability", (uint8(Lua_NPC::*)(void))&Lua_NPC::GetMerchantProbability) .def("GetRawAC", (int(Lua_NPC::*)(void))&Lua_NPC::GetRawAC) .def("GetAvoidanceRating", &Lua_NPC::GetAvoidanceRating); } diff --git a/zone/lua_npc.h b/zone/lua_npc.h index d3d673641..972adee90 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -110,6 +110,7 @@ public: void SetSwarmTarget(int target); void ModifyNPCStat(const char *stat, const char *value); void AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust); + void AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust, int min_hp, int max_hp); void RemoveAISpell(int spell_id); void SetSpellFocusDMG(int focus); void SetSpellFocusHeal(int focus); @@ -123,8 +124,6 @@ public: int GetScore(); void MerchantOpenShop(); void MerchantCloseShop(); - void SetMerchantProbability(uint8 amt); - uint8 GetMerchantProbability(); int GetRawAC(); int GetAvoidanceRating(); }; diff --git a/zone/map.cpp b/zone/map.cpp index 32c6564b4..0627c2dc2 100644 --- a/zone/map.cpp +++ b/zone/map.cpp @@ -268,6 +268,14 @@ bool Map::CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const { return !imp->rm->raycast((const RmReal*)&myloc, (const RmReal*)&oloc, nullptr, nullptr, nullptr); } +// returns true if a collision happens +bool Map::DoCollisionCheck(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outnorm, float &distance) const { + if(!imp) + return false; + + return imp->rm->raycast((const RmReal*)&myloc, (const RmReal*)&oloc, nullptr, (RmReal *)&outnorm, (RmReal *)&distance); +} + inline bool file_exists(const std::string& name) { std::ifstream f(name.c_str()); return f.good(); diff --git a/zone/map.h b/zone/map.h index 35b5baeda..8a2ec7f68 100644 --- a/zone/map.h +++ b/zone/map.h @@ -42,6 +42,7 @@ public: bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const; bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const; bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const; + bool DoCollisionCheck(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outnorm, float &distance) const; #ifdef USE_MAP_MMFS bool Load(std::string filename, bool force_mmf_overwrite = false); diff --git a/zone/mob.cpp b/zone/mob.cpp index d08804410..d23aaf0b4 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -75,7 +75,6 @@ Mob::Mob(const char* in_name, uint32 in_drakkin_tattoo, uint32 in_drakkin_details, EQEmu::TintProfile in_armor_tint, - uint8 in_aa_title, uint8 in_see_invis, // see through invis/ivu uint8 in_see_invis_undead, @@ -91,24 +90,24 @@ Mob::Mob(const char* in_name, uint8 in_handtexture, uint8 in_legtexture, uint8 in_feettexture - ) : + ) : attack_timer(2000), attack_dw_timer(2000), ranged_timer(2000), tic_timer(6000), mana_timer(2000), spellend_timer(0), - rewind_timer(30000), //Timer used for determining amount of time between actual player position updates for /rewind. + rewind_timer(30000), bindwound_timer(10000), stunned_timer(0), spun_timer(0), bardsong_timer(6000), gravity_timer(1000), viral_timer(0), - m_FearWalkTarget(-999999.0f,-999999.0f,-999999.0f), + m_FearWalkTarget(-999999.0f, -999999.0f, -999999.0f), m_TargetLocation(glm::vec3()), m_TargetV(glm::vec3()), - flee_timer(FLEE_CHECK_TIMER), + flee_timer(FLEE_CHECK_TIMER), m_Position(position), tmHidden(-1), mitigation_ac(0), @@ -116,50 +115,50 @@ Mob::Mob(const char* in_name, fix_z_timer(300), fix_z_timer_engaged(100), attack_anim_timer(1000), - position_update_melee_push_timer(1000) + position_update_melee_push_timer(500), + mHateListCleanup(6000) { targeted = 0; - tar_ndx=0; - tar_vector=0; + tar_ndx = 0; + tar_vector = 0; currently_fleeing = false; - last_z = 0; - last_major_update_position = m_Position; + is_distance_roamer = false; AI_Init(); SetMoving(false); - moved=false; + moved = false; m_RewindLocation = glm::vec3(); _egnode = nullptr; - name[0]=0; - orig_name[0]=0; - clean_name[0]=0; - lastname[0]=0; - if(in_name) { - strn0cpy(name,in_name,64); - strn0cpy(orig_name,in_name,64); + name[0] = 0; + orig_name[0] = 0; + clean_name[0] = 0; + lastname[0] = 0; + if (in_name) { + strn0cpy(name, in_name, 64); + strn0cpy(orig_name, in_name, 64); } - if(in_lastname) - strn0cpy(lastname,in_lastname,64); - cur_hp = in_cur_hp; - max_hp = in_max_hp; - base_hp = in_max_hp; - gender = in_gender; - race = in_race; - base_gender = in_gender; - base_race = in_race; - class_ = in_class; - bodytype = in_bodytype; + if (in_lastname) + strn0cpy(lastname, in_lastname, 64); + cur_hp = in_cur_hp; + max_hp = in_max_hp; + base_hp = in_max_hp; + gender = in_gender; + race = in_race; + base_gender = in_gender; + base_race = in_race; + class_ = in_class; + bodytype = in_bodytype; orig_bodytype = in_bodytype; - deity = in_deity; - level = in_level; + deity = in_deity; + level = in_level; orig_level = in_level; - npctype_id = in_npctype_id; - size = in_size; - base_size = size; - runspeed = in_runspeed; + npctype_id = in_npctype_id; + size = in_size; + base_size = size; + runspeed = in_runspeed; // neotokyo: sanity check if (runspeed < 0 || runspeed > 20) runspeed = 1.25f; @@ -172,7 +171,8 @@ Mob::Mob(const char* in_name, fearspeed = 0.625f; base_fearspeed = 25; // npcs - } else { + } + else { base_walkspeed = base_runspeed * 100 / 265; walkspeed = ((float)base_walkspeed) * 0.025f; base_fearspeed = base_runspeed * 100 / 127; @@ -184,7 +184,7 @@ Mob::Mob(const char* in_name, current_speed = base_runspeed; - m_PlayerState = 0; + m_PlayerState = 0; // sanity check @@ -196,8 +196,8 @@ Mob::Mob(const char* in_name, m_Light.Type[EQEmu::lightsource::LightActive] = m_Light.Type[EQEmu::lightsource::LightInnate]; m_Light.Level[EQEmu::lightsource::LightActive] = m_Light.Level[EQEmu::lightsource::LightInnate]; - texture = in_texture; - helmtexture = in_helmtexture; + texture = in_texture; + helmtexture = in_helmtexture; armtexture = in_armtexture; bracertexture = in_bracertexture; handtexture = in_handtexture; @@ -205,21 +205,21 @@ Mob::Mob(const char* in_name, feettexture = in_feettexture; multitexture = (armtexture || bracertexture || handtexture || legtexture || feettexture); - haircolor = in_haircolor; - beardcolor = in_beardcolor; - eyecolor1 = in_eyecolor1; - eyecolor2 = in_eyecolor2; - hairstyle = in_hairstyle; - luclinface = in_luclinface; - beard = in_beard; - drakkin_heritage = in_drakkin_heritage; - drakkin_tattoo = in_drakkin_tattoo; - drakkin_details = in_drakkin_details; + haircolor = in_haircolor; + beardcolor = in_beardcolor; + eyecolor1 = in_eyecolor1; + eyecolor2 = in_eyecolor2; + hairstyle = in_hairstyle; + luclinface = in_luclinface; + beard = in_beard; + drakkin_heritage = in_drakkin_heritage; + drakkin_tattoo = in_drakkin_tattoo; + drakkin_details = in_drakkin_details; attack_speed = 0; attack_delay = 0; slow_mitigation = 0; - findable = false; - trackable = true; + findable = false; + trackable = true; has_shieldequiped = false; has_twohandbluntequiped = false; has_twohanderequipped = false; @@ -230,19 +230,19 @@ Mob::Mob(const char* in_name, SpellPowerDistanceMod = 0; last_los_check = false; - if(in_aa_title>0) - aa_title = in_aa_title; + if (in_aa_title > 0) + aa_title = in_aa_title; else - aa_title =0xFF; - AC = in_ac; - ATK = in_atk; - STR = in_str; - STA = in_sta; - DEX = in_dex; - AGI = in_agi; - INT = in_int; - WIS = in_wis; - CHA = in_cha; + aa_title = 0xFF; + AC = in_ac; + ATK = in_atk; + STR = in_str; + STA = in_sta; + DEX = in_dex; + AGI = in_agi; + INT = in_int; + WIS = in_wis; + CHA = in_cha; MR = CR = FR = DR = PR = Corrup = 0; ExtraHaste = 0; @@ -263,9 +263,10 @@ Mob::Mob(const char* in_name, hidden = false; improved_hidden = false; invulnerable = false; - IsFullHP = (cur_hp == max_hp); - qglobal=0; + IsFullHP = (cur_hp == max_hp); + qglobal = 0; spawned = false; + rare_spawn = false; InitializeBuffSlots(); @@ -305,7 +306,7 @@ Mob::Mob(const char* in_name, logging_enabled = false; isgrouped = false; israidgrouped = false; - + IsHorse = false; entity_id_being_looted = 0; @@ -376,13 +377,13 @@ Mob::Mob(const char* in_name, } destructibleobject = false; - wandertype=0; - pausetype=0; + wandertype = 0; + pausetype = 0; cur_wp = 0; m_CurrentWayPoint = glm::vec4(); cur_wp_pause = 0; - patrol=0; - follow=0; + patrol = 0; + follow = 0; follow_dist = 100; // Default Distance for Follow no_target_hotkey = false; flee_mode = false; @@ -392,11 +393,12 @@ Mob::Mob(const char* in_name, permarooted = (runspeed > 0) ? false : true; movetimercompleted = false; + ForcedMovement = 0; roamer = false; rooted = false; charmed = false; has_virus = false; - for (i=0; ispawn.lastName, lastname, sizeof(ns->spawn.lastName)); } - ns->spawn.heading = FloatToEQ19(m_Position.w); + ns->spawn.heading = FloatToEQ12(m_Position.w); ns->spawn.x = FloatToEQ19(m_Position.x);//((int32)x_pos)<<3; ns->spawn.y = FloatToEQ19(m_Position.y);//((int32)y_pos)<<3; ns->spawn.z = FloatToEQ19(m_Position.z);//((int32)z_pos)<<3; @@ -1437,6 +1439,21 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal } } +void Mob::StopMoving() { + FixZ(); + SetCurrentSpeed(0); + if (moved) + moved = false; +} + +void Mob::StopMoving(float new_heading) { + SetHeading(new_heading); + FixZ(); + SetCurrentSpeed(0); + if (moved) + moved = false; +} + /* Used for mobs standing still - this does not send a delta */ void Mob::SendPosition() { auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); @@ -1447,6 +1464,7 @@ void Mob::SendPosition() { if (DistanceSquared(last_major_update_position, m_Position) >= (100 * 100)) { entity_list.QueueClients(this, app, true, true); last_major_update_position = m_Position; + is_distance_roamer = true; } else { entity_list.QueueCloseClients(this, app, true, RuleI(Range, MobPositionUpdates), nullptr, false); @@ -1480,6 +1498,11 @@ void Mob::SendPositionUpdate(uint8 iSendToSelf) { CastToClient()->FastQueuePacket(&app, false); } } + else if (DistanceSquared(last_major_update_position, m_Position) >= (100 * 100)) { + entity_list.QueueClients(this, app, true, true); + last_major_update_position = m_Position; + is_distance_roamer = true; + } else { entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), RuleI(Range, MobPositionUpdates), nullptr, false); } @@ -1493,12 +1516,12 @@ void Mob::MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct *spu) { spu->x_pos = FloatToEQ19(m_Position.x); spu->y_pos = FloatToEQ19(m_Position.y); spu->z_pos = FloatToEQ19(m_Position.z); - spu->delta_x = NewFloatToEQ13(0); - spu->delta_y = NewFloatToEQ13(0); - spu->delta_z = NewFloatToEQ13(0); - spu->heading = FloatToEQ19(m_Position.w); + spu->delta_x = FloatToEQ13(0); + spu->delta_y = FloatToEQ13(0); + spu->delta_z = FloatToEQ13(0); + spu->heading = FloatToEQ12(m_Position.w); spu->animation = 0; - spu->delta_heading = NewFloatToEQ13(0); + spu->delta_heading = FloatToEQ10(0); spu->padding0002 = 0; spu->padding0006 = 7; spu->padding0014 = 0x7f; @@ -1512,10 +1535,10 @@ void Mob::MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu) { spu->x_pos = FloatToEQ19(m_Position.x); spu->y_pos = FloatToEQ19(m_Position.y); spu->z_pos = FloatToEQ19(m_Position.z); - spu->delta_x = NewFloatToEQ13(m_Delta.x); - spu->delta_y = NewFloatToEQ13(m_Delta.y); - spu->delta_z = NewFloatToEQ13(m_Delta.z); - spu->heading = FloatToEQ19(m_Position.w); + spu->delta_x = FloatToEQ13(m_Delta.x); + spu->delta_y = FloatToEQ13(m_Delta.y); + spu->delta_z = FloatToEQ13(m_Delta.z); + spu->heading = FloatToEQ12(m_Position.w); spu->padding0002 = 0; spu->padding0006 = 7; spu->padding0014 = 0x7f; @@ -1529,7 +1552,7 @@ void Mob::MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu) { else spu->animation = pRunAnimSpeed;//animation; - spu->delta_heading = NewFloatToEQ13(m_Delta.w); + spu->delta_heading = FloatToEQ10(m_Delta.w); } void Mob::ShowStats(Client* client) @@ -2416,18 +2439,18 @@ float Mob::MobAngle(Mob *other, float ourx, float oury) const { float mobx = -(other->GetX()); // mob xloc (inverse because eq) float moby = other->GetY(); // mob yloc float heading = other->GetHeading(); // mob heading - heading = (heading * 360.0f) / 256.0f; // convert to degrees + heading = (heading * 360.0f) / 512.0f; // convert to degrees if (heading < 270) heading += 90; else heading -= 270; heading = heading * 3.1415f / 180.0f; // convert to radians - vectorx = mobx + (10.0f * cosf(heading)); // create a vector based on heading - vectory = moby + (10.0f * sinf(heading)); // of mob length 10 + vectorx = mobx + (10.0f * std::cos(heading)); // create a vector based on heading + vectory = moby + (10.0f * std::sin(heading)); // of mob length 10 // length of mob to player vector - lengthb = (float) sqrtf(((-ourx - mobx) * (-ourx - mobx)) + ((oury - moby) * (oury - moby))); + lengthb = (float) std::sqrt(((-ourx - mobx) * (-ourx - mobx)) + ((oury - moby) * (oury - moby))); // calculate dot product to get angle // Handle acos domain errors due to floating point rounding errors @@ -2440,7 +2463,7 @@ float Mob::MobAngle(Mob *other, float ourx, float oury) const { else if (dotp < -1) return 180.0f; - angle = acosf(dotp); + angle = std::acos(dotp); angle = angle * 180.0f / 3.1415f; return angle; @@ -2609,7 +2632,7 @@ bool Mob::PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, fl look_heading = target->GetHeading(); // Convert to sony heading to radians - look_heading = (look_heading / 256.0f) * 6.283184f; + look_heading = (look_heading / 512.0f) * 6.283184f; float tempX = 0; float tempY = 0; @@ -2717,20 +2740,10 @@ bool Mob::HateSummon() { if(summon_level == 1) { entity_list.MessageClose(this, true, 500, MT_Say, "%s says,'You will not evade me, %s!' ", GetCleanName(), target->GetCleanName() ); - if (target->IsClient()) { + if (target->IsClient()) target->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), m_Position.x, m_Position.y, m_Position.z, target->GetHeading(), 0, SummonPC); - } - else { -#ifdef BOTS - if(target && target->IsBot()) { - // set pre summoning info to return to (to get out of melee range for caster) - target->CastToBot()->SetHasBeenSummoned(true); - target->CastToBot()->SetPreSummonLocation(glm::vec3(target->GetPosition())); - - } -#endif //BOTS + else target->GMMove(m_Position.x, m_Position.y, m_Position.z, target->GetHeading()); - } return true; } else if(summon_level == 2) { @@ -3397,13 +3410,18 @@ int Mob::GetHaste() else // 1-25 h += itembonuses.haste > 10 ? 10 : itembonuses.haste; - // 60+ 100, 51-59 85, 1-50 level+25 - if (level > 59) // 60+ - cap = RuleI(Character, HasteCap); - else if (level > 50) // 51-59 - cap = 85; - else // 1-50 - cap = level + 25; + // mobs are different! + Mob *owner = nullptr; + if (IsPet()) + owner = GetOwner(); + else if (IsNPC() && CastToNPC()->GetSwarmOwner()) + owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner()); + if (owner) { + cap = 10 + level; + cap += std::max(0, owner->GetLevel() - 39) + std::max(0, owner->GetLevel() - 60); + } else { + cap = 150; + } if(h > cap) h = cap; @@ -3439,6 +3457,19 @@ void Mob::SetTarget(Mob* mob) { this->GetTarget()->SendHPUpdate(false, true); } +// For when we want a Ground Z at a location we are not at yet +// Like MoveTo. +float Mob::FindDestGroundZ(glm::vec3 dest, float z_offset) +{ + float best_z = BEST_Z_INVALID; + if (zone->zonemap != nullptr) + { + dest.z += z_offset; + best_z = zone->zonemap->FindBestZ(dest, nullptr); + } + return best_z; +} + float Mob::FindGroundZ(float new_x, float new_y, float z_offset) { float ret = BEST_Z_INVALID; @@ -4646,16 +4677,16 @@ void Mob::DoKnockback(Mob *caster, uint32 pushback, uint32 pushup) spu->x_pos = FloatToEQ19(GetX()); spu->y_pos = FloatToEQ19(GetY()); spu->z_pos = FloatToEQ19(GetZ()); - spu->delta_x = NewFloatToEQ13(static_cast(new_x)); - spu->delta_y = NewFloatToEQ13(static_cast(new_y)); - spu->delta_z = NewFloatToEQ13(static_cast(pushup)); - spu->heading = FloatToEQ19(GetHeading()); + spu->delta_x = FloatToEQ13(static_cast(new_x)); + spu->delta_y = FloatToEQ13(static_cast(new_y)); + spu->delta_z = FloatToEQ13(static_cast(pushup)); + spu->heading = FloatToEQ12(GetHeading()); spu->padding0002 =0; spu->padding0006 =7; spu->padding0014 =0x7f; spu->padding0018 =0x5df27; spu->animation = 0; - spu->delta_heading = NewFloatToEQ13(0); + spu->delta_heading = FloatToEQ10(0); outapp_push->priority = 6; entity_list.QueueClients(this, outapp_push, true); CastToClient()->FastQueuePacket(&outapp_push); @@ -4973,7 +5004,7 @@ void Mob::DoGravityEffect() } if(IsClient()) - this->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), cur_x, cur_y, new_ground, GetHeading()*2); // I know the heading thing is weird(chance of movepc to halve the heading value, too lazy to figure out why atm) + this->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), cur_x, cur_y, new_ground, GetHeading()); else this->GMMove(cur_x, cur_y, new_ground, GetHeading()); } @@ -5610,8 +5641,7 @@ bool Mob::IsFacingMob(Mob *other) if (!other) return false; float angle = HeadingAngleToMob(other); - // what the client uses appears to be 2x our internal heading - float heading = GetHeading() * 2.0f; + float heading = GetHeading(); if (angle > 472.0 && heading < 40.0) angle = heading; @@ -5625,15 +5655,13 @@ bool Mob::IsFacingMob(Mob *other) } // All numbers derived from the client -float Mob::HeadingAngleToMob(Mob *other) +float Mob::HeadingAngleToMob(float other_x, float other_y) { - float mob_x = other->GetX(); - float mob_y = other->GetY(); float this_x = GetX(); float this_y = GetY(); - float y_diff = std::abs(this_y - mob_y); - float x_diff = std::abs(this_x - mob_x); + float y_diff = std::abs(this_y - other_y); + float x_diff = std::abs(this_x - other_x); if (y_diff < 0.0000009999999974752427) y_diff = 0.0000009999999974752427; @@ -5641,13 +5669,13 @@ float Mob::HeadingAngleToMob(Mob *other) // return the right thing based on relative quadrant // I'm sure this could be improved for readability, but whatever - if (this_y >= mob_y) { - if (mob_x >= this_x) + if (this_y >= other_y) { + if (other_x >= this_x) return (90.0f - angle + 90.0f) * 511.5f * 0.0027777778f; - if (mob_x <= this_x) + if (other_x <= this_x) return (angle + 180.0f) * 511.5f * 0.0027777778f; } - if (this_y > mob_y || mob_x > this_x) + if (this_y > other_y || other_x > this_x) return angle * 511.5f * 0.0027777778f; else return (90.0f - angle + 270.0f) * 511.5f * 0.0027777778f; diff --git a/zone/mob.h b/zone/mob.h index 058774c54..cb8e7b261 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -50,6 +50,8 @@ struct AuraRecord; struct NewSpawn_Struct; struct PlayerPositionUpdateServer_Struct; +const int COLLISION_BOX_SIZE = 8; + namespace EQEmu { struct ItemData; @@ -162,6 +164,8 @@ public: inline virtual bool IsMob() const { return true; } inline virtual bool InZone() const { return true; } + bool is_distance_roamer; + //Somewhat sorted: needs documenting! //Attack @@ -175,7 +179,8 @@ public: inline bool InFrontMob(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const { return (!other || other == this) ? true : MobAngle(other, ourx, oury) < 56.0f; } bool IsFacingMob(Mob *other); // kind of does the same as InFrontMob, but derived from client - float HeadingAngleToMob(Mob *other); // to keep consistent with client generated messages + float HeadingAngleToMob(Mob *other) { return HeadingAngleToMob(other->GetX(), other->GetY()); } + float HeadingAngleToMob(float other_x, float other_y); // to keep consistent with client generated messages virtual void RangedAttack(Mob* other) { } virtual void ThrowingAttack(Mob* other) { } // 13 = Primary (default), 14 = secondary @@ -199,6 +204,7 @@ public: void ApplyMeleeDamageMods(uint16 skill, int &damage, Mob * defender = nullptr, ExtraAttackOptions *opts = nullptr); int ACSum(); int offense(EQEmu::skills::SkillType skill); + int GetBestMeleeSkill(); void CalcAC() { mitigation_ac = ACSum(); } int GetACSoftcap(); double GetSoftcapReturns(); @@ -278,6 +284,7 @@ public: float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false, int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false, int level_override = -1); + int GetResist(uint8 resist_type); int ResistPhysical(int level_diff, uint8 caster_level); int ResistElementalWeaponDmg(const EQEmu::ItemInstance *item); int CheckBaneDamage(const EQEmu::ItemInstance *item); @@ -349,6 +356,7 @@ public: virtual int GetMaxSongSlots() const { return 0; } virtual int GetMaxDiscSlots() const { return 0; } virtual int GetMaxTotalSlots() const { return 0; } + bool HasDiscBuff(); virtual uint32 GetFirstBuffSlot(bool disc, bool song); virtual uint32 GetLastBuffSlot(bool disc, bool song); virtual void InitializeBuffSlots() { buffs = nullptr; current_buff_count = 0; } @@ -434,6 +442,20 @@ public: inline uint8 GetDrakkinHeritage() const { return drakkin_heritage; } inline uint8 GetDrakkinTattoo() const { return drakkin_tattoo; } inline uint8 GetDrakkinDetails() const { return drakkin_details; } + inline void ChangeRace(uint16 in) { race = in; } + inline void ChangeGender(uint8 in) { gender = in;} + inline void ChangeTexture(uint8 in) { texture = in; } + inline void ChangeHelmTexture(uint8 in) { helmtexture = in; } + inline void ChangeHairColor(uint8 in) { haircolor = in; } + inline void ChangeBeardColor(uint8 in) { beardcolor = in; } + inline void ChangeEyeColor1(uint8 in) { eyecolor1 = in; } + inline void ChangeEyeColor2(uint8 in) { eyecolor2 = in; } + inline void ChangeHairStyle(uint8 in) { hairstyle = in; } + inline void ChangeLuclinFace(uint8 in) { luclinface = in; } + inline void ChangeBeard(uint8 in) { beard = in; } + inline void ChangeDrakkinHeritage(uint8 in) { drakkin_heritage = in; } + inline void ChangeDrakkinTattoo(uint8 in) { drakkin_tattoo = in; } + inline void ChangeDrakkinDetails(uint8 in) { drakkin_details = in; } inline uint32 GetArmorTint(uint8 i) const { return armor_tint.Slot[(i < EQEmu::textures::materialCount) ? i : 0].Color; } inline uint8 GetClass() const { return class_; } inline uint8 GetLevel() const { return level; } @@ -550,12 +572,20 @@ public: void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu); void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu); void SendPosition(); + void StopMoving(); + void StopMoving(float new_heading); void SetSpawned() { spawned = true; }; bool Spawned() { return spawned; }; virtual bool ShouldISpawnFor(Client *c) { return true; } void SetFlyMode(uint8 flymode); inline void Teleport(glm::vec3 NewPosition) { m_Position.x = NewPosition.x; m_Position.y = NewPosition.y; m_Position.z = NewPosition.z; }; + void TryMoveAlong(float distance, float angle, bool send = true); + void ProcessForcedMovement(); + inline void IncDeltaX(float in) { m_Delta.x += in; } + inline void IncDeltaY(float in) { m_Delta.y += in; } + inline void IncDeltaZ(float in) { m_Delta.z += in; } + inline void SetForcedMovement(int in) { ForcedMovement = in; } //AI static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel); @@ -593,6 +623,7 @@ public: std::list& GetHateList() { return hate_list.GetHateList(); } bool CheckLosFN(Mob* other); bool CheckLosFN(float posX, float posY, float posZ, float mobSize); + static bool CheckLosFN(glm::vec3 posWatcher, float sizeWatcher, glm::vec3 posTarget, float sizeTarget); inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); } inline const uint32 LastChange() const { return pLastChange; } inline void SetLastLosState(bool value) { last_los_check = value; } @@ -667,6 +698,8 @@ public: void SetFollowDistance(uint32 dist) { follow_dist = dist; } uint32 GetFollowID() const { return follow; } uint32 GetFollowDistance() const { return follow_dist; } + inline bool IsRareSpawn() const { return rare_spawn; } + inline void SetRareSpawn(bool in) { rare_spawn = in; } virtual void Message(uint32 type, const char* message, ...) { } virtual void Message_StringID(uint32 type, uint32 string_id, uint32 distance = 0) { } @@ -946,15 +979,16 @@ public: inline bool IsBlind() { return spellbonuses.IsBlind; } inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);} - float CalculateHeadingToTarget(float in_x, float in_y); - bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = false, bool calcheading = true); - virtual bool CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true); + float CalculateHeadingToTarget(float in_x, float in_y) {return HeadingAngleToMob(in_x, in_y); } + bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = false, bool calcHeading = true); + virtual bool CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ = true, bool calcHeading = true); float CalculateDistance(float x, float y, float z); float GetGroundZ(float new_x, float new_y, float z_offset=0.0); void SendTo(float new_x, float new_y, float new_z); void SendToFixZ(float new_x, float new_y, float new_z); float GetZOffset() const; - void FixZ(int32 z_find_offset = 5); + void FixZ(int32 z_find_offset = 5); + float GetFixedZ(glm::vec3 position, int32 z_find_offset = 5); void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false); inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; } inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; } @@ -1108,8 +1142,6 @@ public: int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item); int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr); - float last_z; - // Bots HealRotation methods #ifdef BOTS bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); } @@ -1131,7 +1163,7 @@ protected: int _GetWalkSpeed() const; int _GetRunSpeed() const; int _GetFearSpeed() const; - virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed); + virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ = true, bool calcHeading = true); virtual bool AI_EngagedCastCheck() { return(false); } virtual bool AI_PursueCastCheck() { return(false); } @@ -1204,6 +1236,7 @@ protected: uint32 follow; uint32 follow_dist; bool no_target_hotkey; + bool rare_spawn; uint32 m_PlayerState; uint32 GetPlayerState() { return m_PlayerState; } @@ -1225,7 +1258,8 @@ protected: uint32 npctype_id; glm::vec4 m_Position; /* Used to determine when an NPC has traversed so many units - to send a zone wide pos update */ - glm::vec4 last_major_update_position; + glm::vec4 last_major_update_position; + int animation; // this is really what MQ2 calls SpeedRun just packed like (int)(SpeedRun * 40.0f) float base_size; float size; @@ -1267,6 +1301,7 @@ protected: virtual int16 GetFocusEffect(focusType type, uint16 spell_id) { return 0; } void CalculateNewFearpoint(); float FindGroundZ(float new_x, float new_y, float z_offset=0.0); + float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0); glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached); void PrintRoute(); @@ -1286,6 +1321,9 @@ protected: char lastname[64]; glm::vec4 m_Delta; + // just locs around them to double check, if we do expand collision this should be cached on movement + // ideally we should use real models, but this should be quick and work mostly + glm::vec4 m_CollisionBox[COLLISION_BOX_SIZE]; EQEmu::LightSourceProfile m_Light; @@ -1396,6 +1434,7 @@ protected: std::unique_ptr AI_movement_timer; std::unique_ptr AI_target_check_timer; bool movetimercompleted; + int8 ForcedMovement; // push bool permarooted; std::unique_ptr AI_scan_area_timer; std::unique_ptr AI_walking_timer; @@ -1413,6 +1452,7 @@ protected: void AddItemFactionBonus(uint32 pFactionID,int32 bonus); int32 GetItemFactionBonus(uint32 pFactionID); void ClearItemFactionBonuses(); + Timer mHateListCleanup; void CalculateFearPosition(); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index fb8faebf0..134beee0a 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -29,12 +29,16 @@ #include "quest_parser_collection.h" #include "string_ids.h" #include "water_map.h" +#include "fastmath.h" +#include #include #include +#include #include extern EntityList entity_list; +extern FastMath g_Math; extern Zone *zone; @@ -47,7 +51,7 @@ extern Zone *zone; #endif //NOTE: do NOT pass in beneficial and detrimental spell types into the same call here! -bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { +bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates) { if (!tar) return false; @@ -61,7 +65,8 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { // Any sane mob would cast if they can. bool cast_only_option = (IsRooted() && !CombatRange(tar)); - if (!cast_only_option && iChance < 100) { + // innates are always attempted + if (!cast_only_option && iChance < 100 && !bInnates) { if (zone->random.Int(0, 100) >= iChance) return false; } @@ -84,6 +89,19 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { //return false; continue; } + + if ((AIspells[i].priority == 0 && !bInnates) || (AIspells[i].priority != 0 && bInnates)) { + // so "innate" spells are special and spammed a bit + // we define an innate spell as a spell with priority 0 + continue; + } + + if (AIspells[i].min_hp != 0 && GetIntHPRatio() < AIspells[i].min_hp) + continue; + + if (AIspells[i].max_hp != 0 && GetIntHPRatio() > AIspells[i].max_hp) + continue; + if (iSpellTypes & AIspells[i].type) { // manacost has special values, -1 is no mana cost, -2 is instant cast (no mana) int32 mana_cost = AIspells[i].manacost; @@ -91,15 +109,19 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { mana_cost = spells[AIspells[i].spellid].mana; else if (mana_cost == -2) mana_cost = 0; + // this is ugly -- ignore distance for hatelist spells, looks like the client is only checking distance for some targettypes in CastSpell, + // should probably match that eventually. This should be good enough for now I guess .... if ( - (( - (spells[AIspells[i].spellid].targettype==ST_AECaster || spells[AIspells[i].spellid].targettype==ST_AEBard) - && dist2 <= spells[AIspells[i].spellid].aoerange*spells[AIspells[i].spellid].aoerange - ) || - dist2 <= spells[AIspells[i].spellid].range*spells[AIspells[i].spellid].range - ) + ( + (spells[AIspells[i].spellid].targettype == ST_HateList || spells[AIspells[i].spellid].targettype == ST_AETargetHateList) || + ( + (spells[AIspells[i].spellid].targettype==ST_AECaster || spells[AIspells[i].spellid].targettype==ST_AEBard) + && dist2 <= spells[AIspells[i].spellid].aoerange*spells[AIspells[i].spellid].aoerange + ) || + dist2 <= spells[AIspells[i].spellid].range*spells[AIspells[i].spellid].range + ) && (mana_cost <= GetMana() || GetMana() == GetMaxMana()) - && (AIspells[i].time_cancast + (zone->random.Int(0, 4) * 1000)) <= Timer::GetCurrentTime() //break up the spelling casting over a period of time. + && (AIspells[i].time_cancast + (zone->random.Int(0, 4) * 500)) <= Timer::GetCurrentTime() //break up the spelling casting over a period of time. ) { #if MobAI_DEBUG_Spells >= 21 @@ -127,7 +149,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { } case SpellType_Root: { Mob *rootee = GetHateRandom(); - if (rootee && !rootee->IsRooted() && zone->random.Roll(50) + if (rootee && !rootee->IsRooted() && !rootee->IsFeared() && (bInnates || zone->random.Roll(50)) && rootee->DontRootMeBefore() < Timer::GetCurrentTime() && rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { @@ -166,7 +188,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { } case SpellType_InCombatBuff: { - if(zone->random.Roll(50)) + if(bInnates || zone->random.Roll(50)) { AIDoSpellCast(i, tar, mana_cost); return true; @@ -185,7 +207,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { case SpellType_Slow: case SpellType_Debuff: { Mob * debuffee = GetHateRandom(); - if (debuffee && manaR >= 10 && zone->random.Roll(70) && + if (debuffee && manaR >= 10 && (bInnates || zone->random.Roll(70)) && debuffee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0) { if (!checked_los) { if (!CheckLosFN(debuffee)) @@ -199,8 +221,8 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { } case SpellType_Nuke: { if ( - manaR >= 10 && zone->random.Roll(70) - && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 + manaR >= 10 && (bInnates || (zone->random.Roll(70) + && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), false) >= 0)) // saying it's a nuke here, AI shouldn't care too much if overwriting ) { if(!checked_los) { if(!CheckLosFN(tar)) @@ -213,7 +235,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { break; } case SpellType_Dispel: { - if(zone->random.Roll(15)) + if(bInnates || zone->random.Roll(15)) { if(!checked_los) { if(!CheckLosFN(tar)) @@ -229,7 +251,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { break; } case SpellType_Mez: { - if(zone->random.Roll(20)) + if(bInnates || zone->random.Roll(20)) { Mob * mezTar = nullptr; mezTar = entity_list.GetTargetForMez(this); @@ -245,7 +267,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { case SpellType_Charm: { - if(!IsPet() && zone->random.Roll(20)) + if(!IsPet() && (bInnates || zone->random.Roll(20))) { Mob * chrmTar = GetHateRandom(); if(chrmTar && chrmTar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0) @@ -259,7 +281,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { case SpellType_Pet: { //keep mobs from recasting pets when they have them. - if (!IsPet() && !GetPetID() && zone->random.Roll(25)) { + if (!IsPet() && !GetPetID() && (bInnates || zone->random.Roll(25))) { AIDoSpellCast(i, tar, mana_cost); return true; } @@ -267,7 +289,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { } case SpellType_Lifetap: { if (GetHPRatio() <= 95 - && zone->random.Roll(50) + && (bInnates || zone->random.Roll(50)) && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { if(!checked_los) { @@ -283,7 +305,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { case SpellType_Snare: { if ( !tar->IsRooted() - && zone->random.Roll(50) + && (bInnates || zone->random.Roll(50)) && tar->DontSnareMeBefore() < Timer::GetCurrentTime() && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { @@ -301,7 +323,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { } case SpellType_DOT: { if ( - zone->random.Roll(60) + (bInnates || zone->random.Roll(60)) && tar->DontDotMeBefore() < Timer::GetCurrentTime() && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { @@ -502,8 +524,8 @@ void NPC::AI_Start(uint32 iMoveDelay) { AIautocastspell_timer = std::unique_ptr(new Timer(1000)); AIautocastspell_timer->Disable(); } else { - AIautocastspell_timer = std::unique_ptr(new Timer(750)); - AIautocastspell_timer->Start(RandomTimer(0, 15000), false); + AIautocastspell_timer = std::unique_ptr(new Timer(500)); + AIautocastspell_timer->Start(RandomTimer(0, 300), false); } if (NPCTypedata) { @@ -900,29 +922,26 @@ void Client::AI_Process() } } - if(IsPet()) - { - Mob* owner = GetOwner(); - if(owner == nullptr) + if (IsPet()) { + Mob *owner = GetOwner(); + if (owner == nullptr) return; float dist = DistanceSquared(m_Position, owner->GetPosition()); - if (dist >= 400) - { - if(AI_movement_timer->Check()) - { - int nspeed = (dist >= 5625 ? GetRunspeed() : GetWalkspeed()); + if (dist >= 202500) { // >= 450 distance + Teleport(static_cast(owner->GetPosition())); + SendPositionUpdate(); // this shouldn't happen a lot (and hard to make it) so lets not rate limit + } else if (dist >= 400) { // >=20 + if (AI_movement_timer->Check()) { + int nspeed = (dist >= 1225 ? GetRunspeed() : GetWalkspeed()); // >= 35 animation = nspeed; nspeed *= 2; SetCurrentSpeed(nspeed); CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed); } - } - else - { - if(moved) - { + } else { + if (moved) { SetCurrentSpeed(0); moved = false; } @@ -931,6 +950,91 @@ void Client::AI_Process() } } +void Mob::ProcessForcedMovement() +{ + // we are being pushed, we will hijack this movement timer + // this also needs to be done before casting to have a chance to interrupt + // this flag won't be set if the mob can't be pushed (rooted etc) + if (AI_movement_timer->Check()) { + bool bPassed = true; + glm::vec3 normal; + + // no zone map = fucked + if (zone->HasMap()) { + // in front + m_CollisionBox[0].x = m_Position.x + 3.0f * g_Math.FastSin(0.0f); + m_CollisionBox[0].y = m_Position.y + 3.0f * g_Math.FastCos(0.0f); + m_CollisionBox[0].z = m_Position.z; + + // 45 right front + m_CollisionBox[1].x = m_Position.x + 3.0f * g_Math.FastSin(64.0f); + m_CollisionBox[1].y = m_Position.y + 3.0f * g_Math.FastCos(64.0f); + m_CollisionBox[1].z = m_Position.z; + + // to right + m_CollisionBox[2].x = m_Position.x + 3.0f * g_Math.FastSin(128.0f); + m_CollisionBox[2].y = m_Position.y + 3.0f * g_Math.FastCos(128.0f); + m_CollisionBox[2].z = m_Position.z; + + // 45 right back + m_CollisionBox[3].x = m_Position.x + 3.0f * g_Math.FastSin(192.0f); + m_CollisionBox[3].y = m_Position.y + 3.0f * g_Math.FastCos(192.0f); + m_CollisionBox[3].z = m_Position.z; + + // behind + m_CollisionBox[4].x = m_Position.x + 3.0f * g_Math.FastSin(256.0f); + m_CollisionBox[4].y = m_Position.y + 3.0f * g_Math.FastCos(256.0f); + m_CollisionBox[4].z = m_Position.z; + + // 45 left back + m_CollisionBox[5].x = m_Position.x + 3.0f * g_Math.FastSin(320.0f); + m_CollisionBox[5].y = m_Position.y + 3.0f * g_Math.FastCos(320.0f); + m_CollisionBox[5].z = m_Position.z; + + // to left + m_CollisionBox[6].x = m_Position.x + 3.0f * g_Math.FastSin(384.0f); + m_CollisionBox[6].y = m_Position.y + 3.0f * g_Math.FastCos(384.0f); + m_CollisionBox[6].z = m_Position.z; + + // 45 left front + m_CollisionBox[7].x = m_Position.x + 3.0f * g_Math.FastSin(448.0f); + m_CollisionBox[7].y = m_Position.y + 3.0f * g_Math.FastCos(448.0f); + m_CollisionBox[7].z = m_Position.z; + + // collision happened, need to move along the wall + float distance = 0.0f, shortest = std::numeric_limits::infinity(); + glm::vec3 tmp_nrm; + for (auto &vec : m_CollisionBox) { + if (zone->zonemap->DoCollisionCheck(vec, vec + m_Delta, tmp_nrm, distance)) { + bPassed = false; // lets try with new projection next pass + if (distance < shortest) { + normal = tmp_nrm; + shortest = distance; + } + } + } + } + + if (bPassed) { + ForcedMovement = 0; + Teleport(m_Position + m_Delta); + m_Delta = glm::vec4(); + SendPositionUpdate(); + pLastChange = Timer::GetCurrentTime(); + FixZ(); // so we teleport to the ground locally, we want the client to interpolate falling etc + } else if (--ForcedMovement) { + if (normal.z < -0.15f) // prevent too much wall climbing. ex. OMM's room in anguish + normal.z = 0.0f; + auto proj = glm::proj(static_cast(m_Delta), normal); + m_Delta.x -= proj.x; + m_Delta.y -= proj.y; + m_Delta.z -= proj.z; + } else { + m_Delta = glm::vec4(); // well, we failed to find a spot to be forced to, lets give up + } + } +} + void Mob::AI_Process() { if (!IsAIControlled()) return; @@ -938,6 +1042,7 @@ void Mob::AI_Process() { if (!(AI_think_timer->Check() || attack_timer.Check(false))) return; + if (IsCasting()) return; @@ -1021,6 +1126,18 @@ void Mob::AI_Process() { if (!(m_PlayerState & static_cast(PlayerState::Aggressive))) SendAddPlayerState(PlayerState::Aggressive); + + // NPCs will forget people after 10 mins of not interacting with them or out of range + // both of these maybe zone specific, hardcoded for now + if (mHateListCleanup.Check()) { + hate_list.RemoveStaleEntries(600000, 600.0f); + if (hate_list.IsHateListEmpty()) { + AI_Event_NoLongerEngaged(); + zone->DelAggroMob(); + if (IsNPC() && !RuleB(Aggro, AllowTickPulling)) + ResetAssistCap(); + } + } // we are prevented from getting here if we are blind and don't have a target in range // from above, so no extra blind checks needed if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind()) @@ -1391,19 +1508,33 @@ void Mob::AI_Process() { //if(owner->IsClient()) // printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ()); - float dist = DistanceSquared(m_Position, owner->GetPosition()); - if (dist >= 400) + glm::vec4 ownerPos = owner->GetPosition(); + float dist = DistanceSquared(m_Position, ownerPos); + float distz = ownerPos.z - m_Position.z; + + if (dist >= 400 || distz > 100) { int speed = GetWalkspeed(); - if (dist >= 5625) + if (dist >= 1225) // 35 speed = GetRunspeed(); - CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed); + if (dist >= 202500 || distz > 100) // dist >= 450 + { + m_Position = ownerPos; + SendPositionUpdate(); + moved = true; + } + else + { + CalculateNewPosition2(owner->GetX(), + owner->GetY(), owner->GetZ(), speed); + } } else { if(moved) { + this->FixZ(); SetCurrentSpeed(0); moved = false; } @@ -1582,18 +1713,22 @@ void NPC::AI_DoMovement() { } this->FixZ(); - SendPosition(); //kick off event_waypoint arrive char temp[16]; sprintf(temp, "%d", cur_wp); parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0); - // start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted. - if (!AI_walking_timer->Enabled()) + // No need to move as we are there. Next loop will + // take care of normal grids, even at pause 0. + // We do need to call and setup a wp if we're cur_wp=-2 + // as that is where roamer is unset and we don't want + // the next trip through to move again based on grid stuff. + doMove = false; + if (cur_wp == -2) { AI_SetupNextWaypoint(); - else - doMove = false; + } + // wipe feign memory since we reached our first waypoint if(cur_wp == 1) ClearFeignMemory(); @@ -1744,6 +1879,12 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) { SetAppearance(eaStanding); + /* + Kick off auto cast timer + */ + if (this->IsNPC()) + this->CastToNPC()->AIautocastspell_timer->Start(300, false); + if (iYellForHelp) { if(IsPet()) { GetOwner()->AI_Event_Engaged(attacker, iYellForHelp); @@ -1849,14 +1990,17 @@ bool NPC::AI_EngagedCastCheck() { Log(Logs::Detail, Logs::AI, "Engaged autocast check triggered. Trying to cast healing spells then maybe offensive spells."); - // try casting a heal or gate - if (!AICastSpell(this, AISpellVar.engaged_beneficial_self_chance, SpellType_Heal | SpellType_Escape | SpellType_InCombatBuff)) { - // try casting a heal on nearby - if (!entity_list.AICheckCloseBeneficialSpells(this, AISpellVar.engaged_beneficial_other_chance, MobAISpellRange, SpellType_Heal)) { - //nobody to heal, try some detrimental spells. - if(!AICastSpell(GetTarget(), AISpellVar.engaged_detrimental_chance, SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root)) { - //no spell to cast, try again soon. - AIautocastspell_timer->Start(RandomTimer(AISpellVar.engaged_no_sp_recast_min, AISpellVar.engaged_no_sp_recast_max), false); + // first try innate (spam) spells + if(!AICastSpell(GetTarget(), 0, SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root, true)) { + // try casting a heal or gate + if (!AICastSpell(this, AISpellVar.engaged_beneficial_self_chance, SpellType_Heal | SpellType_Escape | SpellType_InCombatBuff)) { + // try casting a heal on nearby + if (!entity_list.AICheckCloseBeneficialSpells(this, AISpellVar.engaged_beneficial_other_chance, MobAISpellRange, SpellType_Heal)) { + //nobody to heal, try some detrimental spells. + if(!AICastSpell(GetTarget(), AISpellVar.engaged_detrimental_chance, SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root)) { + //no spell to cast, try again soon. + AIautocastspell_timer->Start(RandomTimer(AISpellVar.engaged_no_sp_recast_min, AISpellVar.engaged_no_sp_recast_max), false); + } } } } @@ -1871,10 +2015,13 @@ bool NPC::AI_PursueCastCheck() { AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. Log(Logs::Detail, Logs::AI, "Engaged (pursuing) autocast check triggered. Trying to cast offensive spells."); - if(!AICastSpell(GetTarget(), AISpellVar.pursue_detrimental_chance, SpellType_Root | SpellType_Nuke | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff)) { - //no spell cast, try again soon. - AIautocastspell_timer->Start(RandomTimer(AISpellVar.pursue_no_sp_recast_min, AISpellVar.pursue_no_sp_recast_max), false); - } //else, spell casting finishing will reset the timer. + // checking innate (spam) spells first + if(!AICastSpell(GetTarget(), AISpellVar.pursue_detrimental_chance, SpellType_Root | SpellType_Nuke | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff, true)) { + if(!AICastSpell(GetTarget(), AISpellVar.pursue_detrimental_chance, SpellType_Root | SpellType_Nuke | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff)) { + //no spell cast, try again soon. + AIautocastspell_timer->Start(RandomTimer(AISpellVar.pursue_no_sp_recast_min, AISpellVar.pursue_no_sp_recast_max), false); + } //else, spell casting finishing will reset the timer. + } return(true); } return(false); @@ -2014,15 +2161,34 @@ bool Mob::Rampage(ExtraAttackOptions *opts) if (m_target) { if (m_target == GetTarget()) continue; - if (CombatRange(m_target)) { + if (DistanceSquaredNoZ(GetPosition(), m_target->GetPosition()) <= NPC_RAMPAGE_RANGE2) { ProcessAttackRounds(m_target, opts); index_hit++; } } } - if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets) - ProcessAttackRounds(GetTarget(), opts); + if (RuleB(Combat, RampageHitsTarget)) { + if (index_hit < rampage_targets) + ProcessAttackRounds(GetTarget(), opts); + } else { // let's do correct behavior here, if they set above rule we can assume they want non-live like behavior + if (index_hit < rampage_targets) { + // so we go over in reverse order and skip range check + // lets do it this way to still support non-live-like >1 rampage targets + // likely live is just a fall through of the last valid mob + for (auto i = RampageArray.crbegin(); i != RampageArray.crend(); ++i) { + if (index_hit >= rampage_targets) + break; + auto m_target = entity_list.GetMob(*i); + if (m_target) { + if (m_target == GetTarget()) + continue; + ProcessAttackRounds(m_target, opts); + index_hit++; + } + } + } + } m_specialattacks = eSpecialAttacks::None; @@ -2317,14 +2483,13 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { return false; } DBnpcspells_Struct* parentlist = database.GetNPCSpells(spell_list->parent_list); - uint32 i; #if MobAI_DEBUG_Spells >= 10 std::string debug_msg = StringFormat("Loading NPCSpells onto %s: dbspellsid=%u", this->GetName(), iDBSpellsID); if (spell_list) { - debug_msg.append(StringFormat(" (found, %u), parentlist=%u", spell_list->numentries, spell_list->parent_list)); + debug_msg.append(StringFormat(" (found, %u), parentlist=%u", spell_list->entries.size(), spell_list->parent_list)); if (spell_list->parent_list) { if (parentlist) - debug_msg.append(StringFormat(" (found, %u)", parentlist->numentries)); + debug_msg.append(StringFormat(" (found, %u)", parentlist->entries.size())); else debug_msg.append(" (not found)"); } @@ -2372,14 +2537,11 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { _idle_no_sp_recast_min = parentlist->idle_no_sp_recast_min; _idle_no_sp_recast_max = parentlist->idle_no_sp_recast_max; _idle_beneficial_chance = parentlist->idle_beneficial_chance; - for (i=0; inumentries; i++) { - if (GetLevel() >= parentlist->entries[i].minlevel && GetLevel() <= parentlist->entries[i].maxlevel && parentlist->entries[i].spellid > 0) { - if (!IsSpellInList(spell_list, parentlist->entries[i].spellid)) + for (auto &e : parentlist->entries) { + if (GetLevel() >= e.minlevel && GetLevel() <= e.maxlevel && e.spellid > 0) { + if (!IsSpellInList(spell_list, e.spellid)) { - AddSpellToNPCList(parentlist->entries[i].priority, - parentlist->entries[i].spellid, parentlist->entries[i].type, - parentlist->entries[i].manacost, parentlist->entries[i].recast_delay, - parentlist->entries[i].resist_adjust); + AddSpellToNPCList(e.priority, e.spellid, e.type, e.manacost, e.recast_delay, e.resist_adjust, e.min_hp, e.max_hp); } } } @@ -2418,14 +2580,12 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { _idle_beneficial_chance = spell_list->idle_beneficial_chance; } - for (i=0; inumentries; i++) { - if (GetLevel() >= spell_list->entries[i].minlevel && GetLevel() <= spell_list->entries[i].maxlevel && spell_list->entries[i].spellid > 0) { - AddSpellToNPCList(spell_list->entries[i].priority, - spell_list->entries[i].spellid, spell_list->entries[i].type, - spell_list->entries[i].manacost, spell_list->entries[i].recast_delay, - spell_list->entries[i].resist_adjust); + for (auto &e : spell_list->entries) { + if (GetLevel() >= e.minlevel && GetLevel() <= e.maxlevel && e.spellid > 0) { + AddSpellToNPCList(e.priority, e.spellid, e.type, e.manacost, e.recast_delay, e.resist_adjust, e.min_hp, e.max_hp); } } + std::sort(AIspells.begin(), AIspells.end(), [](const AISpells_Struct& a, const AISpells_Struct& b) { return a.priority > b.priority; }); @@ -2563,16 +2723,14 @@ bool IsSpellEffectInList(DBnpcspellseffects_Struct* spelleffect_list, uint16 iSp } bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID) { - for (uint32 i=0; i < spell_list->numentries; i++) { - if (spell_list->entries[i].spellid == iSpellID) - return true; - } - return false; + auto it = std::find_if(spell_list->entries.begin(), spell_list->entries.end(), + [iSpellID](const DBnpcspells_entries_Struct &a) { return a.spellid == iSpellID; }); + return it != spell_list->entries.end(); } // adds a spell to the list, taking into account priority and resorting list as needed. void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, - int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust) + int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp) { if(!IsValidSpell(iSpellID)) @@ -2588,12 +2746,14 @@ void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, t.recast_delay = iRecastDelay; t.time_cancast = 0; t.resist_adjust = iResistAdjust; + t.min_hp = min_hp; + t.max_hp = max_hp; AIspells.push_back(t); // If we're going from an empty list, we need to start the timer if (AIspells.size() == 1) - AIautocastspell_timer->Start(RandomTimer(0, 15000), false); + AIautocastspell_timer->Start(RandomTimer(0, 300), false); } void NPC::RemoveSpellFromNPCList(int16 spell_id) @@ -2616,131 +2776,114 @@ void NPC::AISpellsList(Client *c) return; for (auto it = AIspells.begin(); it != AIspells.end(); ++it) - c->Message(0, "%s (%d): Type %d, Priority %d", - spells[it->spellid].name, it->spellid, it->type, it->priority); + c->Message(0, "%s (%d): Type %d, Priority %d, Recast Delay %d, Resist Adjust %d, Min HP %d, Max HP %d", + spells[it->spellid].name, it->spellid, it->type, it->priority, it->recast_delay, it->resist_adjust, it->min_hp, it->max_hp); return; } -DBnpcspells_Struct* ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) { +DBnpcspells_Struct *ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) +{ if (iDBSpellsID == 0) return nullptr; - if (!npc_spells_cache) { - npc_spells_maxid = GetMaxNPCSpellsID(); - npc_spells_cache = new DBnpcspells_Struct*[npc_spells_maxid+1]; - npc_spells_loadtried = new bool[npc_spells_maxid+1]; - for (uint32 i=0; i<=npc_spells_maxid; i++) { - npc_spells_cache[i] = nullptr; - npc_spells_loadtried[i] = false; - } + auto it = npc_spells_cache.find(iDBSpellsID); + + if (it != npc_spells_cache.end()) { // it's in the cache, easy =) + return &it->second; } - if (iDBSpellsID > npc_spells_maxid) - return nullptr; - if (npc_spells_cache[iDBSpellsID]) { // it's in the cache, easy =) - return npc_spells_cache[iDBSpellsID]; - } - - else if (!npc_spells_loadtried[iDBSpellsID]) { // no reason to ask the DB again if we have failed once already - npc_spells_loadtried[iDBSpellsID] = true; + if (!npc_spells_loadtried.count(iDBSpellsID)) { // no reason to ask the DB again if we have failed once already + npc_spells_loadtried.insert(iDBSpellsID); std::string query = StringFormat("SELECT id, parent_list, attack_proc, proc_chance, " - "range_proc, rproc_chance, defensive_proc, dproc_chance, " - "fail_recast, engaged_no_sp_recast_min, engaged_no_sp_recast_max, " - "engaged_b_self_chance, engaged_b_other_chance, engaged_d_chance, " - "pursue_no_sp_recast_min, pursue_no_sp_recast_max, " - "pursue_d_chance, idle_no_sp_recast_min, idle_no_sp_recast_max, " - "idle_b_chance FROM npc_spells WHERE id=%d", iDBSpellsID); - auto results = QueryDatabase(query); - if (!results.Success()) { + "range_proc, rproc_chance, defensive_proc, dproc_chance, " + "fail_recast, engaged_no_sp_recast_min, engaged_no_sp_recast_max, " + "engaged_b_self_chance, engaged_b_other_chance, engaged_d_chance, " + "pursue_no_sp_recast_min, pursue_no_sp_recast_max, " + "pursue_d_chance, idle_no_sp_recast_min, idle_no_sp_recast_max, " + "idle_b_chance FROM npc_spells WHERE id=%d", + iDBSpellsID); + auto results = QueryDatabase(query); + if (!results.Success()) { return nullptr; - } + } - if (results.RowCount() != 1) - return nullptr; + if (results.RowCount() != 1) + return nullptr; - auto row = results.begin(); - uint32 tmpparent_list = atoi(row[1]); - uint16 tmpattack_proc = atoi(row[2]); - uint8 tmpproc_chance = atoi(row[3]); - uint16 tmprange_proc = atoi(row[4]); - int16 tmprproc_chance = atoi(row[5]); - uint16 tmpdefensive_proc = atoi(row[6]); - int16 tmpdproc_chance = atoi(row[7]); - uint32 tmppfail_recast = atoi(row[8]); - uint32 tmpengaged_no_sp_recast_min = atoi(row[9]); - uint32 tmpengaged_no_sp_recast_max = atoi(row[10]); - uint8 tmpengaged_b_self_chance = atoi(row[11]); - uint8 tmpengaged_b_other_chance = atoi(row[12]); - uint8 tmpengaged_d_chance = atoi(row[13]); - uint32 tmppursue_no_sp_recast_min = atoi(row[14]); - uint32 tmppursue_no_sp_recast_max = atoi(row[15]); - uint8 tmppursue_d_chance = atoi(row[16]); - uint32 tmpidle_no_sp_recast_min = atoi(row[17]); - uint32 tmpidle_no_sp_recast_max = atoi(row[18]); - uint8 tmpidle_b_chance = atoi(row[19]); + auto row = results.begin(); + DBnpcspells_Struct spell_set; + + spell_set.parent_list = atoi(row[1]); + spell_set.attack_proc = atoi(row[2]); + spell_set.proc_chance = atoi(row[3]); + spell_set.range_proc = atoi(row[4]); + spell_set.rproc_chance = atoi(row[5]); + spell_set.defensive_proc = atoi(row[6]); + spell_set.dproc_chance = atoi(row[7]); + spell_set.fail_recast = atoi(row[8]); + spell_set.engaged_no_sp_recast_min = atoi(row[9]); + spell_set.engaged_no_sp_recast_max = atoi(row[10]); + spell_set.engaged_beneficial_self_chance = atoi(row[11]); + spell_set.engaged_beneficial_other_chance = atoi(row[12]); + spell_set.engaged_detrimental_chance = atoi(row[13]); + spell_set.pursue_no_sp_recast_min = atoi(row[14]); + spell_set.pursue_no_sp_recast_max = atoi(row[15]); + spell_set.pursue_detrimental_chance = atoi(row[16]); + spell_set.idle_no_sp_recast_min = atoi(row[17]); + spell_set.idle_no_sp_recast_max = atoi(row[18]); + spell_set.idle_beneficial_chance = atoi(row[19]); // pulling fixed values from an auto-increment field is dangerous... - query = StringFormat("SELECT spellid, type, minlevel, maxlevel, " - "manacost, recast_delay, priority, resist_adjust " + query = StringFormat( + "SELECT spellid, type, minlevel, maxlevel, " + "manacost, recast_delay, priority, min_hp, max_hp, resist_adjust " #ifdef BOTS - "FROM %s " - "WHERE npc_spells_id=%d ORDER BY minlevel", (iDBSpellsID >= 3001 && iDBSpellsID <= 3016 ? "bot_spells_entries" : "npc_spells_entries"), iDBSpellsID); + "FROM %s " + "WHERE npc_spells_id=%d ORDER BY minlevel", + (iDBSpellsID >= 3001 && iDBSpellsID <= 3016 ? "bot_spells_entries" : "npc_spells_entries"), + iDBSpellsID); #else - "FROM npc_spells_entries " - "WHERE npc_spells_id=%d ORDER BY minlevel", iDBSpellsID); + "FROM npc_spells_entries " + "WHERE npc_spells_id=%d ORDER BY minlevel", + iDBSpellsID); #endif - results = QueryDatabase(query); + results = QueryDatabase(query); - if (!results.Success()) - { + if (!results.Success()) { return nullptr; - } + } - uint32 tmpSize = sizeof(DBnpcspells_Struct) + (sizeof(DBnpcspells_entries_Struct) * results.RowCount()); - npc_spells_cache[iDBSpellsID] = (DBnpcspells_Struct*) new uchar[tmpSize]; - memset(npc_spells_cache[iDBSpellsID], 0, tmpSize); - npc_spells_cache[iDBSpellsID]->parent_list = tmpparent_list; - npc_spells_cache[iDBSpellsID]->attack_proc = tmpattack_proc; - npc_spells_cache[iDBSpellsID]->proc_chance = tmpproc_chance; - npc_spells_cache[iDBSpellsID]->range_proc = tmprange_proc; - npc_spells_cache[iDBSpellsID]->rproc_chance = tmprproc_chance; - npc_spells_cache[iDBSpellsID]->defensive_proc = tmpdefensive_proc; - npc_spells_cache[iDBSpellsID]->dproc_chance = tmpdproc_chance; - npc_spells_cache[iDBSpellsID]->fail_recast = tmppfail_recast; - npc_spells_cache[iDBSpellsID]->engaged_no_sp_recast_min = tmpengaged_no_sp_recast_min; - npc_spells_cache[iDBSpellsID]->engaged_no_sp_recast_max = tmpengaged_no_sp_recast_max; - npc_spells_cache[iDBSpellsID]->engaged_beneficial_self_chance = tmpengaged_b_self_chance; - npc_spells_cache[iDBSpellsID]->engaged_beneficial_other_chance = tmpengaged_b_other_chance; - npc_spells_cache[iDBSpellsID]->engaged_detrimental_chance = tmpengaged_d_chance; - npc_spells_cache[iDBSpellsID]->pursue_no_sp_recast_min = tmppursue_no_sp_recast_min; - npc_spells_cache[iDBSpellsID]->pursue_no_sp_recast_max = tmppursue_no_sp_recast_max; - npc_spells_cache[iDBSpellsID]->pursue_detrimental_chance = tmppursue_d_chance; - npc_spells_cache[iDBSpellsID]->idle_no_sp_recast_min = tmpidle_no_sp_recast_min; - npc_spells_cache[iDBSpellsID]->idle_no_sp_recast_max = tmpidle_no_sp_recast_max; - npc_spells_cache[iDBSpellsID]->idle_beneficial_chance = tmpidle_b_chance; - npc_spells_cache[iDBSpellsID]->numentries = results.RowCount(); + int entryIndex = 0; + for (row = results.begin(); row != results.end(); ++row, ++entryIndex) { + DBnpcspells_entries_Struct entry; + int spell_id = atoi(row[0]); + entry.spellid = spell_id; + entry.type = atoul(row[1]); + entry.minlevel = atoi(row[2]); + entry.maxlevel = atoi(row[3]); + entry.manacost = atoi(row[4]); + entry.recast_delay = atoi(row[5]); + entry.priority = atoi(row[6]); + entry.min_hp = atoi(row[7]); + entry.max_hp = atoi(row[8]); - int entryIndex = 0; - for (row = results.begin(); row != results.end(); ++row, ++entryIndex) - { - int spell_id = atoi(row[0]); - npc_spells_cache[iDBSpellsID]->entries[entryIndex].spellid = spell_id; - npc_spells_cache[iDBSpellsID]->entries[entryIndex].type = atoul(row[1]); - npc_spells_cache[iDBSpellsID]->entries[entryIndex].minlevel = atoi(row[2]); - npc_spells_cache[iDBSpellsID]->entries[entryIndex].maxlevel = atoi(row[3]); - npc_spells_cache[iDBSpellsID]->entries[entryIndex].manacost = atoi(row[4]); - npc_spells_cache[iDBSpellsID]->entries[entryIndex].recast_delay = atoi(row[5]); - npc_spells_cache[iDBSpellsID]->entries[entryIndex].priority = atoi(row[6]); + // some spell types don't make much since to be priority 0, so fix that + if (!(entry.type & SpellTypes_Innate) && entry.priority == 0) + entry.priority = 1; - if(row[7]) - npc_spells_cache[iDBSpellsID]->entries[entryIndex].resist_adjust = atoi(row[7]); - else if(IsValidSpell(spell_id)) - npc_spells_cache[iDBSpellsID]->entries[entryIndex].resist_adjust = spells[spell_id].ResistDiff; - } + if (row[9]) + entry.resist_adjust = atoi(row[9]); + else if (IsValidSpell(spell_id)) + entry.resist_adjust = spells[spell_id].ResistDiff; - return npc_spells_cache[iDBSpellsID]; + spell_set.entries.push_back(entry); + } + + npc_spells_cache.insert(std::make_pair(iDBSpellsID, spell_set)); + + return &npc_spells_cache[iDBSpellsID]; } return nullptr; diff --git a/zone/npc.cpp b/zone/npc.cpp index a4e6c4214..b9aec3abb 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -135,6 +135,9 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if respawn2 = in_respawn; swarm_timer.Disable(); + if (size < 0.0f) + size = GetRaceGenderDefaultHeight(race, gender); + taunting = false; proximity = nullptr; copper = 0; @@ -208,6 +211,24 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if avoidance_rating = d->avoidance_rating; ATK = d->ATK; + // used for when switch back to charm + default_ac = d->AC; + default_min_dmg = min_dmg; + default_max_dmg = max_dmg; + default_attack_delay = d->attack_delay; + default_accuracy_rating = d->accuracy_rating; + default_avoidance_rating = d->avoidance_rating; + default_atk = d->ATK; + + // used for when getting charmed, if 0, doesn't swap + charm_ac = d->charm_ac; + charm_min_dmg = d->charm_min_dmg; + charm_max_dmg = d->charm_max_dmg; + charm_attack_delay = d->charm_attack_delay; + charm_accuracy_rating = d->charm_accuracy_rating; + charm_avoidance_rating = d->charm_avoidance_rating; + charm_atk = d->charm_atk; + CalcMaxMana(); SetMana(GetMaxMana()); @@ -227,6 +248,8 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if roambox_delay = 1000; p_depop = false; loottable_id = d->loottable_id; + skip_global_loot = d->skip_global_loot; + rare_spawn = d->rare_spawn; no_target_hotkey = d->no_target_hotkey; @@ -436,6 +459,26 @@ void NPC::SetTarget(Mob* mob) { //attack_timer.Disable(); attack_dw_timer.Disable(); } + + // either normal pet and owner is client or charmed pet and owner is client + Mob *owner = nullptr; + if (IsPet() && IsPetOwnerClient()) { + owner = GetOwner(); + } else if (IsCharmed()) { + owner = GetOwner(); + if (owner && !owner->IsClient()) + owner = nullptr; + } + + if (owner) { + auto client = owner->CastToClient(); + if (client->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) { + auto app = new EQApplicationPacket(OP_PetHoTT, sizeof(ClientTarget_Struct)); + auto ct = (ClientTarget_Struct *)app->pBuffer; + ct->new_target = mob ? mob->GetID() : 0; + client->FastQueuePacket(&app); + } + } Mob::SetTarget(mob); } @@ -543,9 +586,7 @@ void NPC::QueryLoot(Client* to) linker.SetLinkType(EQEmu::saylink::SayLinkLootItem); linker.SetLootData(*cur); - auto item_link = linker.GenerateLink(); - - to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), (*cur)->item_id, (*cur)->min_level, (*cur)->max_level); + to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", linker.GenerateLink().c_str(), (*cur)->item_id, (*cur)->min_level, (*cur)->max_level); } to->Message(0, "%i items on %s.", x, GetName()); @@ -724,6 +765,10 @@ bool NPC::Process() reface_timer->Disable(); } + // needs to be done before mez and stun + if (ForcedMovement) + ProcessForcedMovement(); + if (IsMezzed()) return true; @@ -900,6 +945,7 @@ bool NPC::SpawnZoneController(){ npc_type->d_melee_texture2 = 0; npc_type->merchanttype = 0; npc_type->bodytype = 11; + npc_type->skip_global_loot = true; if (RuleB(Zone, EnableZoneControllerGlobals)) { npc_type->qglobal = true; @@ -2110,6 +2156,8 @@ void NPC::LevelScale() { if(level > 15 && level <= 25) scale_adjust = 2; + AC += (int)(AC * scaling); + ATK += (int)(ATK * scaling); base_hp += (int)(base_hp * scaling); max_hp += (int)(max_hp * scaling); cur_hp = max_hp; @@ -2616,3 +2664,42 @@ void NPC::DepopSwarmPets() } } } + +void NPC::ModifyStatsOnCharm(bool bRemoved) +{ + if (bRemoved) { + if (charm_ac) + AC = default_ac; + if (charm_attack_delay) + attack_delay = default_attack_delay; + if (charm_accuracy_rating) + accuracy_rating = default_accuracy_rating; + if (charm_avoidance_rating) + avoidance_rating = default_avoidance_rating; + if (charm_atk) + ATK = default_atk; + if (charm_min_dmg || charm_max_dmg) { + base_damage = round((default_max_dmg - default_min_dmg) / 1.9); + min_damage = default_min_dmg - round(base_damage / 10.0); + } + } else { + if (charm_ac) + AC = charm_ac; + if (charm_attack_delay) + attack_delay = charm_attack_delay; + if (charm_accuracy_rating) + accuracy_rating = charm_accuracy_rating; + if (charm_avoidance_rating) + avoidance_rating = charm_avoidance_rating; + if (charm_atk) + ATK = charm_atk; + if (charm_min_dmg || charm_max_dmg) { + base_damage = round((charm_max_dmg - charm_min_dmg) / 1.9); + min_damage = charm_min_dmg - round(base_damage / 10.0); + } + } + // the rest of the stats aren't cached, so lets just do these two instead of full CalcBonuses() + SetAttackTimer(); + CalcAC(); +} + diff --git a/zone/npc.h b/zone/npc.h index c973eb79d..2e264ce24 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -61,6 +61,8 @@ struct AISpells_Struct { int32 recast_delay; int16 priority; int16 resist_adjust; + int8 min_hp; // >0 won't cast if HP is below + int8 max_hp; // >0 won't cast if HP is above }; struct AISpellsEffects_Struct { @@ -183,6 +185,7 @@ public: void AddItem(uint32 itemid, uint16 charges, bool equipitem = true, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0); void AddLootTable(); void AddLootTable(uint32 ldid); + void CheckGlobalLootTables(); void DescribeAggro(Client *towho, Mob *mob, bool verbose); void RemoveItem(uint32 item_id, uint16 quantity = 0, uint16 slot = 0); void CheckMinMaxLevel(Mob *them); @@ -195,6 +198,7 @@ public: uint32 CountLoot(); inline uint32 GetLoottableID() const { return loottable_id; } virtual void UpdateEquipmentLight(); + inline bool DropsGlobalLoot() const { return !skip_global_loot; } inline uint32 GetCopper() const { return copper; } inline uint32 GetSilver() const { return silver; } @@ -280,6 +284,8 @@ public: int32 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; } inline const char* GetAmmoIDfile() const { return ammo_idfile; } + void ModifyStatsOnCharm(bool bRemoved); + //waypoint crap int GetMaxWp() const { return max_wp; } void DisplayWaypointInfo(Client *to); @@ -378,7 +384,7 @@ public: void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots uint32 GetAdventureTemplate() const { return adventure_template_id; } - void AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust); + void AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp); void AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base, int32 limit, int32 max); void RemoveSpellFromNPCList(int16 spell_id); Timer *GetRefaceTimer() const { return reface_timer; } @@ -403,8 +409,6 @@ public: uint32 GetSpawnKillCount(); int GetScore(); - void SetMerchantProbability(uint8 amt) { probability = amt; } - uint8 GetMerchantProbability() { return probability; } void mod_prespawn(Spawn2 *sp); int mod_npc_damage(int damage, EQEmu::skills::SkillType skillinuse, int hand, const EQEmu::ItemData* weapon, Mob* other); void mod_npc_killed_merit(Mob* c); @@ -420,6 +424,8 @@ public: bool IgnoreDespawn() { return ignore_despawn; } + std::unique_ptr AIautocastspell_timer; + protected: const NPCType* NPCTypedata; @@ -453,11 +459,11 @@ protected: uint32 npc_spells_id; uint8 casting_spell_AIindex; - std::unique_ptr AIautocastspell_timer; + uint32* pDontCastBefore_casting_spell; std::vector AIspells; bool HasAISpell; - virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes); + virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates = false); virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); AISpellsVar_Struct AISpellVar; int16 GetFocusEffect(focusType type, uint16 spell_id); @@ -480,6 +486,25 @@ protected: int32 SpellFocusDMG; int32 SpellFocusHeal; + // stats to switch back to after charm wears off + // could probably pick a better name, but these probably aren't taken so ... + int default_ac; + int default_min_dmg; + int default_max_dmg; + int default_attack_delay; + int default_accuracy_rating; + int default_avoidance_rating; + int default_atk; + + // when charmed, switch to these + int charm_ac; + int charm_min_dmg; + int charm_max_dmg; + int charm_attack_delay; + int charm_accuracy_rating; + int charm_avoidance_rating; + int charm_atk; + //pet crap: uint16 pet_spell_id; bool taunting; @@ -535,11 +560,11 @@ protected: std::list mercDataList; bool raid_target; - uint8 probability; bool ignore_despawn; //NPCs with this set to 1 will ignore the despawn value in spawngroup private: uint32 loottable_id; + bool skip_global_loot; bool p_depop; }; diff --git a/zone/object.cpp b/zone/object.cpp index d8db2f1d8..0ba5f9fa3 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -70,7 +70,7 @@ Object::Object(uint32 id, uint32 type, uint32 icon, const Object_Struct& object, //creating a re-ocurring ground spawn. Object::Object(const EQEmu::ItemInstance* inst, char* name,float max_x,float min_x,float max_y,float min_y,float z,float heading,uint32 respawntimer) - : respawn_timer(respawntimer), decay_timer(300000) + : respawn_timer(respawntimer * 1000), decay_timer(300000) { user = nullptr; diff --git a/zone/pathing.cpp b/zone/pathing.cpp index 0bc054d58..7f2d8c880 100644 --- a/zone/pathing.cpp +++ b/zone/pathing.cpp @@ -560,7 +560,8 @@ void PathManager::SpawnPathNodes() sprintf(npc_type->lastname, "%i", PathNodes[i].id); npc_type->cur_hp = 4000000; npc_type->max_hp = 4000000; - npc_type->race = 151; + npc_type->race = 2253; + npc_type->size = 3.0f; npc_type->gender = 2; npc_type->class_ = 9; npc_type->deity= 1; @@ -1377,7 +1378,7 @@ void PathManager::ShowPathNodeNeighbours(Client *c) Mob *m = entity_list.GetMob(Name); if(m) - m->SendIllusionPacket(151); + m->ChangeSize(3.0f); } std::stringstream Neighbours; @@ -1401,7 +1402,7 @@ void PathManager::ShowPathNodeNeighbours(Client *c) Mob *m = entity_list.GetMob(Name); if(m) - m->SendIllusionPacket(46); + m->ChangeSize(5.0f); } c->Message(0, "Neighbours: %s", Neighbours.str().c_str()); } @@ -1560,7 +1561,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques sprintf(npc_type->lastname, "%i", new_id); npc_type->cur_hp = 4000000; npc_type->max_hp = 4000000; - npc_type->race = 151; + npc_type->race = 2253; + npc_type->size = 3.0f; npc_type->gender = 2; npc_type->class_ = 9; npc_type->deity= 1; @@ -1621,7 +1623,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques sprintf(npc_type->lastname, "%i", new_id); npc_type->cur_hp = 4000000; npc_type->max_hp = 4000000; - npc_type->race = 151; + npc_type->race = 2253; + npc_type->size = 3.0f; npc_type->gender = 2; npc_type->class_ = 9; npc_type->deity= 1; diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index 64e71d82f..eef7b1717 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -1993,7 +1993,7 @@ XS(XS_NPC_AddSpellToNPCList) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust); + THIS->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, 0, 0); } XSRETURN_EMPTY; } @@ -2304,54 +2304,6 @@ XS(XS_NPC_GetScore) XSRETURN(1); } -XS(XS_NPC_SetMerchantProbability); -XS(XS_NPC_SetMerchantProbability) { - dXSARGS; - if (items != 2) - Perl_croak(aTHX_ "Usage: NPC::SetMerchantProbability(THIS, Probability)"); - { - NPC *THIS; - uint8 Probability = (uint8)SvIV(ST(1)); - - if (sv_derived_from(ST(0), "NPC")) { - IV tmp = SvIV((SV*)SvRV(ST(0))); - THIS = INT2PTR(NPC *,tmp); - } - else - Perl_croak(aTHX_ "THIS is not of type NPC"); - if(THIS == nullptr) - Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - - THIS->SetMerchantProbability(Probability); - } - XSRETURN_EMPTY; -} - -XS(XS_NPC_GetMerchantProbability); -XS(XS_NPC_GetMerchantProbability) { - dXSARGS; - if (items != 1) - Perl_croak(aTHX_ "Usage: NPC::GetMerchantProbability(THIS)"); - { - NPC *THIS; - uint8 RETVAL; - dXSTARG; - - if (sv_derived_from(ST(0), "NPC")) { - IV tmp = SvIV((SV*)SvRV(ST(0))); - THIS = INT2PTR(NPC *,tmp); - } - else - Perl_croak(aTHX_ "THIS is not of type NPC"); - if(THIS == NULL) - Perl_croak(aTHX_ "THIS is NULL, avoiding crash."); - - RETVAL = THIS->GetMerchantProbability(); - XSprePUSH; PUSHu((UV)RETVAL); - } - XSRETURN(1); -} - XS(XS_NPC_AddMeleeProc); XS(XS_NPC_AddMeleeProc) { dXSARGS; @@ -2677,8 +2629,6 @@ XS(boot_NPC) newXSproto(strcpy(buf, "GetAvoidanceRating"), XS_NPC_GetAvoidanceRating, file, "$"); newXSproto(strcpy(buf, "GetSpawnKillCount"), XS_NPC_GetSpawnKillCount, file, "$"); newXSproto(strcpy(buf, "GetScore"), XS_NPC_GetScore, file, "$"); - newXSproto(strcpy(buf, "SetMerchantProbability"), XS_NPC_SetMerchantProbability, file, "$$"); - newXSproto(strcpy(buf, "GetMerchantProbability"), XS_NPC_GetMerchantProbability, file, "$"); newXSproto(strcpy(buf, "AddMeleeProc"), XS_NPC_AddMeleeProc, file, "$$$"); newXSproto(strcpy(buf, "AddRangedProc"), XS_NPC_AddRangedProc, file, "$$$"); newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$"); diff --git a/zone/pets.cpp b/zone/pets.cpp index 0c150f743..be17a3293 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -28,6 +28,8 @@ #include "pets.h" #include "zonedb.h" +#include + #ifdef BOTS #include "bot.h" #endif @@ -38,82 +40,42 @@ #endif -const char *GetRandPetName() +// need to pass in a char array of 64 chars +void GetRandPetName(char *name) { - static const char *petnames[] = { "Gabaner","Gabann","Gabantik","Gabarab","Gabarer","Gabarn","Gabartik", - "Gabekab","Gabeker","Gabekn","Gaber","Gabn","Gabobab","Gabobn","Gabtik", - "Ganer","Gann","Gantik","Garab","Garaner","Garann","Garantik","Gararn", - "Garekn","Garer","Garn","Gartik","Gasaner","Gasann","Gasantik","Gasarer", - "Gasartik","Gasekn","Gaser","Gebann","Gebantik","Gebarer","Gebarn","Gebartik", - "Gebeker","Gebekn","Gebn","Gekab","Geker","Gekn","Genaner","Genann","Genantik", - "Genarer","Genarn","Gener","Genn","Genobtik","Gibaner","Gibann","Gibantik", - "Gibarn","Gibartik","Gibekn","Giber","Gibn","Gibobtik","Gibtik","Gobaber", - "Gobaner","Gobann","Gobarn","Gobartik","Gober","Gobn","Gobober","Gobobn", - "Gobobtik","Gobtik","Gonaner","Gonann","Gonantik","Gonarab","Gonarer", - "Gonarn","Gonartik","Gonekab","Gonekn","Goner","Gonobtik","Gontik","Gotik", - "Jabaner","Jabann","Jabantik","Jabarab","Jabarer","Jabarn","Jabartik", - "Jabekab","Jabeker","Jabekn","Jaber","Jabn","Jabobtik","Jabtik","Janab", - "Janer","Jann","Jantik","Jarab","Jaranab","Jaraner","Jararer","Jararn", - "Jarartik","Jareker","Jarekn","Jarer","Jarn","Jarobn","Jarobtik","Jartik", - "Jasab","Jasaner","Jasantik","Jasarer","Jasartik","Jasekab","Jaseker", - "Jasekn","Jaser","Jasn","Jasobab","Jasober","Jastik","Jebanab","Jebann", - "Jebantik","Jebarab","Jebarar","Jebarer","Jebarn","Jebartik","Jebeker", - "Jebekn","Jeber","Jebobn","Jebtik","Jekab","Jeker","Jekn","Jenann", - "Jenantik","Jenarer","Jeneker","Jenekn","Jentik","Jibaner","Jibann", - "Jibantik","Jibarer","Jibarn","Jibartik","Jibeker","Jibn","Jibobn", - "Jibtik","Jobab","Jobaner","Jobann","Jobantik","Jobarn","Jobartik", - "Jobekab","Jobeker","Jober","Jobn","Jobtik","Jonanab","Jonaner", - "Jonann","Jonantik","Jonarer","Jonarn","Jonartik","Jonekab","Joneker", - "Jonekn","Joner","Jonn","Jonnarn","Jonober","Jonobn","Jonobtik","Jontik", - "Kabanab","Kabaner","Kabann","Kabantik","Kabarer","Kabarn","Kabartik", - "Kabeker","Kabekn","Kaber","Kabn","Kabober","Kabobn","Kabobtik","Kabtik", - "Kanab","Kaner","Kann","Kantik","Karab","Karanab","Karaner","Karann", - "Karantik","Kararer","Karartik","Kareker","Karer","Karn","Karobab","Karobn", - "Kartik","Kasaner","Kasann","Kasarer","Kasartik","Kaseker","Kasekn","Kaser", - "Kasn","Kasober","Kastik","Kebann","Kebantik","Kebarab","Kebartik","Kebeker", - "Kebekn","Kebn","Kebobab","Kebtik","Kekab","Keker","Kekn","Kenab","Kenaner", - "Kenantik","Kenarer","Kenarn","Keneker","Kener","Kenn","Kenobn","Kenobtik", - "Kentik","Kibab","Kibaner","Kibantik","Kibarn","Kibartik","Kibekab","Kibeker", - "Kibekn","Kibn","Kibobn","Kibobtik","Kobab","Kobanab","Kobaner","Kobann", - "Kobantik","Kobarer","Kobarn","Kobartik","Kobeker","Kobekn","Kober","Kobn", - "Kobober","Kobobn","Kobtik","Konanab","Konaner","Konann","Konantik","Konarab", - "Konarer","Konarn","Konekab","Koneker","Konekn","Koner","Konn","Konobn", - "Konobtik","Kontik","Labanab","Labaner","Labann","Labarab","Labarer", - "Labarn","Labartik","Labeker","Labekn","Laner","Lann","Larab","Larantik", - "Lararer","Lararn","Larartik","Lareker","Larer","Larn","Lartik","Lasaner", - "Lasann","Lasarer","Laseker","Laser","Lasik","Lasn","Lastik","Lebaner", - "Lebarer","Lebartik","Lebekn","Lebtik","Lekab","Lekn","Lenanab","Lenaner", - "Lenann","Lenartik","Lenekab","Leneker","Lenekn","Lentik","Libab","Libaner", - "Libann","Libantik","Libarer","Libarn","Libartik","Libeker","Libekn","Lobann", - "Lobarab","Lobarn","Lobartik","Lobekn","Lobn","Lobober","Lobobn","Lobtik", - "Lonaner","Lonann","Lonantik","Lonarab","Lonarer","Lonarn","Lonartik","Lonekn", - "Loner","Lonobtik","Lontik","Vabanab","Vabaner","Vabann","Vabantik","Vabarer", - "Vabarn","Vabartik","Vabeker","Vabekn","Vabtik","Vanikk","Vann","Varartik","Varn", - "Vartik","Vasann","Vasantik","Vasarab","Vasarer","Vaseker","Vebaner","Vebantik", - "Vebarab","Vebeker","Vebekn","Vebobn","Vekab","Veker","Venaner","Venantik","Venar", - "Venarn","Vener","Ventik","Vibann","Vibantik","Viber","Vibobtik","Vobann", - "Vobarer","Vobartik","Vobekn","Vober","Vobn","Vobtik","Vonaner","Vonann", - "Vonantik","Vonarab","Vonarn","Vonartik","Voneker","Vonn","Xabanab","Xabaner", - "Xabarer","Xabarn","Xabartik","Xabekab","Xabeker","Xabekn","Xaber","Xabober", - "Xaner","Xann","Xarab","Xaranab","Xarann","Xarantik","Xararer","Xarartik","Xarer", - "Xarn","Xartik","Xasaner","Xasann","Xasarab","Xasarn","Xasekab","Xaseker", - "Xebarer","Xebarn","Xebeker","Xeber","Xebober","Xebtik","Xekab","Xeker", - "Xekn","Xenann","Xenantik","Xenarer","Xenartik","Xenekn","Xener","Xenober", - "Xentik","Xibantik","Xibarer","Xibekab","Xibeker","Xibobab","Xibober","Xibobn", - "Xobaner","Xobann","Xobarab","Xobarn","Xobekab","Xobeker","Xobekn","Xober", - "Xobn","Xobobn","Xobtik","Xonaner","Xonann","Xonantik","Xonarer","Xonartik", - "Xonekab","Xoneker","Xonekn","Xoner","Xonober","Xtik","Zabaner","Zabantik", - "Zabarab","Zabekab","Zabekn","Zaber","Zabn","Zabobab","Zabober","Zabtik", - "Zaner","Zantik","Zarann","Zarantik","Zararn","Zarartik","Zareker","Zarekn", - "Zarer","Zarn","Zarober","Zartik","Zasaner","Zasarer","Zaseker","Zasekn","Zasn", - "Zebantik","Zebarer","Zebarn","Zebartik","Zebobab","Zekab","Zekn","Zenann", - "Zenantik","Zenarer","Zenarn","Zenekab","Zeneker","Zenobtik","Zibanab","Zibaner", - "Zibann","Zibarer","Zibartik","Zibekn","Zibn","Zibobn","Zobaner","Zobann", - "Zobarn","Zober","Zobn","Zonanab","Zonaner","Zonann","Zonantik","Zonarer", - "Zonartik","Zonobn","Zonobtik","Zontik","Ztik" }; - int r = zone->random.Int(0, (sizeof(petnames)/sizeof(const char *))-1); - printf("Pet being created: %s\n",petnames[r]); // DO NOT COMMENT THIS OUT! - return petnames[r]; + std::string temp; + temp.reserve(64); + // note these orders are used to make the exclusions cheap :P + static const char *part1[] = {"G", "J", "K", "L", "V", "X", "Z"}; + static const char *part2[] = {nullptr, "ab", "ar", "as", "eb", "en", "ib", "ob", "on"}; + static const char *part3[] = {nullptr, "an", "ar", "ek", "ob"}; + static const char *part4[] = {"er", "ab", "n", "tik"}; + + const char *first = part1[zone->random.Int(0, (sizeof(part1) / sizeof(const char *)) - 1)]; + const char *second = part2[zone->random.Int(0, (sizeof(part2) / sizeof(const char *)) - 1)]; + const char *third = part3[zone->random.Int(0, (sizeof(part3) / sizeof(const char *)) - 1)]; + const char *fourth = part4[zone->random.Int(0, (sizeof(part4) / sizeof(const char *)) - 1)]; + + // if both of these are empty, we would get an illegally short name + if (second == nullptr && third == nullptr) + fourth = part4[(sizeof(part4) / sizeof(const char *)) - 1]; + + // "ektik" isn't allowed either I guess? + if (third == part3[3] && fourth == part4[3]) + fourth = part4[zone->random.Int(0, (sizeof(part4) / sizeof(const char *)) - 2)]; + + // "Laser" isn't allowed either I guess? + if (first == part1[3] && second == part2[3] && third == nullptr && fourth == part4[0]) + fourth = part4[zone->random.Int(1, (sizeof(part4) / sizeof(const char *)) - 2)]; + + temp += first; + if (second != nullptr) + temp += second; + if (third != nullptr) + temp += third; + temp += fourth; + + strn0cpy(name, temp.c_str(), 64); } //not used anymore @@ -325,7 +287,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, } else if (record.petnaming == 4) { // Keep the DB name } else if (record.petnaming == 3 && IsClient()) { - strcpy(npc_type->name, GetRandPetName()); + GetRandPetName(npc_type->name); } else if (record.petnaming == 5 && IsClient()) { strcpy(npc_type->name, this->GetName()); npc_type->name[24] = '\0'; @@ -475,22 +437,6 @@ Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 po // Class should use npc constructor to set light properties } -void Pet::SetTarget(Mob *mob) -{ - if (mob == GetTarget()) - return; - - auto owner = GetOwner(); - if (owner && owner->IsClient() && owner->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) { - auto app = new EQApplicationPacket(OP_PetHoTT, sizeof(ClientTarget_Struct)); - auto ct = (ClientTarget_Struct *)app->pBuffer; - ct->new_target = mob ? mob->GetID() : 0; - owner->CastToClient()->QueuePacket(app); - safe_delete(app); - } - NPC::SetTarget(mob); -} - bool ZoneDatabase::GetPetEntry(const char *pet_type, PetRecord *into) { return GetPoweredPetEntry(pet_type, 0, into); } @@ -671,10 +617,15 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { continue; const EQEmu::ItemData* item2 = database.GetItem(items[i]); - if (item2 && item2->NoDrop != 0) { - //dont bother saving item charges for now, NPCs never use them - //and nobody should be able to get them off the corpse..? - AddLootDrop(item2, &itemlist, 0, 1, 255, true, true); + + if (item2) { + bool noDrop=(item2->NoDrop == 0); // Field is reverse logic + bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) && + _CLIENTPET(this) && GetPetType() <= petOther); + + if (!noDrop || petCanHaveNoDrop) { + AddLootDrop(item2, &itemlist, 0, 1, 255, true, true); + } } } } diff --git a/zone/pets.h b/zone/pets.h index edb6dbe95..1b9811149 100644 --- a/zone/pets.h +++ b/zone/pets.h @@ -7,7 +7,6 @@ struct NPCType; class Pet : public NPC { public: Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power); - virtual void SetTarget(Mob *mob); virtual bool CheckSpellLevelRestriction(uint16 spell_id); }; diff --git a/zone/position.cpp b/zone/position.cpp index 798ff145c..22885b4b1 100644 --- a/zone/position.cpp +++ b/zone/position.cpp @@ -150,13 +150,13 @@ float GetReciprocalHeading(const float heading) float result = 0; // Convert to radians - float h = (heading / 256.0f) * 6.283184f; + float h = (heading / 512.0f) * 6.283184f; // Calculate the reciprocal heading in radians result = h + 3.141592f; // Convert back to eq heading from radians - result = (result / 6.283184f) * 256.0f; + result = (result / 6.283184f) * 512.0f; return result; } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index c77e96979..569afcd42 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -210,6 +210,8 @@ Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& p { auto npc = new NPC(tmp, nullptr, position, FlyMode3); npc->AddLootTable(); + if (npc->DropsGlobalLoot()) + npc->CheckGlobalLootTables(); entity_list.AddNPC(npc,true,true); if(grid > 0) { @@ -232,6 +234,8 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v { auto npc = new NPC(tmp, nullptr, position, FlyMode3); npc->AddLootTable(); + if (npc->DropsGlobalLoot()) + npc->CheckGlobalLootTables(); entity_list.AddNPC(npc,true,true); if(grid > 0) { @@ -308,6 +312,8 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) found_spawn->SetNPCPointer(npc); npc->AddLootTable(); + if (npc->DropsGlobalLoot()) + npc->CheckGlobalLootTables(); npc->SetSp2(found_spawn->SpawnGroupID()); entity_list.AddNPC(npc); entity_list.LimitAddNPC(npc); @@ -1313,9 +1319,7 @@ void QuestManager::itemlink(int item_id) { linker.SetLinkType(EQEmu::saylink::SayLinkItemData); linker.SetItemData(item); - auto item_link = linker.GenerateLink(); - - initiator->Message(0, "%s tells you, %s", owner->GetCleanName(), item_link.c_str()); + initiator->Message(0, "%s tells you, %s", owner->GetCleanName(), linker.GenerateLink().c_str()); } } @@ -1656,6 +1660,8 @@ void QuestManager::respawn(int npcTypeID, int grid) { { owner = new NPC(npcType, nullptr, owner->GetPosition(), FlyMode3); owner->CastToNPC()->AddLootTable(); + if (owner->CastToNPC()->DropsGlobalLoot()) + owner->CastToNPC()->CheckGlobalLootTables(); entity_list.AddNPC(owner->CastToNPC(),true,true); if(grid > 0) owner->CastToNPC()->AssignWaypoints(grid); @@ -1981,8 +1987,8 @@ void QuestManager::npcfeature(char *feature, int setting) QuestManagerCurrentQuestVars(); uint16 Race = owner->GetRace(); uint8 Gender = owner->GetGender(); - uint8 Texture = 0xFF; - uint8 HelmTexture = 0xFF; + uint8 Texture = owner->GetTexture(); + uint8 HelmTexture = owner->GetHelmTexture(); uint8 HairColor = owner->GetHairColor(); uint8 BeardColor = owner->GetBeardColor(); uint8 EyeColor1 = owner->GetEyeColor1(); @@ -2541,9 +2547,8 @@ const char* QuestManager::varlink(char* perltext, int item_id) { linker.SetLinkType(EQEmu::saylink::SayLinkItemData); linker.SetItemData(item); - auto item_link = linker.GenerateLink(); - strcpy(perltext, item_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink() - + strcpy(perltext, linker.GenerateLink().c_str()); + return perltext; } @@ -2765,8 +2770,7 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam linker.SetProxyAugment1ID(sayid); linker.SetProxyText(LinkName); - auto say_link = linker.GenerateLink(); - strcpy(Phrase, say_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink() + strcpy(Phrase, linker.GenerateLink().c_str()); return Phrase; } diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 654c5e836..bfc474721 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -236,6 +236,8 @@ bool Spawn2::Process() { npcthis = npc; npc->AddLootTable(); + if (npc->DropsGlobalLoot()) + npc->CheckGlobalLootTables(); npc->SetSp2(spawngroup_id_); npc->SaveGuardPointAnim(anim); npc->SetAppearance((EmuAppearance)anim); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 03b144b5a..7c91c97a7 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -1443,7 +1443,7 @@ void Mob::SendItemAnimation(Mob *to, const EQEmu::ItemData *item, EQEmu::skills: //these angle and tilt used together seem to make the arrow/knife throw as straight as I can make it - as->launch_angle = CalculateHeadingToTarget(to->GetX(), to->GetY()) * 2; + as->launch_angle = CalculateHeadingToTarget(to->GetX(), to->GetY()); as->tilt = 125; as->arc = 50; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 9f78cb35d..5f151e487 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -790,6 +790,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove CastToClient()->AI_Start(); } else if(IsNPC()) { CastToNPC()->SetPetSpellID(0); //not a pet spell. + CastToNPC()->ModifyStatsOnCharm(false); } bool bBreak = false; @@ -912,16 +913,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove action->source = caster ? caster->GetID() : GetID(); action->level = 65; action->instrument_mod = 10; - action->sequence = static_cast((GetHeading() * 12345 / 2)); + action->hit_heading = GetHeading(); action->type = 231; action->spell = spell_id; - action->buff_unknown = 4; + action->effect_flag = 4; cd->target = action->target; cd->source = action->source; cd->type = action->type; cd->spellid = action->spell; - cd->meleepush_xy = action->sequence; + cd->hit_heading = action->hit_heading; CastToClient()->QueuePacket(action_packet); if(caster && caster->IsClient() && caster != this) @@ -963,16 +964,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove action->source = caster ? caster->GetID() : GetID(); action->level = 65; action->instrument_mod = 10; - action->sequence = static_cast((GetHeading() * 12345 / 2)); + action->hit_heading = GetHeading(); action->type = 231; action->spell = spell_id; - action->buff_unknown = 4; + action->effect_flag = 4; cd->target = action->target; cd->source = action->source; cd->type = action->type; cd->spellid = action->spell; - cd->meleepush_xy = action->sequence; + cd->hit_heading = action->hit_heading; CastToClient()->QueuePacket(action_packet); if(caster->IsClient() && caster != this) @@ -1001,16 +1002,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove action->source = caster ? caster->GetID() : GetID(); action->level = 65; action->instrument_mod = 10; - action->sequence = static_cast((GetHeading() * 12345 / 2)); + action->hit_heading = GetHeading(); action->type = 231; action->spell = spell_id; - action->buff_unknown = 4; + action->effect_flag = 4; cd->target = action->target; cd->source = action->source; cd->type = action->type; cd->spellid = action->spell; - cd->meleepush_xy = action->sequence; + cd->hit_heading = action->hit_heading; CastToClient()->QueuePacket(action_packet); if(caster->IsClient() && caster != this) @@ -1624,13 +1625,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove break; if(IsClient()) { + CastToClient()->SetHorseId(0); // dismount if have horse if (zone->random.Int(0, 99) > spells[spell_id].base[i]) { CastToClient()->SetFeigned(false); entity_list.MessageClose_StringID(this, false, 200, 10, STRING_FEIGNFAILED, GetName()); - } - else + } else { CastToClient()->SetFeigned(true); + } } break; } @@ -1796,8 +1798,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove Message_StringID(4, CORPSE_CANT_SENSE); } } - else if (caster) - caster->Message_StringID(MT_SpellFailure, SPELL_LEVEL_REQ); + else if (caster) { + char level[4]; + ConvertArray(effect_value, level); + caster->Message_StringID(MT_SpellFailure, + SPELL_LEVEL_REQ, level); + } } else { Message_StringID(4, TARGET_NOT_FOUND); @@ -2069,61 +2075,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Toss Up: %d", effect_value); #endif - double toss_amt = (double)spells[spell_id].base[i]; - if(toss_amt < 0) - toss_amt = -toss_amt; - - if(IsNPC()) - { - Stun(static_cast(toss_amt)); + if (IsNPC()) { + Damage(caster, std::abs(effect_value), spell_id, spell.skill, false, buffslot, false); } - toss_amt = sqrt(toss_amt)-2.0; - - if(toss_amt < 0.0) - toss_amt = 0.0; - - if(toss_amt > 20.0) - toss_amt = 20.0; - - if(IsClient()) - { - CastToClient()->SetKnockBackExemption(true); - } - - double look_heading = GetHeading(); - look_heading /= 256; - look_heading *= 360; - look_heading += 180; - if(look_heading > 360) - look_heading -= 360; - - //x and y are crossed mkay - double new_x = spells[spell_id].pushback * sin(double(look_heading * 3.141592 / 180.0)); - double new_y = spells[spell_id].pushback * cos(double(look_heading * 3.141592 / 180.0)); - - auto outapp_push = - new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); - PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)outapp_push->pBuffer; - - spu->spawn_id = GetID(); - spu->x_pos = FloatToEQ19(GetX()); - spu->y_pos = FloatToEQ19(GetY()); - spu->z_pos = FloatToEQ19(GetZ()); - spu->delta_x = NewFloatToEQ13(new_x); - spu->delta_y = NewFloatToEQ13(new_y); - spu->delta_z = NewFloatToEQ13(toss_amt); - spu->heading = FloatToEQ19(GetHeading()); - spu->padding0002 =0; - spu->padding0006 =7; - spu->padding0014 =0x7f; - spu->padding0018 =0x5df27; - spu->animation = 0; - spu->delta_heading = NewFloatToEQ13(0); - outapp_push->priority = 5; - entity_list.QueueClients(this, outapp_push, true); - if(IsClient()) - CastToClient()->FastQueuePacket(&outapp_push); - break; } @@ -2648,7 +2602,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove float new_ground = GetGroundZ(my_x, my_y); if(caster->IsClient()) - caster->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), my_x, my_y, new_ground, GetHeading()*2); + caster->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), my_x, my_y, new_ground, GetHeading()); else caster->GMMove(my_x, my_y, new_ground, GetHeading()); } @@ -3962,6 +3916,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) if(IsNPC()) { CastToNPC()->RestoreGuardSpotCharm(); + CastToNPC()->ModifyStatsOnCharm(true); } SendAppearancePacket(AT_Pet, 0, true, true); diff --git a/zone/spells.cpp b/zone/spells.cpp index c5a5a0b48..1c17e80f4 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -81,6 +81,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) #include "quest_parser_collection.h" #include "string_ids.h" #include "worldserver.h" +#include "fastmath.h" #include #include @@ -104,6 +105,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) extern Zone* zone; extern volatile bool is_zone_loaded; extern WorldServer worldserver; +extern FastMath g_Math; using EQEmu::CastingSlot; @@ -1208,7 +1210,10 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo // handle the components for traditional casters else { - if(c->GetInv().HasItem(component, component_count, invWhereWorn|invWherePersonal) == -1) // item not found + if (!RuleB(Character, PetsUseReagents) && IsEffectInSpell(spell_id, SE_SummonPet)) { + //bypass reagent cost + } + else if(c->GetInv().HasItem(component, component_count, invWhereWorn|invWherePersonal) == -1) // item not found { if (!missingreags) { @@ -1238,6 +1243,9 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo return; } } + else if (!RuleB(Character, PetsUseReagents) && IsEffectInSpell(spell_id, SE_SummonPet)) { + //bypass reagent cost + } else if (!bard_song_mode) { int noexpend; @@ -2646,20 +2654,18 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) { action->source = caster->GetID(); action->target = GetID(); action->spell = spell_id; - action->sequence = (uint32) (GetHeading() * 2); // just some random number + action->force = spells[spell_id].pushback; + action->hit_heading = GetHeading(); + action->hit_pitch = spells[spell_id].pushup; action->instrument_mod = caster->GetInstrumentMod(spell_id); - action->buff_unknown = 0; - action->level = buffs[buffs_i].casterlevel; + action->effect_flag = 0; + action->spell_level = action->level = buffs[buffs_i].casterlevel; action->type = DamageTypeSpell; entity_list.QueueCloseClients(this, packet, false, RuleI(Range, SongMessages), 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells); - action->buff_unknown = 4; + action->effect_flag = 4; - if(IsEffectInSpell(spell_id, SE_TossUp)) - { - action->buff_unknown = 0; - } - else if(spells[spell_id].pushback > 0 || spells[spell_id].pushup > 0) + if(spells[spell_id].pushback != 0.0f || spells[spell_id].pushup != 0.0f) { if(IsClient()) { @@ -2667,38 +2673,6 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) { { CastToClient()->SetKnockBackExemption(true); - action->buff_unknown = 0; - auto outapp_push = new EQApplicationPacket( - OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); - PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)outapp_push->pBuffer; - - double look_heading = caster->CalculateHeadingToTarget(GetX(), GetY()); - look_heading /= 256; - look_heading *= 360; - if(look_heading > 360) - look_heading -= 360; - - //x and y are crossed mkay - double new_x = spells[spell_id].pushback * sin(double(look_heading * 3.141592 / 180.0)); - double new_y = spells[spell_id].pushback * cos(double(look_heading * 3.141592 / 180.0)); - - spu->spawn_id = GetID(); - spu->x_pos = FloatToEQ19(GetX()); - spu->y_pos = FloatToEQ19(GetY()); - spu->z_pos = FloatToEQ19(GetZ()); - spu->delta_x = NewFloatToEQ13(new_x); - spu->delta_y = NewFloatToEQ13(new_y); - spu->delta_z = NewFloatToEQ13(spells[spell_id].pushup); - spu->heading = FloatToEQ19(GetHeading()); - spu->padding0002 =0; - spu->padding0006 =7; - spu->padding0014 =0x7f; - spu->padding0018 =0x5df27; - spu->animation = 0; - spu->delta_heading = NewFloatToEQ13(0); - outapp_push->priority = 6; - entity_list.QueueClients(this, outapp_push, true); - CastToClient()->FastQueuePacket(&outapp_push); } } } @@ -2719,7 +2693,9 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) { cd->source = action->source; cd->type = DamageTypeSpell; cd->spellid = action->spell; - cd->meleepush_xy = action->sequence; + cd->force = action->force; + cd->hit_heading = action->hit_heading; + cd->hit_pitch = action->hit_pitch; cd->damage = 0; if(!IsEffectInSpell(spell_id, SE_BindAffinity)) { @@ -3190,6 +3166,12 @@ uint32 Client::GetLastBuffSlot(bool disc, bool song) return GetCurrentBuffSlots(); } +bool Mob::HasDiscBuff() +{ + int slot = GetFirstBuffSlot(true, false); + return buffs[slot].spellid != SPELL_UNKNOWN; +} + // returns the slot the buff was added to, -1 if it wasn't added due to // stacking problems, and -2 if this is not a buff // if caster is null, the buff will be added with the caster level being @@ -3521,12 +3503,14 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r action->target = spelltar->GetID(); } - action->level = caster_level; // caster level, for animation only + action->spell_level = action->level = caster_level; // caster level, for animation only action->type = 231; // 231 means a spell action->spell = spell_id; - action->sequence = (uint32) (GetHeading() * 2); // just some random number + action->force = spells[spell_id].pushback; + action->hit_heading = GetHeading(); + action->hit_pitch = spells[spell_id].pushup; action->instrument_mod = GetInstrumentMod(spell_id); - action->buff_unknown = 0; + action->effect_flag = 0; if(spelltar != this && spelltar->IsClient()) // send to target spelltar->CastToClient()->QueuePacket(action_packet); @@ -3953,53 +3937,21 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r // NOTE: this is what causes the buff icon to appear on the client, if // this is a buff - but it sortof relies on the first packet. // the complete sequence is 2 actions and 1 damage message - action->buff_unknown = 0x04; // this is a success flag + action->effect_flag = 0x04; // this is a success flag - if(IsEffectInSpell(spell_id, SE_TossUp)) - { - action->buff_unknown = 0; - } - else if(spells[spell_id].pushback > 0 || spells[spell_id].pushup > 0) + if(spells[spell_id].pushback != 0.0f || spells[spell_id].pushup != 0.0f) { if(spelltar->IsClient()) { if(!IsBuffSpell(spell_id)) { spelltar->CastToClient()->SetKnockBackExemption(true); - - action->buff_unknown = 0; - auto outapp_push = - new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); - PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)outapp_push->pBuffer; - - double look_heading = CalculateHeadingToTarget(spelltar->GetX(), spelltar->GetY()); - look_heading /= 256; - look_heading *= 360; - if(look_heading > 360) - look_heading -= 360; - - //x and y are crossed mkay - double new_x = spells[spell_id].pushback * sin(double(look_heading * 3.141592 / 180.0)); - double new_y = spells[spell_id].pushback * cos(double(look_heading * 3.141592 / 180.0)); - - spu->spawn_id = spelltar->GetID(); - spu->x_pos = FloatToEQ19(spelltar->GetX()); - spu->y_pos = FloatToEQ19(spelltar->GetY()); - spu->z_pos = FloatToEQ19(spelltar->GetZ()); - spu->delta_x = NewFloatToEQ13(new_x); - spu->delta_y = NewFloatToEQ13(new_y); - spu->delta_z = NewFloatToEQ13(spells[spell_id].pushup); - spu->heading = FloatToEQ19(spelltar->GetHeading()); - spu->padding0002 =0; - spu->padding0006 =7; - spu->padding0014 =0x7f; - spu->padding0018 =0x5df27; - spu->animation = 0; - spu->delta_heading = NewFloatToEQ13(0); - outapp_push->priority = 6; - entity_list.QueueClients(this, outapp_push, true); - spelltar->CastToClient()->FastQueuePacket(&outapp_push); } + } else if (RuleB(Spells, NPCSpellPush) && !spelltar->IsRooted() && spelltar->ForcedMovement == 0) { + spelltar->m_Delta.x += action->force * g_Math.FastSin(action->hit_heading); + spelltar->m_Delta.y += action->force * g_Math.FastCos(action->hit_heading); + spelltar->m_Delta.z += action->hit_pitch; + spelltar->ForcedMovement = 6; } } @@ -4027,7 +3979,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r cd->source = action->source; cd->type = action->type; cd->spellid = action->spell; - cd->meleepush_xy = action->sequence; + cd->force = action->force; + cd->hit_heading = action->hit_heading; + cd->hit_pitch = action->hit_pitch; cd->damage = 0; if(!IsEffectInSpell(spell_id, SE_BindAffinity)){ entity_list.QueueCloseClients( @@ -4431,6 +4385,36 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) return false; } +int Mob::GetResist(uint8 resist_type) +{ + switch(resist_type) + { + case RESIST_FIRE: + return GetFR(); + case RESIST_COLD: + return GetCR(); + case RESIST_MAGIC: + return GetMR(); + case RESIST_DISEASE: + return GetDR(); + case RESIST_POISON: + return GetPR(); + case RESIST_CORRUPTION: + return GetCorrup(); + case RESIST_PRISMATIC: + return (GetFR() + GetCR() + GetMR() + GetDR() + GetPR()) / 5; + case RESIST_CHROMATIC: + return std::min({GetFR(), GetCR(), GetMR(), GetDR(), GetPR()}); + case RESIST_PHYSICAL: + if (IsNPC()) + return GetPhR(); + else + return 0; + default: + return 0; + } +} + // // Spell resists: // returns an effectiveness index from 0 to 100. for most spells, 100 means @@ -4514,68 +4498,16 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use return 100; } - int target_resist; - switch(resist_type) - { - case RESIST_FIRE: - target_resist = GetFR(); - break; - case RESIST_COLD: - target_resist = GetCR(); - break; - case RESIST_MAGIC: - target_resist = GetMR(); - break; - case RESIST_DISEASE: - target_resist = GetDR(); - break; - case RESIST_POISON: - target_resist = GetPR(); - break; - case RESIST_CORRUPTION: - target_resist = GetCorrup(); - break; - case RESIST_PRISMATIC: - target_resist = (GetFR() + GetCR() + GetMR() + GetDR() + GetPR()) / 5; - break; - case RESIST_CHROMATIC: - { - target_resist = GetFR(); - int temp = GetCR(); - if(temp < target_resist) - { - target_resist = temp; - } + int target_resist = GetResist(resist_type); - temp = GetMR(); - if(temp < target_resist) - { - target_resist = temp; - } - - temp = GetDR(); - if(temp < target_resist) - { - target_resist = temp; - } - - temp = GetPR(); - if(temp < target_resist) - { - target_resist = temp; - } + // JULY 24, 2002 changes + int level = GetLevel(); + if (IsPetOwnerClient() && caster->IsNPC() && !caster->IsPetOwnerClient()) { + auto owner = GetOwner(); + if (owner != nullptr) { + target_resist = std::max(target_resist, owner->GetResist(resist_type)); + level = owner->GetLevel(); } - break; - case RESIST_PHYSICAL: - { - if (IsNPC()) - target_resist = GetPhR(); - else - target_resist = 0; - } - default: - - target_resist = 0; } //Setup our base resist chance. @@ -4584,7 +4516,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use //Adjust our resist chance based on level modifiers uint8 caster_level = level_override > 0 ? level_override : caster->GetLevel(); - int temp_level_diff = GetLevel() - caster_level; + int temp_level_diff = level - caster_level; //Physical Resists are calclated using their own formula derived from extensive parsing. if (resist_type == RESIST_PHYSICAL) { @@ -4593,7 +4525,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use else { - if(IsNPC() && GetLevel() >= RuleI(Casting,ResistFalloff)) + if(IsNPC() && level >= RuleI(Casting,ResistFalloff)) { int a = (RuleI(Casting,ResistFalloff)-1) - caster_level; if(a > 0) @@ -4606,7 +4538,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } } - if(IsClient() && GetLevel() >= 21 && temp_level_diff > 15) + if(IsClient() && level >= 21 && temp_level_diff > 15) { temp_level_diff = 15; } @@ -4622,16 +4554,16 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use level_mod = -level_mod; } - if(IsNPC() && (caster_level - GetLevel()) < -20) + if(IsNPC() && (caster_level - level) < -20) { level_mod = 1000; } //Even more level stuff this time dealing with damage spells - if(IsNPC() && IsDamageSpell(spell_id) && GetLevel() >= 17) + if(IsNPC() && IsDamageSpell(spell_id) && level >= 17) { int level_diff; - if(GetLevel() >= RuleI(Casting,ResistFalloff)) + if(level >= RuleI(Casting,ResistFalloff)) { level_diff = (RuleI(Casting,ResistFalloff)-1) - caster_level; if(level_diff < 0) @@ -4641,7 +4573,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } else { - level_diff = GetLevel() - caster_level; + level_diff = level - caster_level; } level_mod += (2 * level_diff); } @@ -4752,17 +4684,17 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use if(IsNPC()) { - if(GetLevel() > caster_level && GetLevel() >= 17 && caster_level <= 50) + if(level > caster_level && level >= 17 && caster_level <= 50) { partial_modifier += 5; } - if(GetLevel() >= 30 && caster_level < 50) + if(level >= 30 && caster_level < 50) { partial_modifier += (caster_level - 25); } - if(GetLevel() < 15) + if(level < 15) { partial_modifier -= 5; } @@ -4770,9 +4702,9 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use if(caster->IsNPC()) { - if((GetLevel() - caster_level) >= 20) + if((level - caster_level) >= 20) { - partial_modifier += (GetLevel() - caster_level) * 1.5; + partial_modifier += (level - caster_level) * 1.5; } } @@ -5732,7 +5664,7 @@ void Client::SendSpellAnim(uint16 targetid, uint16 spell_id) a->source = this->GetID(); a->type = 231; a->spell = spell_id; - a->sequence = 231; + a->hit_heading = GetHeading(); app.priority = 1; entity_list.QueueCloseClients(this, &app, false, RuleI(Range, SpellParticles)); @@ -5743,8 +5675,8 @@ void Mob::CalcDestFromHeading(float heading, float distance, float MaxZDiff, flo if (!distance) { return; } if (!MaxZDiff) { MaxZDiff = 5; } - float ReverseHeading = 256 - heading; - float ConvertAngle = ReverseHeading * 1.40625f; + float ReverseHeading = 512 - heading; + float ConvertAngle = ReverseHeading * 360.0f / 512.0f; if (ConvertAngle <= 270) ConvertAngle = ConvertAngle + 90; else @@ -5752,8 +5684,8 @@ void Mob::CalcDestFromHeading(float heading, float distance, float MaxZDiff, flo float Radian = ConvertAngle * (3.1415927f / 180.0f); - float CircleX = distance * cos(Radian); - float CircleY = distance * sin(Radian); + float CircleX = distance * std::cos(Radian); + float CircleY = distance * std::sin(Radian); dX = CircleX + StartX; dY = CircleY + StartY; dZ = FindGroundZ(dX, dY, MaxZDiff); @@ -5818,7 +5750,8 @@ void Mob::BeamDirectional(uint16 spell_id, int16 resist_adjust) maxtarget_count++; } - if (maxtarget_count >= spells[spell_id].aemaxtargets) + // not sure if we need this check, but probably do, need to check if it should be default limited or not + if (spells[spell_id].aemaxtargets && maxtarget_count >= spells[spell_id].aemaxtargets) return; } ++iter; @@ -5833,8 +5766,10 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust) if (IsBeneficialSpell(spell_id) && IsClient()) beneficial_targets = true; - float angle_start = spells[spell_id].directional_start + (GetHeading() * 360.0f / 256.0f); - float angle_end = spells[spell_id].directional_end + (GetHeading() * 360.0f / 256.0f); + float heading = GetHeading() * 360.0f / 512.0f; // convert to degrees + + float angle_start = spells[spell_id].directional_start + heading; + float angle_end = spells[spell_id].directional_end + heading; while (angle_start > 360.0f) angle_start -= 360.0f; @@ -5855,7 +5790,7 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust) } float heading_to_target = - (CalculateHeadingToTarget((*iter)->GetX(), (*iter)->GetY()) * 360.0f / 256.0f); + (CalculateHeadingToTarget((*iter)->GetX(), (*iter)->GetY()) * 360.0f / 512.0f); while (heading_to_target < 0.0f) heading_to_target += 360.0f; @@ -5899,7 +5834,8 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust) } } - if (maxtarget_count >= spells[spell_id].aemaxtargets) + // my SHM breath could hit all 5 dummies I could summon in arena + if (spells[spell_id].aemaxtargets && maxtarget_count >= spells[spell_id].aemaxtargets) return; ++iter; diff --git a/zone/string_ids.h b/zone/string_ids.h index 997858bed..7786d12dc 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -120,6 +120,7 @@ #define FAIL_DISARM_DETECTED_TRAP 370 //You fail to disarm the detected trap. #define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one. #define PICK_LORE 379 //You cannot pick up a lore item you already possess. +#define POISON_TOO_HIGH 382 // This poison is too high level for you to apply. #define CONSENT_DENIED 390 //You do not have consent to summon that corpse. #define DISCIPLINE_RDY 393 //You are ready to use a new discipline now. #define CONSENT_INVALID_NAME 397 //Not a valid consent name. diff --git a/zone/tasks.cpp b/zone/tasks.cpp index bcddfcf0a..06e3b4c59 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -2804,8 +2804,7 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN if (strlen(Tasks[TaskID]->Reward) != 0) linker.SetProxyText(Tasks[TaskID]->Reward); - auto reward_link = linker.GenerateLink(); - reward_text.append(reward_link); + reward_text.append(linker.GenerateLink()); } else { reward_text.append(Tasks[TaskID]->Reward); diff --git a/zone/trading.cpp b/zone/trading.cpp index 5c069cacd..70d5c85c1 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -523,7 +523,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st else qs_audit->char1_count += detail->charges; - //for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) { for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot); @@ -743,7 +742,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st qs_audit->char1_count += detail->charges; // 'step 3' should never really see containers..but, just in case... - //for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) { for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot); @@ -888,8 +886,12 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st const EQEmu::ItemData* item = inst->GetItem(); if(item && quest_npc == false) { + bool isPetAndCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) && + _CLIENTPET(tradingWith) && + tradingWith->GetPetType()<=petOther); // if it was not a NO DROP or Attuned item (or if a GM is trading), let the NPC have it - if(GetGM() || (item->NoDrop != 0 && inst->IsAttuned() == false)) { + if(GetGM() || (inst->IsAttuned() == false && + (item->NoDrop != 0 || isPetAndCanHaveNoDrop))) { // pets need to look inside bags and try to equip items found there if (item->IsClassBag() && item->BagSlots > 0) { for (int16 bslot = EQEmu::inventory::containerBegin; bslot < item->BagSlots; bslot++) { diff --git a/zone/trap.cpp b/zone/trap.cpp index d5bcfbeb8..687d3ded3 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -168,6 +168,8 @@ void Trap::Trigger(Mob* trigger) auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f); auto new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3); new_npc->AddLootTable(); + if (new_npc->DropsGlobalLoot()) + new_npc->CheckGlobalLootTables(); entity_list.AddNPC(new_npc); new_npc->AddToHateList(trigger,1); } @@ -191,6 +193,8 @@ void Trap::Trigger(Mob* trigger) auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f); auto new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3); new_npc->AddLootTable(); + if (new_npc->DropsGlobalLoot()) + new_npc->CheckGlobalLootTables(); entity_list.AddNPC(new_npc); new_npc->AddToHateList(trigger,1); } @@ -212,7 +216,7 @@ void Trap::Trigger(Mob* trigger) int dmg = zone->random.Int(effectvalue, effectvalue2); trigger->SetHP(trigger->GetHP() - dmg); a->damage = dmg; - a->meleepush_xy = zone->random.Int(0, 1234567); + a->hit_heading = 0.0f; a->source = GetHiddenTrigger()!=nullptr ? GetHiddenTrigger()->GetID() : trigger->GetID(); a->spellid = 0; a->target = trigger->GetID(); @@ -555,4 +559,4 @@ void Trap::UpdateTrap(bool respawn, bool repopnow) { database.SetTrapData(this, repopnow); } -} \ No newline at end of file +} diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index ca0d24175..55a2cc511 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -29,10 +29,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "npc.h" #include "quest_parser_collection.h" #include "water_map.h" +#include "fastmath.h" #include #include +extern FastMath g_Math; + struct wp_distance { float dist; @@ -176,9 +179,15 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) cur_wp = -2; // flag as quest controlled w/no grid Log(Logs::Detail, Logs::AI, "MoveTo %s without a grid.", to_string(static_cast(position)).c_str()); } + + glm::vec3 dest(position); + + m_CurrentWayPoint = position; + m_CurrentWayPoint.z = GetFixedZ(dest); + if (saveguardspot) { - m_GuardPoint = position; + m_GuardPoint = m_CurrentWayPoint; if (m_GuardPoint.w == 0) m_GuardPoint.w = 0.0001; //hack to make IsGuarding simpler @@ -189,7 +198,6 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) Log(Logs::Detail, Logs::AI, "Setting guard position to %s", to_string(static_cast(m_GuardPoint)).c_str()); } - m_CurrentWayPoint = position; cur_wp_pause = 0; pLastFightingDelayMoving = 0; if (AI_walking_timer->Enabled()) @@ -430,28 +438,7 @@ float Mob::CalculateDistance(float x, float y, float z) { return (float)sqrtf(((m_Position.x - x)*(m_Position.x - x)) + ((m_Position.y - y)*(m_Position.y - y)) + ((m_Position.z - z)*(m_Position.z - z))); } -float Mob::CalculateHeadingToTarget(float in_x, float in_y) { - float angle; - - if (in_x - m_Position.x > 0) - angle = -90 + atan((float)(in_y - m_Position.y) / (float)(in_x - m_Position.x)) * 180 / M_PI; - else if (in_x - m_Position.x < 0) - angle = +90 + atan((float)(in_y - m_Position.y) / (float)(in_x - m_Position.x)) * 180 / M_PI; - else // Added? - { - if (in_y - m_Position.y > 0) - angle = 0; - else - angle = 180; - } - if (angle < 0) - angle += 360; - if (angle > 360) - angle -= 360; - return (256 * (360 - angle) / 360.0f); -} - -bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed) { +bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { if (GetID() == 0) return true; @@ -495,7 +482,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed) { m_Position.y = new_y; m_Position.z = new_z; - if(fix_z_timer.Check() && + if(checkZ && fix_z_timer.Check() && (!this->IsEngaged() || flee_mode || currently_fleeing)) this->FixZ(); @@ -562,7 +549,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed) { m_Position.x = new_x; m_Position.y = new_y; m_Position.z = new_z; - m_Position.w = CalculateHeadingToTarget(x, y); + if (calcHeading) + m_Position.w = CalculateHeadingToTarget(x, y); tar_ndx = 20 - numsteps; } else @@ -600,10 +588,11 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed) { m_Position.x = new_x; m_Position.y = new_y; m_Position.z = new_z; - m_Position.w = CalculateHeadingToTarget(x, y); + if (calcHeading) + m_Position.w = CalculateHeadingToTarget(x, y); } - if (fix_z_timer.Check() && !this->IsEngaged()) + if (checkZ && fix_z_timer.Check() && !this->IsEngaged()) this->FixZ(); SetMoving(true); @@ -627,7 +616,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed) { } bool Mob::CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { - return MakeNewPositionAndSendUpdate(x, y, z, speed); + return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ, calcHeading); } bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { @@ -838,49 +827,61 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) { } } -void Mob::FixZ(int32 z_find_offset /*= 5*/) +float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset) { - BenchTimer timer; timer.reset(); + float new_z = dest.z; - if (zone->HasMap() && RuleB(Map, FixZWhenMoving) && (flymode != 1 && flymode != 2)) + if (zone->HasMap() && RuleB(Map, FixZWhenMoving) && + (flymode != 1 && flymode != 2)) { - if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() || - (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position)))) + if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() + || (zone->HasWaterMap() && + !zone->watermap->InWater(glm::vec3(m_Position)))) { /* Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors */ - float new_z = this->FindGroundZ(m_Position.x, m_Position.y, z_find_offset); - new_z += this->GetZOffset(); + new_z = this->FindDestGroundZ(dest, z_find_offset); + if (new_z != BEST_Z_INVALID) + { + new_z += this->GetZOffset(); - auto duration = timer.elapsed(); - - Log( - Logs::Moderate, - Logs::FixZ, - "Mob::FixZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf", - this->GetCleanName(), - new_z, - m_Position.x, - m_Position.y, - m_Position.z, - duration - ); - - if ((new_z > -2000) && new_z != BEST_Z_INVALID) { - if (RuleB(Map, MobZVisualDebug)) - this->SendAppearanceEffect(78, 0, 0, 0, 0); - - m_Position.z = new_z; + // If bad new Z restore old one + if (new_z < -2000) { + new_z = m_Position.z; + } } - else { - if (RuleB(Map, MobZVisualDebug)) - this->SendAppearanceEffect(103, 0, 0, 0, 0); + } - Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f", this->GetCleanName(), std::abs(m_Position.z - new_z)); - } + auto duration = timer.elapsed(); - last_z = m_Position.z; + Log(Logs::Moderate, Logs::FixZ, + "Mob::GetFixedZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf", + this->GetCleanName(), new_z, dest.x, dest.y, dest.z, duration); + } + + return new_z; +} + +void Mob::FixZ(int32 z_find_offset /*= 5*/) +{ + glm::vec3 current_loc(m_Position); + float new_z = GetFixedZ(current_loc, z_find_offset); + + if (!IsClient() && new_z != m_Position.z) + { + if ((new_z > -2000) && new_z != BEST_Z_INVALID) { + if (RuleB(Map, MobZVisualDebug)) + this->SendAppearanceEffect(78, 0, 0, 0, 0); + + m_Position.z = new_z; + } + else { + if (RuleB(Map, MobZVisualDebug)) + this->SendAppearanceEffect(103, 0, 0, 0, 0); + + Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f", + this->GetCleanName(), std::abs(m_Position.z - new_z)); } } } @@ -992,6 +993,35 @@ float Mob::GetZOffset() const { return 0.2 * GetSize() * offset; } +// This function will try to move the mob along the relative angle a set distance +// if it can't be moved, it will lower the distance and try again +// If we want to move on like say a spawn, we can pass send as false +void Mob::TryMoveAlong(float distance, float angle, bool send) +{ + angle += GetHeading(); + angle = FixHeading(angle); + + glm::vec3 tmp_pos; + glm::vec3 new_pos = GetPosition(); + new_pos.x += distance * g_Math.FastSin(angle); + new_pos.y += distance * g_Math.FastCos(angle); + new_pos.z += GetZOffset(); + + if (zone->HasMap()) { + auto new_z = zone->zonemap->FindClosestZ(new_pos, nullptr); + if (new_z != BEST_Z_INVALID) + new_pos.z = new_z; + + if (zone->zonemap->LineIntersectsZone(GetPosition(), new_pos, 0.0f, &tmp_pos)) + new_pos = tmp_pos; + } + + new_pos.z = GetFixedZ(new_pos); + Teleport(new_pos); + if (send) + SendPositionUpdate(); +} + int ZoneDatabase::GetHighestGrid(uint32 zoneid) { std::string query = StringFormat("SELECT COALESCE(MAX(id), 0) FROM grid WHERE zoneid = %i", zoneid); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 18730bb55..7c60bffe0 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #ifdef _WINDOWS #include @@ -338,6 +339,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) if (ztz->response <= 0) { zc2->success = ZONE_ERROR_NOTREADY; entity->CastToMob()->SetZone(ztz->current_zone_id, ztz->current_instance_id); + entity->CastToClient()->SetZoning(false); } else { entity->CastToClient()->UpdateWho(1); @@ -1812,6 +1814,13 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) break; } + case ServerOP_UCSServerStatusReply: + { + auto ucsss = (UCSServerStatus_Struct*)pack->pBuffer; + if (zone) + zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp); + break; + } case ServerOP_CZSetEntityVariableByNPCTypeID: { CZSetEntVarByNPCTypeID_Struct* CZM = (CZSetEntVarByNPCTypeID_Struct*)pack->pBuffer; diff --git a/zone/zone.cpp b/zone/zone.cpp index 3a8f1e938..90d59e17e 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -146,6 +146,8 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { UpdateWindowTitle(); zone->GetTimeSync(); + zone->RequestUCSServerStatus(); + /* Set Logging */ LogSys.StartFileLogs(StringFormat("%s_version_%u_inst_id_%u_port_%u", zone->GetShortName(), zone->GetInstanceVersion(), zone->GetInstanceID(), ZoneConfig::get()->ZonePort)); @@ -847,6 +849,9 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) GuildBanks = new GuildBankManager; else GuildBanks = nullptr; + + m_ucss_available = false; + m_last_ucss_update = 0; } Zone::~Zone() { @@ -968,6 +973,8 @@ bool Zone::Init(bool iStaticZone) { LoadAlternateAdvancement(); + database.LoadGlobalLoot(); + //Load merchant data zone->GetMerchantDataForZoneLoad(); @@ -1437,6 +1444,9 @@ bool Zone::Depop(bool StartSpawnTimer) { npctable.erase(itr); } + // clear spell cache + database.ClearNPCSpells(); + return true; } @@ -1515,7 +1525,7 @@ void Zone::Repop(uint32 delay) { void Zone::GetTimeSync() { if (worldserver.Connected() && !zone_has_current_time) { - auto pack = new ServerPacket(ServerOP_GetWorldTime, 0); + auto pack = new ServerPacket(ServerOP_GetWorldTime, 1); worldserver.SendPacket(pack); safe_delete(pack); } @@ -1858,14 +1868,17 @@ bool ZoneDatabase::GetDecayTimes(npcDecayTimes_Struct* npcCorpseDecayTimes) { return true; } -void Zone::weatherSend() +void Zone::weatherSend(Client* client) { auto outapp = new EQApplicationPacket(OP_Weather, 8); if(zone_weather>0) outapp->pBuffer[0] = zone_weather-1; if(zone_weather>0) outapp->pBuffer[4] = zone->weather_intensity; - entity_list.QueueClients(0, outapp); + if (client) + client->QueuePacket(outapp); + else + entity_list.QueueClients(0, outapp); safe_delete(outapp); } @@ -2226,6 +2239,8 @@ void Zone::DoAdventureActions() { NPC* npc = new NPC(tmp, nullptr, glm::vec4(ds->assa_x, ds->assa_y, ds->assa_z, ds->assa_h), FlyMode3); npc->AddLootTable(); + if (npc->DropsGlobalLoot()) + npc->CheckGlobalLootTables(); entity_list.AddNPC(npc); npc->Shout("Rarrrgh!"); did_adventure_actions = true; @@ -2329,3 +2344,22 @@ void Zone::UpdateHotzone() is_hotzone = atoi(row[0]) == 0 ? false: true; } +void Zone::RequestUCSServerStatus() { + auto outapp = new ServerPacket(ServerOP_UCSServerStatusRequest, sizeof(UCSServerStatus_Struct)); + auto ucsss = (UCSServerStatus_Struct*)outapp->pBuffer; + ucsss->available = 0; + ucsss->port = Config->ZonePort; + ucsss->unused = 0; + worldserver.SendPacket(outapp); + safe_delete(outapp); +} + +void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) { + if (m_last_ucss_update == update_timestamp && m_ucss_available != ucss_available) { + m_ucss_available = false; + RequestUCSServerStatus(); + return; + } + if (m_last_ucss_update < update_timestamp) + m_ucss_available = ucss_available; +} diff --git a/zone/zone.h b/zone/zone.h index b3ea9fbf1..bbd070305 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -28,6 +28,7 @@ #include "spawn2.h" #include "spawngroup.h" #include "aa_ability.h" +#include "global_loot_manager.h" struct ZonePoint { @@ -209,6 +210,7 @@ public: void LoadAlternateCurrencies(); void LoadNPCEmotes(LinkedList* NPCEmoteList); void ReloadWorld(uint32 Option); + void ReloadMerchants(); Map* zonemap; WaterMap* watermap; @@ -222,7 +224,7 @@ public: void SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute); void SetTime(uint8 hour, uint8 minute, bool update_world = true); - void weatherSend(); + void weatherSend(Client* client = nullptr); bool CanBind() const { return(can_bind); } bool IsCity() const { return(is_city); } bool CanDoCombat() const { return(can_combat); } @@ -268,6 +270,15 @@ public: void UpdateHotzone(); std::unordered_map tick_items; + inline std::vector GetGlobalLootTables(NPC *mob) const { return m_global_loot.GetGlobalLootTables(mob); } + inline void AddGlobalLootEntry(GlobalLootEntry &in) { return m_global_loot.AddEntry(in); } + inline void ShowZoneGlobalLoot(Client *to) { m_global_loot.ShowZoneGlobalLoot(to); } + inline void ShowNPCGlobalLoot(Client *to, NPC *who) { m_global_loot.ShowNPCGlobalLoot(to, who); } + + void RequestUCSServerStatus(); + void SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp); + bool IsUCSServerAvailable() { return m_ucss_available; } + // random object that provides random values for the zone EQEmu::Random random; @@ -346,6 +357,11 @@ private: QGlobalCache *qGlobals; Timer hotzone_timer; + + GlobalLootManager m_global_loot; + + bool m_ucss_available; + uint32 m_last_ucss_update; }; #endif diff --git a/zone/zone_config.h b/zone/zone_config.h index d67cb5201..43f5b723c 100644 --- a/zone/zone_config.h +++ b/zone/zone_config.h @@ -49,7 +49,7 @@ class ZoneConfig : public EQEmuConfig { _zone_config=new ZoneConfig; _config=_zone_config; - return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server"); + return _config->parseFile(); } // Accessors for the static private object diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e23d534c5..cef24a649 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -34,28 +34,15 @@ ZoneDatabase::ZoneDatabase(const char* host, const char* user, const char* passw void ZoneDatabase::ZDBInitVars() { memset(door_isopen_array, 0, sizeof(door_isopen_array)); - npc_spells_maxid = 0; - npc_spellseffects_maxid = 0; - npc_spells_cache = 0; npc_spellseffects_cache = 0; - npc_spells_loadtried = 0; npc_spellseffects_loadtried = 0; max_faction = 0; faction_array = nullptr; } ZoneDatabase::~ZoneDatabase() { - unsigned int x; - if (npc_spells_cache) { - for (x = 0; x <= npc_spells_maxid; x++) { - safe_delete_array(npc_spells_cache[x]); - } - safe_delete_array(npc_spells_cache); - } - safe_delete_array(npc_spells_loadtried); - if (npc_spellseffects_cache) { - for (x = 0; x <= npc_spellseffects_maxid; x++) { + for (int x = 0; x <= npc_spellseffects_maxid; x++) { safe_delete_array(npc_spellseffects_cache[x]); } safe_delete_array(npc_spellseffects_cache); @@ -63,7 +50,7 @@ ZoneDatabase::~ZoneDatabase() { safe_delete_array(npc_spellseffects_loadtried); if (faction_array != nullptr) { - for (x = 0; x <= max_faction; x++) { + for (int x = 0; x <= max_faction; x++) { if (faction_array[x] != 0) safe_delete(faction_array[x]); } @@ -338,62 +325,260 @@ bool ZoneDatabase::logevents(const char* accountname,uint32 accountid,uint8 stat return true; } +void ZoneDatabase::RegisterBug(BugReport_Struct* bug_report) { + if (!bug_report) + return; -void ZoneDatabase::UpdateBug(BugStruct* bug) { - - uint32 len = strlen(bug->bug); - char* bugtext = nullptr; - if(len > 0) - { - bugtext = new char[2*len+1]; - memset(bugtext, 0, 2*len+1); - DoEscapeString(bugtext, bug->bug, len); + size_t len = 0; + char* name_ = nullptr; + char* ui_ = nullptr; + char* type_ = nullptr; + char* target_ = nullptr; + char* bug_ = nullptr; + + len = strlen(bug_report->reporter_name); + if (len) { + if (len > 63) // check against db column size + len = 63; + name_ = new char[(2 * len + 1)]; + memset(name_, 0, (2 * len + 1)); + DoEscapeString(name_, bug_report->reporter_name, len); } - len = strlen(bug->ui); - char* uitext = nullptr; - if(len > 0) - { - uitext = new char[2*len+1]; - memset(uitext, 0, 2*len+1); - DoEscapeString(uitext, bug->ui, len); + len = strlen(bug_report->ui_path); + if (len) { + if (len > 127) + len = 127; + ui_ = new char[(2 * len + 1)]; + memset(ui_, 0, (2 * len + 1)); + DoEscapeString(ui_, bug_report->ui_path, len); } - len = strlen(bug->target_name); - char* targettext = nullptr; - if(len > 0) - { - targettext = new char[2*len+1]; - memset(targettext, 0, 2*len+1); - DoEscapeString(targettext, bug->target_name, len); + len = strlen(bug_report->category_name); + if (len) { + if (len > 63) + len = 63; + type_ = new char[(2 * len + 1)]; + memset(type_, 0, (2 * len + 1)); + DoEscapeString(type_, bug_report->category_name, len); } - //x and y are intentionally swapped because eq is inversexy coords - std::string query = StringFormat("INSERT INTO bugs (zone, name, ui, x, y, z, type, flag, target, bug, date) " + len = strlen(bug_report->target_name); + if (len) { + if (len > 63) + len = 63; + target_ = new char[(2 * len + 1)]; + memset(target_, 0, (2 * len + 1)); + DoEscapeString(target_, bug_report->target_name, len); + } + + len = strlen(bug_report->bug_report); + if (len) { + if (len > 1023) + len = 1023; + bug_ = new char[(2 * len + 1)]; + memset(bug_, 0, (2 * len + 1)); + DoEscapeString(bug_, bug_report->bug_report, len); + } + + //x and y are intentionally swapped because eq is inversexy coords //is this msg out-of-date or are the parameters wrong? + std::string query = StringFormat( + "INSERT INTO `bugs` (`zone`, `name`, `ui`, `x`, `y`, `z`, `type`, `flag`, `target`, `bug`, `date`) " "VALUES('%s', '%s', '%s', '%.2f', '%.2f', '%.2f', '%s', %d, '%s', '%s', CURDATE())", - zone->GetShortName(), bug->name, uitext == nullptr ? "": uitext, - bug->x, bug->y, bug->z, bug->chartype, bug->type, targettext == nullptr? "Unknown Target": targettext, - bugtext==nullptr?"":bugtext); - safe_delete_array(bugtext); - safe_delete_array(uitext); - safe_delete_array(targettext); + zone->GetShortName(), + (name_ ? name_ : ""), + (ui_ ? ui_ : ""), + bug_report->pos_x, + bug_report->pos_y, + bug_report->pos_z, + (type_ ? type_ : ""), + bug_report->optional_info_mask, + (target_ ? target_ : "Unknown Target"), + (bug_ ? bug_ : "") + ); + safe_delete_array(name_); + safe_delete_array(ui_); + safe_delete_array(type_); + safe_delete_array(target_); + safe_delete_array(bug_); + QueryDatabase(query); } -void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug){ +void ZoneDatabase::RegisterBug(Client* client, BugReport_Struct* bug_report) { + if (!client || !bug_report) + return; - uint32 len = strlen(bug->text); - auto bugtext = new char[2 * len + 1]; - memset(bugtext, 0, 2*len+1); - DoEscapeString(bugtext, bug->text, len); + size_t len = 0; + char* category_name_ = nullptr; + char* reporter_name_ = nullptr; + char* ui_path_ = nullptr; + char* target_name_ = nullptr; + char* bug_report_ = nullptr; + char* system_info_ = nullptr; - std::string query = StringFormat("INSERT INTO bugs (type, name, bugtext, flag) " - "VALUES('%s', '%s', '%s', %i)", - "Petition", bug->name, bugtext, 25); - safe_delete_array(bugtext); - QueryDatabase(query); + len = strlen(bug_report->category_name); + if (len) { + if (len > 63) // check against db column size + len = 63; + category_name_ = new char[(2 * len + 1)]; + memset(category_name_, 0, (2 * len + 1)); + DoEscapeString(category_name_, bug_report->category_name, len); + } + + len = strlen(bug_report->reporter_name); + if (len) { + if (len > 63) + len = 63; + reporter_name_ = new char[(2 * len + 1)]; + memset(reporter_name_, 0, (2 * len + 1)); + DoEscapeString(reporter_name_, bug_report->reporter_name, len); + } + + len = strlen(bug_report->ui_path); + if (len) { + if (len > 127) + len = 127; + ui_path_ = new char[(2 * len + 1)]; + memset(ui_path_, 0, (2 * len + 1)); + DoEscapeString(ui_path_, bug_report->ui_path, len); + } + + len = strlen(bug_report->target_name); + if (len) { + if (len > 63) + len = 63; + target_name_ = new char[(2 * len + 1)]; + memset(target_name_, 0, (2 * len + 1)); + DoEscapeString(target_name_, bug_report->target_name, len); + } + + len = strlen(bug_report->bug_report); + if (len) { + if (len > 1023) + len = 1023; + bug_report_ = new char[(2 * len + 1)]; + memset(bug_report_, 0, (2 * len + 1)); + DoEscapeString(bug_report_, bug_report->bug_report, len); + } + + len = strlen(bug_report->system_info); + if (len) { + if (len > 1023) + len = 1023; + system_info_ = new char[(2 * len + 1)]; + memset(system_info_, 0, (2 * len + 1)); + DoEscapeString(system_info_, bug_report->system_info, len); + } + + std::string query = StringFormat( + "INSERT INTO `bug_reports` " + "(`zone`," + " `client_version_id`," + " `client_version_name`," + " `account_id`," + " `character_id`," + " `character_name`," + " `reporter_spoof`," + " `category_id`," + " `category_name`," + " `reporter_name`," + " `ui_path`," + " `pos_x`," + " `pos_y`," + " `pos_z`," + " `heading`," + " `time_played`," + " `target_id`," + " `target_name`," + " `optional_info_mask`," + " `_can_duplicate`," + " `_crash_bug`," + " `_target_info`," + " `_character_flags`," + " `_unknown_value`," + " `bug_report`," + " `system_info`) " + "VALUES " + "('%s'," + " '%u'," + " '%s'," + " '%u'," + " '%u'," + " '%s'," + " '%u'," + " '%u'," + " '%s'," + " '%s'," + " '%s'," + " '%1.1f'," + " '%1.1f'," + " '%1.1f'," + " '%u'," + " '%u'," + " '%u'," + " '%s'," + " '%u'," + " '%u'," + " '%u'," + " '%u'," + " '%u'," + " '%u'," + " '%s'," + " '%s')", + zone->GetShortName(), + client->ClientVersion(), + EQEmu::versions::ClientVersionName(client->ClientVersion()), + client->AccountID(), + client->CharacterID(), + client->GetName(), + (strcmp(client->GetName(), reporter_name_) != 0 ? 1 : 0), + bug_report->category_id, + (category_name_ ? category_name_ : ""), + (reporter_name_ ? reporter_name_ : ""), + (ui_path_ ? ui_path_ : ""), + bug_report->pos_x, + bug_report->pos_y, + bug_report->pos_z, + bug_report->heading, + bug_report->time_played, + bug_report->target_id, + (target_name_ ? target_name_ : ""), + bug_report->optional_info_mask, + ((bug_report->optional_info_mask & EQEmu::bug::infoCanDuplicate) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoCrashBug) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoTargetInfo) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoCharacterFlags) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoUnknownValue) != 0 ? 1 : 0), + (bug_report_ ? bug_report_ : ""), + (system_info_ ? system_info_ : "") + ); + safe_delete_array(category_name_); + safe_delete_array(reporter_name_); + safe_delete_array(ui_path_); + safe_delete_array(target_name_); + safe_delete_array(bug_report_); + safe_delete_array(system_info_); + + auto result = QueryDatabase(query); + + // TODO: Entity dumping [RuleB(Bugs, DumpTargetEntity)] } +//void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug) { +// +// uint32 len = strlen(bug->text); +// auto bugtext = new char[2 * len + 1]; +// memset(bugtext, 0, 2 * len + 1); +// DoEscapeString(bugtext, bug->text, len); +// +// std::string query = StringFormat("INSERT INTO bugs (type, name, bugtext, flag) " +// "VALUES('%s', '%s', '%s', %i)", +// "Petition", bug->name, bugtext, 25); +// safe_delete_array(bugtext); +// QueryDatabase(query); +//} + bool ZoneDatabase::SetSpecialAttkFlag(uint8 id, const char* flag) { std::string query = StringFormat("UPDATE npc_types SET npcspecialattks='%s' WHERE id = %i;", flag, id); @@ -1438,6 +1623,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla if (account_id <= 0) return false; + std::string mail_key = database.GetMailKey(character_id); + clock_t t = std::clock(); /* Function timer start */ std::string query = StringFormat( "REPLACE INTO `character_data` (" @@ -1534,7 +1721,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla " e_aa_effects, " " e_percent_to_aa, " " e_expended_aa_spent, " - " e_last_invsnapshot " + " e_last_invsnapshot, " + " mailkey " ") " "VALUES (" "%u," // id " id, " @@ -1630,7 +1818,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla "%u," // e_aa_effects "%u," // e_percent_to_aa "%u," // e_expended_aa_spent - "%u" // e_last_invsnapshot + "%u," // e_last_invsnapshot + "'%s'" // mailkey mail_key ")", character_id, // " id, " account_id, // " account_id, " @@ -1725,7 +1914,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla m_epp->aa_effects, m_epp->perAA, m_epp->expended_aa, - m_epp->last_invsnapshot_time + m_epp->last_invsnapshot_time, + mail_key.c_str() ); auto results = database.QueryDatabase(query); Log(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterData %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); @@ -1975,7 +2165,16 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load "npc_types.feettexture, " "npc_types.ignore_despawn, " "npc_types.show_name, " - "npc_types.untargetable " + "npc_types.untargetable, " + "npc_types.charm_ac, " + "npc_types.charm_min_dmg, " + "npc_types.charm_max_dmg, " + "npc_types.charm_attack_delay, " + "npc_types.charm_accuracy_rating, " + "npc_types.charm_avoidance_rating, " + "npc_types.charm_atk, " + "npc_types.skip_global_loot, " + "npc_types.rare_spawn " "FROM npc_types %s", where_condition.c_str() ); @@ -2154,6 +2353,17 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load temp_npctype_data->show_name = atoi(row[98]) != 0 ? true : false; temp_npctype_data->untargetable = atoi(row[99]) != 0 ? true : false; + temp_npctype_data->charm_ac = atoi(row[100]); + temp_npctype_data->charm_min_dmg = atoi(row[101]); + temp_npctype_data->charm_max_dmg = atoi(row[102]); + temp_npctype_data->charm_attack_delay = atoi(row[103]) * 100; // TODO: fix DB + temp_npctype_data->charm_accuracy_rating = atoi(row[104]); + temp_npctype_data->charm_avoidance_rating = atoi(row[105]); + temp_npctype_data->charm_atk = atoi(row[106]); + + temp_npctype_data->skip_global_loot = atoi(row[107]) != 0; + temp_npctype_data->rare_spawn = atoi(row[108]) != 0; + // If NPC with duplicate NPC id already in table, // free item we attempted to add. if (zone->npctable.find(temp_npctype_data->npc_id) != zone->npctable.end()) { diff --git a/zone/zonedb.h b/zone/zonedb.h index c134dade3..d0e7b1a99 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -1,6 +1,8 @@ #ifndef ZONEDB_H_ #define ZONEDB_H_ +#include + #include "../common/shareddb.h" #include "../common/eq_packet_structs.h" #include "position.h" @@ -46,13 +48,15 @@ struct wplist { #pragma pack(1) struct DBnpcspells_entries_Struct { int16 spellid; - uint32 type; uint8 minlevel; uint8 maxlevel; + uint32 type; int16 manacost; - int32 recast_delay; int16 priority; + int32 recast_delay; int16 resist_adjust; + int8 min_hp; + int8 max_hp; }; #pragma pack() @@ -75,7 +79,6 @@ struct DBnpcspells_Struct { int16 rproc_chance; uint16 defensive_proc; int16 dproc_chance; - uint32 numentries; uint32 fail_recast; uint32 engaged_no_sp_recast_min; uint32 engaged_no_sp_recast_max; @@ -88,7 +91,7 @@ struct DBnpcspells_Struct { uint32 idle_no_sp_recast_min; uint32 idle_no_sp_recast_max; uint8 idle_beneficial_chance; - DBnpcspells_entries_Struct entries[0]; + std::vector entries; }; struct DBnpcspellseffects_Struct { @@ -421,9 +424,11 @@ public: uint32 GetMaxNPCSpellsID(); uint32 GetMaxNPCSpellsEffectsID(); bool GetAuraEntry(uint16 spell_id, AuraRecord &record); + void LoadGlobalLoot(); DBnpcspells_Struct* GetNPCSpells(uint32 iDBSpellsID); DBnpcspellseffects_Struct* GetNPCSpellsEffects(uint32 iDBSpellsEffectsID); + void ClearNPCSpells() { npc_spells_cache.clear(); npc_spells_loadtried.clear(); } const NPCType* LoadNPCTypesData(uint32 id, bool bulk_load = false); /* Mercs */ @@ -437,8 +442,9 @@ public: bool DeleteMerc(uint32 merc_id); /* Petitions */ - void UpdateBug(BugStruct* bug); - void UpdateBug(PetitionBug_Struct* bug); + void RegisterBug(BugReport_Struct* bug_report); // old method + void RegisterBug(Client* client, BugReport_Struct* bug_report); // new method + //void UpdateBug(PetitionBug_Struct* bug); void DeletePetitionFromDB(Petition* wpet); void UpdatePetitionToDB(Petition* wpet); void InsertPetitionToDB(Petition* wpet); @@ -524,10 +530,9 @@ protected: uint32 max_faction; Faction** faction_array; - uint32 npc_spells_maxid; uint32 npc_spellseffects_maxid; - DBnpcspells_Struct** npc_spells_cache; - bool* npc_spells_loadtried; + std::unordered_map npc_spells_cache; + std::unordered_set npc_spells_loadtried; DBnpcspellseffects_Struct** npc_spellseffects_cache; bool* npc_spellseffects_loadtried; uint8 door_isopen_array[255]; diff --git a/zone/zonedump.h b/zone/zonedump.h index 2bd78c2d8..66c7ec01d 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -89,6 +89,13 @@ struct NPCType EQEmu::TintProfile armor_tint; uint32 min_dmg; uint32 max_dmg; + uint32 charm_ac; + uint32 charm_min_dmg; + uint32 charm_max_dmg; + int charm_attack_delay; + int charm_accuracy_rating; + int charm_avoidance_rating; + int charm_atk; int16 attack_count; char special_abilities[512]; uint16 d_melee_texture1; @@ -126,7 +133,6 @@ struct NPCType float healscale; bool no_target_hotkey; bool raid_target; - uint8 probability; uint8 armtexture; uint8 bracertexture; uint8 handtexture; @@ -135,6 +141,8 @@ struct NPCType bool ignore_despawn; bool show_name; // should default on bool untargetable; + bool skip_global_loot; + bool rare_spawn; }; namespace player_lootitem { diff --git a/zone/zoning.cpp b/zone/zoning.cpp index c7be0a37e..cbd928f21 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -42,7 +42,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { Bot::ProcessClientZoneChange(this); #endif - zoning = true; + bZoning = true; if (app->size != sizeof(ZoneChange_Struct)) { Log(Logs::General, Logs::None, "Wrong size: OP_ZoneChange, size=%d, expected %d", app->size, sizeof(ZoneChange_Struct)); return; @@ -308,6 +308,8 @@ void Client::SendZoneCancel(ZoneChange_Struct *zc) { //reset to unsolicited. zone_mode = ZoneUnsolicited; + // reset since we're not zoning anymore + bZoning = false; } void Client::SendZoneError(ZoneChange_Struct *zc, int8 err) @@ -327,6 +329,8 @@ void Client::SendZoneError(ZoneChange_Struct *zc, int8 err) //reset to unsolicited. zone_mode = ZoneUnsolicited; + // reset since we're not zoning anymore + bZoning = false; } void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instance_id, float dest_x, float dest_y, float dest_z, float dest_h, int8 ignore_r) {